diff --git a/src/ImageProcessorCore/Bootstrapper.cs b/src/ImageProcessorCore/Bootstrapper.cs index 08698af320..7a7d1892f0 100644 --- a/src/ImageProcessorCore/Bootstrapper.cs +++ b/src/ImageProcessorCore/Bootstrapper.cs @@ -74,7 +74,7 @@ namespace ImageProcessorCore /// The type of pixel data. /// The image /// The - public IPixelAccessor GetPixelAccessor(IImageBase image) + public IPixelAccessor GetPixelAccessor(IImageBase image) where TPackedVector : IPackedVector, new() { Type packed = typeof(TPackedVector); @@ -82,33 +82,7 @@ namespace ImageProcessorCore { // TODO: Double check this. It should work... - return (IPixelAccessor)new Bgra32PixelAccessor(image); - //return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image); - } - - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:"); - - foreach (Type value in this.pixelAccessors.Values) - { - stringBuilder.AppendLine("-" + value.Name); - } - - throw new NotSupportedException(stringBuilder.ToString()); - } - - /// - /// Gets an instance of the correct for the packed vector. - /// - /// The type of pixel data. - /// The image - /// The - public IPixelAccessor GetPixelAccessor(ImageFrame image) - where TPackedVector : IPackedVector - { - Type packed = typeof(TPackedVector); - if (!this.pixelAccessors.ContainsKey(packed)) - { + //return new Bgra32PixelAccessor(image); return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image); } @@ -122,5 +96,31 @@ namespace ImageProcessorCore throw new NotSupportedException(stringBuilder.ToString()); } + + ///// + ///// Gets an instance of the correct for the packed vector. + ///// + ///// The type of pixel data. + ///// The image + ///// The + //public IPixelAccessor GetPixelAccessor(ImageFrame image) + // where TPackedVector : IPackedVector, new() + //{ + // Type packed = typeof(TPackedVector); + // if (!this.pixelAccessors.ContainsKey(packed)) + // { + // return (IPixelAccessor)Activator.CreateInstance(this.pixelAccessors[packed], image); + // } + + // StringBuilder stringBuilder = new StringBuilder(); + // stringBuilder.AppendLine("PixelAccessor cannot be loaded. Available accessors:"); + + // foreach (Type value in this.pixelAccessors.Values) + // { + // stringBuilder.AppendLine("-" + value.Name); + // } + + // throw new NotSupportedException(stringBuilder.ToString()); + //} } } diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs b/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs index 4b212d4ea0..bb413cc383 100644 --- a/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageProcessorCore/Formats/Bmp/BmpEncoder.cs @@ -44,7 +44,7 @@ namespace ImageProcessorCore.Formats /// public void Encode(ImageBase image, Stream stream) - where TPackedVector: IPackedVector + where TPackedVector : IPackedVector, new() { BmpEncoderCore encoder = new BmpEncoderCore(); encoder.Encode(image, stream, this.BitsPerPixel); diff --git a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs index 2ad8e24e6e..a0d321ecb9 100644 --- a/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageProcessorCore/Formats/Bmp/BmpEncoderCore.cs @@ -29,7 +29,7 @@ namespace ImageProcessorCore.Formats /// The to encode the image data to. /// The public void Encode(ImageBase image, Stream stream, BmpBitsPerPixel bitsPerPixel) - where TPackedVector : IPackedVector + where TPackedVector : IPackedVector, new() { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); @@ -128,7 +128,7 @@ namespace ImageProcessorCore.Formats /// The containing pixel data. /// private void WriteImage(EndianBinaryWriter writer, ImageBase image) - where TPackedVector : IPackedVector + where TPackedVector : IPackedVector, new() { // TODO: Add more compression formats. int amount = (image.Width * (int)this.bmpBitsPerPixel) % 4; diff --git a/src/ImageProcessorCore/Formats/IImageDecoder.cs b/src/ImageProcessorCore/Formats/IImageDecoder.cs index f394843caa..59b4ddb2d4 100644 --- a/src/ImageProcessorCore/Formats/IImageDecoder.cs +++ b/src/ImageProcessorCore/Formats/IImageDecoder.cs @@ -44,6 +44,7 @@ namespace ImageProcessorCore.Formats /// The type of pixels contained within the image. /// The to decode to. /// The containing image data. - void Decode(Image image, Stream stream) where TPackedVector : IPackedVector, new(); + void Decode(Image image, Stream stream) + where TPackedVector : IPackedVector, new(); } } diff --git a/src/ImageProcessorCore/Formats/IImageEncoder.cs b/src/ImageProcessorCore/Formats/IImageEncoder.cs index df7234aad0..32b6f99018 100644 --- a/src/ImageProcessorCore/Formats/IImageEncoder.cs +++ b/src/ImageProcessorCore/Formats/IImageEncoder.cs @@ -48,6 +48,7 @@ namespace ImageProcessorCore.Formats /// The type of pixels contained within the image. /// The to encode from. /// The to encode the image data to. - void Encode(ImageBase image, Stream stream) where TPackedVector : IPackedVector; + void Encode(ImageBase image, Stream stream) + where TPackedVector : IPackedVector, new(); } } diff --git a/src/ImageProcessorCore/IImageBase.cs b/src/ImageProcessorCore/IImageBase.cs index c8b762382c..cc383cb258 100644 --- a/src/ImageProcessorCore/IImageBase.cs +++ b/src/ImageProcessorCore/IImageBase.cs @@ -6,8 +6,8 @@ namespace ImageProcessorCore where TPackedVector : IPackedVector, new() { TPackedVector[] Pixels { get; } - void ClonePixels(int width, int height, IEnumerable pixels); - IPixelAccessor Lock(); + void ClonePixels(int width, int height, TPackedVector[] pixels); + IPixelAccessor Lock(); void SetPixels(int width, int height, TPackedVector[] pixels); } diff --git a/src/ImageProcessorCore/Image.cs b/src/ImageProcessorCore/Image.cs index acd49d5514..caa333e9c0 100644 --- a/src/ImageProcessorCore/Image.cs +++ b/src/ImageProcessorCore/Image.cs @@ -184,9 +184,9 @@ namespace ImageProcessorCore public IImageFormat CurrentImageFormat { get; internal set; } /// - public override IPixelAccessor Lock() + public override IPixelAccessor Lock() { - return Bootstrapper.Instance.GetPixelAccessor(this); + return Bootstrapper.Instance.GetPixelAccessor(this); } /// diff --git a/src/ImageProcessorCore/ImageBase.cs b/src/ImageProcessorCore/ImageBase.cs index 0c0bb6fac6..15fd9b5d3f 100644 --- a/src/ImageProcessorCore/ImageBase.cs +++ b/src/ImageProcessorCore/ImageBase.cs @@ -196,6 +196,6 @@ namespace ImageProcessorCore /// /// /// The - public abstract IPixelAccessor Lock(); + public abstract IPixelAccessor Lock(); } } diff --git a/src/ImageProcessorCore/ImageFrame.cs b/src/ImageProcessorCore/ImageFrame.cs index cc65739c13..d170778e41 100644 --- a/src/ImageProcessorCore/ImageFrame.cs +++ b/src/ImageProcessorCore/ImageFrame.cs @@ -33,9 +33,9 @@ namespace ImageProcessorCore } /// - public override IPixelAccessor Lock() + public override IPixelAccessor Lock() { - return Bootstrapper.Instance.GetPixelAccessor(this); + return Bootstrapper.Instance.GetPixelAccessor(this); } } } diff --git a/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs index 0645ff429f..e5f090e417 100644 --- a/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs +++ b/src/ImageProcessorCore/PixelAccessor/Bgra32PixelAccessor.cs @@ -15,7 +15,7 @@ namespace ImageProcessorCore /// The image data is always stored in format, where the blue, green, red, and /// alpha values are 8 bit unsigned bytes. /// - public sealed unsafe class Bgra32PixelAccessor : IPixelAccessor + public sealed unsafe class Bgra32PixelAccessor : IPixelAccessor { /// @@ -90,7 +90,7 @@ namespace ImageProcessorCore /// than zero and smaller than the width of the pixel. /// /// The at the specified position. - public Bgra32 this[int x, int y] + public IPackedVector this[int x, int y] { get { @@ -121,7 +121,7 @@ namespace ImageProcessorCore throw new ArgumentOutOfRangeException(nameof(y), "Value cannot be less than zero or greater than the bitmap height."); } #endif - *(this.pixelsBase + ((y * this.Width) + x)) = value; + *(this.pixelsBase + ((y * this.Width) + x)) = (Bgra32)value; } } diff --git a/src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs b/src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs index f64fcf231d..cf3c2cf539 100644 --- a/src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs +++ b/src/ImageProcessorCore/PixelAccessor/IPixelAccessor.cs @@ -10,7 +10,7 @@ namespace ImageProcessorCore /// /// Encapsulates properties to provides per-pixel access to an images pixels. /// - public interface IPixelAccessor : IDisposable where TPackedVector : IPackedVector, new() + public interface IPixelAccessor : IDisposable { /// /// Gets the width of the image in pixels. @@ -34,7 +34,7 @@ namespace ImageProcessorCore /// than zero and smaller than the width of the pixel. /// /// The at the specified position. - TPackedVector this[int x, int y] + IPackedVector this[int x, int y] { get; set; diff --git a/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs index a6e787714d..ce713797b5 100644 --- a/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/ResizeProcessor.cs @@ -14,11 +14,6 @@ namespace ImageProcessorCore.Processors /// public class ResizeProcessor : ImageSampler { - /// - /// The image used for storing the first pass pixels. - /// - private object firstPass; - /// /// Initializes a new instance of the class. /// @@ -55,8 +50,6 @@ namespace ImageProcessorCore.Processors this.HorizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); this.VerticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); } - - this.firstPass = new Image(target.Width, source.Height); } /// @@ -79,17 +72,14 @@ namespace ImageProcessorCore.Processors int endX = targetRectangle.Right; bool compand = this.Compand; - // TODO: Yuck! Fix this boxing nonsense - Image fp = (Image)this.firstPass; - if (this.Sampler is NearestNeighborResampler) { // Scaling factors float widthFactor = sourceRectangle.Width / (float)targetRectangle.Width; float heightFactor = sourceRectangle.Height / (float)targetRectangle.Height; - using (IPixelAccessor sourcePixels = source.Lock()) - using (IPixelAccessor targetPixels = target.Lock()) + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) { Parallel.For( startY, @@ -124,94 +114,114 @@ namespace ImageProcessorCore.Processors // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. - using (IPixelAccessor sourcePixels = source.Lock()) - using (IPixelAccessor firstPassPixels = fp.Lock()) - using (IPixelAccessor targetPixels = target.Lock()) + Image firstPass = new Image(target.Width, source.Height); + using (IPixelAccessor sourcePixels = source.Lock()) + using (IPixelAccessor firstPassPixels = firstPass.Lock()) + using (IPixelAccessor targetPixels = target.Lock()) { Parallel.For( 0, sourceHeight, y => + { + for (int x = startX; x < endX; x++) { - for (int x = startX; x < endX; x++) + if (x >= 0 && x < width) { - if (x >= 0 && x < width) - { - // Ensure offsets are normalised for cropping and padding. - int offsetX = x - startX; - float sum = this.HorizontalWeights[offsetX].Sum; - Weight[] horizontalValues = this.HorizontalWeights[offsetX].Values; + // Ensure offsets are normalised for cropping and padding. + int offsetX = x - startX; + float sum = this.HorizontalWeights[offsetX].Sum; + Weight[] horizontalValues = this.HorizontalWeights[offsetX].Values; - // Destination color components - Vector4 destination = new Vector4(); + // Destination color components + //Color destination = new Color(); - for (int i = 0; i < sum; i++) - { - Weight xw = horizontalValues[i]; - int originX = xw.Index; - Vector4 sourceColor = sourcePixels[originX, y].ToVector4(); - //Color sourceColor = compand - // ? Color.Expand(sourcePixels[originX, y]) - // : sourcePixels[originX, y]; - - destination += sourceColor * xw.Value; - } + //for (int i = 0; i < sum; i++) + //{ + // Weight xw = horizontalValues[i]; + // int originX = xw.Index; + // Color sourceColor = compand + // ? Color.Expand(sourcePixels[originX, y]) + // : sourcePixels[originX, y]; + + // destination += sourceColor * xw.Value; + //} - //if (compand) - //{ - // destination = Color.Compress(destination); - //} - TPackedVector packed = new TPackedVector(); - packed.PackVector(destination); - firstPassPixels[x, y] = packed; + //if (compand) + //{ + // destination = Color.Compress(destination); + //} + + //firstPassPixels[x, y] = destination; + Vector4 destination = new Vector4(); + + for (int i = 0; i < sum; i++) + { + Weight xw = horizontalValues[i]; + int originX = xw.Index; + Vector4 sourceColor = sourcePixels[originX, y].ToVector4(); + //Color sourceColor = compand + // ? Color.Expand(sourcePixels[originX, y]) + // : sourcePixels[originX, y]; + + destination += sourceColor * xw.Value; } + + //if (compand) + //{ + // destination = Color.Compress(destination); + //} + TPackedVector packed = new TPackedVector(); + packed.PackVector(destination); + + firstPassPixels[x, y] = packed; } - }); + } + }); // Now process the rows. Parallel.For( startY, endY, y => + { + if (y >= 0 && y < height) { - if (y >= 0 && y < height) + // Ensure offsets are normalised for cropping and padding. + int offsetY = y - startY; + float sum = this.VerticalWeights[offsetY].Sum; + Weight[] verticalValues = this.VerticalWeights[offsetY].Values; + + for (int x = 0; x < width; x++) { - // Ensure offsets are normalised for cropping and padding. - int offsetY = y - startY; - float sum = this.VerticalWeights[offsetY].Sum; - Weight[] verticalValues = this.VerticalWeights[offsetY].Values; + // Destination color components + Vector4 destination = new Vector4(); - for (int x = 0; x < width; x++) + for (int i = 0; i < sum; i++) { - // Destination color components - Vector4 destination = new Vector4(); - - for (int i = 0; i < sum; i++) - { - Weight yw = verticalValues[i]; - int originY = yw.Index; - - Vector4 sourceColor = sourcePixels[x, originY].ToVector4(); - //Color sourceColor = compand - // ? Color.Expand(firstPassPixels[x, originY]) - // : firstPassPixels[x, originY]; + Weight yw = verticalValues[i]; + int originY = yw.Index; + //Color sourceColor = compand + // ? Color.Expand(firstPassPixels[x, originY]) + // : firstPassPixels[x, originY]; + Vector4 sourceColor = firstPassPixels[x, originY].ToVector4(); + destination += sourceColor * yw.Value; + } - destination += sourceColor * yw.Value; - } + //if (compand) + //{ + // destination = Color.Compress(destination); + //} - //if (compand) - //{ - // destination = Color.Compress(destination); - //} + TPackedVector packed = new TPackedVector(); + packed.PackVector(destination); - TPackedVector packed = new TPackedVector(); - packed.PackVector(destination); - targetPixels[x, y] = packed; - } + targetPixels[x, y] = packed; } + } - this.OnRowProcessed(); - }); + this.OnRowProcessed(); + }); } }