From 8c84d41b269ff00fc356cfacb4299975b20e1320 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 28 Aug 2016 19:03:51 +1000 Subject: [PATCH] Don't create a copy if you dont need to. ImageFilter = NoCopy ImageSampler = Copy Former-commit-id: 530cc95d3b655175999dc78d95fea988f25416e6 Former-commit-id: 63650e982a0a2bb116a473816692187b186a4d0f Former-commit-id: fe8e7020aa116899a2ae1620b4c78b446a3510e7 --- src/ImageProcessorCore/Filters/Blend.cs | 2 +- .../Filters/ColorBlindness.cs | 2 +- src/ImageProcessorCore/Filters/Grayscale.cs | 4 +- .../Filters/Processors/AlphaProcessor.cs | 27 ++-- .../Processors/BackgroundColorProcessor.cs | 47 ++++--- .../Binarization/BinaryThresholdProcessor.cs | 31 +++-- .../Filters/Processors/BlendProcessor.cs | 7 +- .../Filters/Processors/BrightnessProcessor.cs | 11 +- .../ColorMatrix/ColorMatrixFilter.cs | 9 +- .../ColorMatrix/IColorMatrixFilter.cs | 2 +- .../ColorMatrix/LomographProcessor.cs | 4 +- .../ColorMatrix/PolaroidProcessor.cs | 6 +- .../Filters/Processors/ContrastProcessor.cs | 13 +- .../Filters/Processors/GlowProcessor.cs | 12 +- .../Filters/Processors/IImageFilter.cs | 31 +++++ .../Filters/Processors/ImageFilter.cs | 68 ++++++++++ .../Filters/Processors/InvertProcessor.cs | 12 +- .../Filters/Processors/VignetteProcessor.cs | 9 +- .../Image/IImageProcessor.cs | 47 +------ .../Image/ImageIOExtensions.cs | 74 +++++++++++ ...nsions.cs => ImageProcessingExtensions.cs} | 104 +++++++-------- src/ImageProcessorCore/ImageProcessor.cs | 125 ++---------------- .../{Filters => Samplers}/BoxBlur.cs | 0 .../{Filters => Samplers}/DetectEdges.cs | 0 .../{Filters => Samplers}/GuassianBlur.cs | 0 .../{Filters => Samplers}/GuassianSharpen.cs | 0 .../{Filters => Samplers}/Pixelate.cs | 0 .../Convolution/BoxBlurProcessor.cs | 0 .../Convolution/Convolution2DFilter.cs | 2 +- .../Convolution/Convolution2PassFilter.cs | 2 +- .../Convolution/ConvolutionFilter.cs | 2 +- .../EdgeDetection/EdgeDetector2DFilter.cs | 2 +- .../EdgeDetection/EdgeDetectorFilter.cs | 2 +- .../EdgeDetection/IEdgeDetectorFilter.cs | 2 +- .../EdgeDetection/KayyaliProcessor.cs | 0 .../EdgeDetection/KirschProcessor.cs | 0 .../EdgeDetection/Laplacian3X3Processor.cs | 0 .../EdgeDetection/Laplacian5X5Processor.cs | 0 .../LaplacianOfGaussianProcessor.cs | 0 .../EdgeDetection/PrewittProcessor.cs | 0 .../EdgeDetection/RobertsCrossProcessor.cs | 0 .../EdgeDetection/ScharrProcessor.cs | 0 .../EdgeDetection/SobelProcessor.cs | 0 .../Convolution/GuassianBlurProcessor.cs | 0 .../Convolution/GuassianSharpenProcessor.cs | 0 .../Processors/EntropyCropProcessor.cs | 2 +- .../Samplers/Processors/IImageSampler.cs | 46 ++++++- .../Samplers/Processors/ImageSampler.cs | 111 +++++++++++++++- .../Processors/PixelateProcessor.cs | 4 +- .../Processors/ResamplingWeightedProcessor.cs | 1 - .../Samplers/Processors/SkewProcessor.cs | 1 + 51 files changed, 488 insertions(+), 336 deletions(-) create mode 100644 src/ImageProcessorCore/Filters/Processors/IImageFilter.cs create mode 100644 src/ImageProcessorCore/Filters/Processors/ImageFilter.cs create mode 100644 src/ImageProcessorCore/Image/ImageIOExtensions.cs rename src/ImageProcessorCore/Image/{ImageExtensions.cs => ImageProcessingExtensions.cs} (70%) rename src/ImageProcessorCore/{Filters => Samplers}/BoxBlur.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/DetectEdges.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/GuassianBlur.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/GuassianSharpen.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Pixelate.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/BoxBlurProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/Convolution2DFilter.cs (99%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/Convolution2PassFilter.cs (99%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/ConvolutionFilter.cs (99%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs (96%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs (96%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs (95%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/KirschProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/PrewittProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/ScharrProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/EdgeDetection/SobelProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/GuassianBlurProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/Convolution/GuassianSharpenProcessor.cs (100%) rename src/ImageProcessorCore/{Filters => Samplers}/Processors/PixelateProcessor.cs (95%) diff --git a/src/ImageProcessorCore/Filters/Blend.cs b/src/ImageProcessorCore/Filters/Blend.cs index 215bd23eb..ea7af5f19 100644 --- a/src/ImageProcessorCore/Filters/Blend.cs +++ b/src/ImageProcessorCore/Filters/Blend.cs @@ -59,4 +59,4 @@ namespace ImageProcessorCore } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/ColorBlindness.cs b/src/ImageProcessorCore/Filters/ColorBlindness.cs index 462e0e8ff..5a29a63de 100644 --- a/src/ImageProcessorCore/Filters/ColorBlindness.cs +++ b/src/ImageProcessorCore/Filters/ColorBlindness.cs @@ -44,7 +44,7 @@ namespace ImageProcessorCore where TColor : IPackedVector where TPacked : struct { - IImageProcessor processor; + IImageFilter processor; switch (colorBlindness) { diff --git a/src/ImageProcessorCore/Filters/Grayscale.cs b/src/ImageProcessorCore/Filters/Grayscale.cs index 3d8b39e91..f9fae3671 100644 --- a/src/ImageProcessorCore/Filters/Grayscale.cs +++ b/src/ImageProcessorCore/Filters/Grayscale.cs @@ -44,8 +44,8 @@ namespace ImageProcessorCore where TColor : IPackedVector where TPacked : struct { - IImageProcessor processor = mode == GrayscaleMode.Bt709 - ? (IImageProcessor)new GrayscaleBt709Processor() + IImageFilter processor = mode == GrayscaleMode.Bt709 + ? (IImageFilter)new GrayscaleBt709Processor() : new GrayscaleBt601Processor(); processor.OnProgress += progressHandler; diff --git a/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs b/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs index 9572cf63b..8810bd0ec 100644 --- a/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/AlphaProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to change the alpha component of an . + /// An to change the alpha component of an . /// /// The pixel format. /// The packed format. uint, long, float. - public class AlphaProcessor : ImageProcessor + public class AlphaProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -37,7 +37,7 @@ namespace ImageProcessorCore.Processors public int Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { float alpha = this.Value / 100F; int startX = sourceRectangle.X; @@ -63,25 +63,24 @@ namespace ImageProcessorCore.Processors Vector4 alphaVector = new Vector4(1, 1, 1, alpha); using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => + { + int offsetY = y - startY; + for (int x = minX; x < maxX; x++) { - int offsetY = y - startY; - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - TColor packed = default(TColor); - packed.PackFromVector4(sourcePixels[offsetX, offsetY].ToVector4() * alphaVector); - targetPixels[offsetX, offsetY] = packed; - } + int offsetX = x - startX; + TColor packed = default(TColor); + packed.PackFromVector4(sourcePixels[offsetX, offsetY].ToVector4() * alphaVector); + sourcePixels[offsetX, offsetY] = packed; + } - this.OnRowProcessed(); - }); + this.OnRowProcessed(); + }); } } } diff --git a/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs b/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs index cb3173385..6654a961c 100644 --- a/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/BackgroundColorProcessor.cs @@ -12,7 +12,7 @@ namespace ImageProcessorCore.Processors /// /// Sets the background color of the image. /// - public class BackgroundColorProcessor : ImageProcessor + public class BackgroundColorProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -36,7 +36,7 @@ namespace ImageProcessorCore.Processors public TColor Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -61,39 +61,38 @@ namespace ImageProcessorCore.Processors Vector4 backgroundColor = this.Value.ToVector4(); using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => + { + int offsetY = y - startY; + for (int x = minX; x < maxX; x++) { - int offsetY = y - startY; - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - Vector4 color = sourcePixels[offsetX, offsetY].ToVector4(); - float a = color.W; - - if (a < 1 && a > 0) - { - color = Vector4.Lerp(color, backgroundColor, .5F); - } + int offsetX = x - startX; + Vector4 color = sourcePixels[offsetX, offsetY].ToVector4(); + float a = color.W; - if (Math.Abs(a) < Epsilon) - { - color = backgroundColor; - } + if (a < 1 && a > 0) + { + color = Vector4.Lerp(color, backgroundColor, .5F); + } - TColor packed = default(TColor); - packed.PackFromVector4(color); - targetPixels[offsetX, offsetY] = packed; + if (Math.Abs(a) < Epsilon) + { + color = backgroundColor; } - this.OnRowProcessed(); - }); + TColor packed = default(TColor); + packed.PackFromVector4(color); + sourcePixels[offsetX, offsetY] = packed; + } + + this.OnRowProcessed(); + }); } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageProcessorCore/Filters/Processors/Binarization/BinaryThresholdProcessor.cs index 4b4f67b50..9dd9debd2 100644 --- a/src/ImageProcessorCore/Filters/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/Binarization/BinaryThresholdProcessor.cs @@ -9,12 +9,12 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to perform binary threshold filtering against an + /// An to perform binary threshold filtering against an /// . The image will be converted to grayscale before thresholding occurs. /// /// The pixel format. /// The packed format. uint, long, float. - public class BinaryThresholdProcessor : ImageProcessor + public class BinaryThresholdProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -56,13 +56,13 @@ namespace ImageProcessorCore.Processors public TColor LowerColor { get; set; } /// - protected override void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - new GrayscaleBt709Processor().Apply(source, source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle); } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { float threshold = this.Value; TColor upper = this.UpperColor; @@ -88,26 +88,25 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, maxY, this.ParallelOptions, y => + { + int offsetY = y - startY; + for (int x = minX; x < maxX; x++) { - int offsetY = y - startY; - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - TColor color = sourcePixels[offsetX, offsetY]; + int offsetX = x - startX; + TColor color = sourcePixels[offsetX, offsetY]; - // Any channel will do since it's Grayscale. - targetPixels[offsetX, offsetY] = color.ToVector4().X >= threshold ? upper : lower; - } + // Any channel will do since it's Grayscale. + sourcePixels[offsetX, offsetY] = color.ToVector4().X >= threshold ? upper : lower; + } - this.OnRowProcessed(); - }); + this.OnRowProcessed(); + }); } } } diff --git a/src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs b/src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs index 1b333b6f0..e645871e2 100644 --- a/src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/BlendProcessor.cs @@ -14,7 +14,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public class BlendProcessor : ImageProcessor + public class BlendProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -44,7 +44,7 @@ namespace ImageProcessorCore.Processors public int Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -71,7 +71,6 @@ namespace ImageProcessorCore.Processors using (PixelAccessor toBlendPixels = this.blend.Lock()) using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -98,7 +97,7 @@ namespace ImageProcessorCore.Processors TColor packed = default(TColor); packed.PackFromVector4(color); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } this.OnRowProcessed(); diff --git a/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs b/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs index f87e514e9..0e823e712 100644 --- a/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/BrightnessProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to change the brightness of an . + /// An to change the brightness of an . /// /// The pixel format. /// The packed format. uint, long, float. - public class BrightnessProcessor : ImageProcessor + public class BrightnessProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -37,7 +37,7 @@ namespace ImageProcessorCore.Processors public int Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { float brightness = this.Value / 100F; int startX = sourceRectangle.X; @@ -61,7 +61,6 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -82,7 +81,7 @@ namespace ImageProcessorCore.Processors TColor packed = default(TColor); packed.PackFromVector4(vector.Compress()); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } this.OnRowProcessed(); @@ -90,4 +89,4 @@ namespace ImageProcessorCore.Processors } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs index b9817b656..ad41df7ed 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/ColorMatrixFilter.cs @@ -14,7 +14,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class ColorMatrixFilter : ImageProcessor, IColorMatrixFilter + public abstract class ColorMatrixFilter : ImageFilter, IColorMatrixFilter where TColor : IPackedVector where TPacked : struct { @@ -25,7 +25,7 @@ namespace ImageProcessorCore.Processors public override bool Compand { get; set; } = true; /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -51,7 +51,6 @@ namespace ImageProcessorCore.Processors bool compand = this.Compand; using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -63,7 +62,7 @@ namespace ImageProcessorCore.Processors for (int x = minX; x < maxX; x++) { int offsetX = x - startX; - targetPixels[offsetX, offsetY] = this.ApplyMatrix(sourcePixels[offsetX, offsetY], matrix, compand); + sourcePixels[offsetX, offsetY] = this.ApplyMatrix(sourcePixels[offsetX, offsetY], matrix, compand); } this.OnRowProcessed(); @@ -96,4 +95,4 @@ namespace ImageProcessorCore.Processors return packed; } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs index f1f6377ef..4310738b0 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/IColorMatrixFilter.cs @@ -13,7 +13,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public interface IColorMatrixFilter : IImageProcessor + public interface IColorMatrixFilter : IImageFilter where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs index 10de7109c..16831e8d8 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/LomographProcessor.cs @@ -28,11 +28,11 @@ namespace ImageProcessorCore.Processors }; /// - protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected override void AfterApply(ImageBase source, Rectangle sourceRectangle) { TColor packed = default(TColor); packed.PackFromBytes(0, 10, 0, 255); // Very dark (mostly black) lime green. - new VignetteProcessor { VignetteColor = packed }.Apply(target, target, sourceRectangle); + new VignetteProcessor { VignetteColor = packed }.Apply(source, sourceRectangle); } } } diff --git a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs index c737a7bb6..638997ce5 100644 --- a/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/ColorMatrix/PolaroidProcessor.cs @@ -34,15 +34,15 @@ namespace ImageProcessorCore.Processors }; /// - protected override void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + protected override void AfterApply(ImageBase source, Rectangle sourceRectangle) { TColor packedV = default(TColor); packedV.PackFromBytes(102, 34, 0, 255); // Very dark orange [Brown tone] - new VignetteProcessor { VignetteColor = packedV }.Apply(target, target, sourceRectangle); + new VignetteProcessor { VignetteColor = packedV }.Apply(source, sourceRectangle); TColor packedG = default(TColor); packedG.PackFromBytes(255, 153, 102, 178); // Light orange - new GlowProcessor { GlowColor = packedG, Radius = target.Width / 4F }.Apply(target, target, sourceRectangle); + new GlowProcessor { GlowColor = packedG, Radius = source.Width / 4F }.Apply(source, sourceRectangle); } } } \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs b/src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs index 54a9e10cc..ca2c4a3d0 100644 --- a/src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/ContrastProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to change the contrast of an . + /// An to change the contrast of an . /// - /// The pixel format. + /// The pixel format. /// The packed format. long, float. - public class ContrastProcessor : ImageProcessor + public class ContrastProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -37,7 +37,7 @@ namespace ImageProcessorCore.Processors public int Value { get; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { float contrast = (100F + this.Value) / 100F; int startX = sourceRectangle.X; @@ -63,7 +63,6 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -82,7 +81,7 @@ namespace ImageProcessorCore.Processors vector += shiftVector; TColor packed = default(TColor); packed.PackFromVector4(vector.Compress()); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } this.OnRowProcessed(); @@ -90,4 +89,4 @@ namespace ImageProcessorCore.Processors } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs b/src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs index 10a68ffcf..5186a8bd0 100644 --- a/src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/GlowProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An that applies a radial glow effect an . + /// An that applies a radial glow effect an . /// /// The pixel format. /// The packed format. uint, long, float. - public class GlowProcessor : ImageProcessor + public class GlowProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -39,7 +39,7 @@ namespace ImageProcessorCore.Processors public float Radius { get; set; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -66,7 +66,6 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -85,7 +84,7 @@ namespace ImageProcessorCore.Processors Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TColor packed = default(TColor); packed.PackFromVector4(Vector4.Lerp(glowColor.ToVector4(), sourceColor, distance / maxDistance)); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } } @@ -94,5 +93,4 @@ namespace ImageProcessorCore.Processors } } } -} - +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/IImageFilter.cs b/src/ImageProcessorCore/Filters/Processors/IImageFilter.cs new file mode 100644 index 000000000..69037f6c1 --- /dev/null +++ b/src/ImageProcessorCore/Filters/Processors/IImageFilter.cs @@ -0,0 +1,31 @@ +namespace ImageProcessorCore.Processors +{ + /// + /// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels. + /// + /// The pixel format. + /// The packed format. uint, long, float. + public interface IImageFilter : IImageProcessor + where TColor : IPackedVector + where TPacked : struct + { + /// + /// Applies the process to the specified portion of the specified . + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// The method keeps the source image unchanged and returns the + /// the result of image processing filter as new image. + /// + /// + /// is null. + /// + /// + /// doesnt fit the dimension of the image. + /// + void Apply(ImageBase source, Rectangle sourceRectangle); + } +} diff --git a/src/ImageProcessorCore/Filters/Processors/ImageFilter.cs b/src/ImageProcessorCore/Filters/Processors/ImageFilter.cs new file mode 100644 index 000000000..6dcbb5a3d --- /dev/null +++ b/src/ImageProcessorCore/Filters/Processors/ImageFilter.cs @@ -0,0 +1,68 @@ +namespace ImageProcessorCore.Processors +{ + using System; + + /// + /// Encapsulates methods to alter the pixels of an image. The processor operates on the original source pixels. + /// + /// The pixel format. + /// The packed format. uint, long, float. + public abstract class ImageFilter : ImageProcessor, IImageFilter + where TColor : IPackedVector + where TPacked : struct + { + /// + public void Apply(ImageBase source, Rectangle sourceRectangle) + { + try + { + this.OnApply(source, sourceRectangle); + + this.NumRowsProcessed = 0; + this.TotalRows = sourceRectangle.Height; + + this.Apply(source, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); + + this.AfterApply(source, sourceRectangle); + } + catch (Exception ex) + { + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + /// Applies the process to the specified portion of the specified at the specified location + /// and with the specified size. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// The index of the row within the source image to start processing. + /// The index of the row within the source image to end processing. + protected abstract void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY); + + /// + /// This method is called before the process is applied to prepare the processor. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void OnApply(ImageBase source, Rectangle sourceRectangle) + { + } + + /// + /// This method is called after the process is applied to prepare the processor. + /// + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void AfterApply(ImageBase source, Rectangle sourceRectangle) + { + } + } +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs b/src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs index ca66ce4c3..5c77eb5ca 100644 --- a/src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/InvertProcessor.cs @@ -10,16 +10,16 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to invert the colors of an . + /// An to invert the colors of an . /// /// The pixel format. /// The packed format. uint, long, float. - public class InvertProcessor : ImageProcessor + public class InvertProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -43,7 +43,6 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -60,7 +59,7 @@ namespace ImageProcessorCore.Processors TColor packed = default(TColor); packed.PackFromVector4(new Vector4(vector, color.W)); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } this.OnRowProcessed(); @@ -68,5 +67,4 @@ namespace ImageProcessorCore.Processors } } } -} - +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs b/src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs index 142f20e6b..56a85111e 100644 --- a/src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs +++ b/src/ImageProcessorCore/Filters/Processors/VignetteProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An that applies a radial vignette effect to an . + /// An that applies a radial vignette effect to an . /// /// The pixel format. /// The packed format. uint, long, float. - public class VignetteProcessor : ImageProcessor + public class VignetteProcessor : ImageFilter where TColor : IPackedVector where TPacked : struct { @@ -44,7 +44,7 @@ namespace ImageProcessorCore.Processors public float RadiusY { get; set; } /// - protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) + protected override void Apply(ImageBase source, Rectangle sourceRectangle, int startY, int endY) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -72,7 +72,6 @@ namespace ImageProcessorCore.Processors } using (PixelAccessor sourcePixels = source.Lock()) - using (PixelAccessor targetPixels = target.Lock()) { Parallel.For( minY, @@ -88,7 +87,7 @@ namespace ImageProcessorCore.Processors Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); TColor packed = default(TColor); packed.PackFromVector4(Vector4.Lerp(vignetteColor.ToVector4(), sourceColor, 1 - (.9F * (distance / maxDistance)))); - targetPixels[offsetX, offsetY] = packed; + sourcePixels[offsetX, offsetY] = packed; } this.OnRowProcessed(); diff --git a/src/ImageProcessorCore/Image/IImageProcessor.cs b/src/ImageProcessorCore/Image/IImageProcessor.cs index 06f0514d8..3942bf1db 100644 --- a/src/ImageProcessorCore/Image/IImageProcessor.cs +++ b/src/ImageProcessorCore/Image/IImageProcessor.cs @@ -17,11 +17,7 @@ namespace ImageProcessorCore.Processors /// /// Encapsulates methods to alter the pixels of an image. /// - /// The pixel format. - /// The packed format. uint, long, float. - public interface IImageProcessor - where TColor : IPackedVector - where TPacked : struct + public interface IImageProcessor { /// /// Event fires when each row of the source image has been processed. @@ -42,46 +38,5 @@ namespace ImageProcessorCore.Processors /// or expand individual pixel colors the value on processing. /// bool Compand { get; set; } - - /// - /// Applies the process to the specified portion of the specified . - /// - /// Target image to apply the process to. - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - /// - /// The method keeps the source image unchanged and returns the - /// the result of image processing filter as new image. - /// - /// - /// is null or is null. - /// - /// - /// doesnt fit the dimension of the image. - /// - void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle); - - /// - /// Applies the process to the specified portion of the specified at the specified - /// location and with the specified size. - /// - /// Target image to apply the process to. - /// The source image. Cannot be null. - /// The target width. - /// The target height. - /// - /// The structure that specifies the location and size of the drawn image. - /// The image is scaled to fit the rectangle. - /// - /// - /// The structure that specifies the portion of the image object to draw. - /// - /// - /// The method keeps the source image unchanged and returns the - /// the result of image process as new image. - /// - void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle); } } diff --git a/src/ImageProcessorCore/Image/ImageIOExtensions.cs b/src/ImageProcessorCore/Image/ImageIOExtensions.cs new file mode 100644 index 000000000..9241a58ed --- /dev/null +++ b/src/ImageProcessorCore/Image/ImageIOExtensions.cs @@ -0,0 +1,74 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + using System.IO; + + using Formats; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Saves the image to the given stream with the bmp format. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The image this method extends. + /// The stream to save the image to. + /// Thrown if the stream is null. + public static void SaveAsBmp(this Image source, Stream stream) + where TColor : IPackedVector + where TPacked : struct + => new BmpEncoder().Encode(source, stream); + + /// + /// Saves the image to the given stream with the png format. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The image this method extends. + /// The stream to save the image to. + /// The quality to save the image to representing the number of colors. + /// Anything equal to 256 and below will cause the encoder to save the image in an indexed format. + /// + /// Thrown if the stream is null. + public static void SaveAsPng(this Image source, Stream stream, int quality = int.MaxValue) + where TColor : IPackedVector + where TPacked : struct + => new PngEncoder { Quality = quality }.Encode(source, stream); + + /// + /// Saves the image to the given stream with the jpeg format. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The image this method extends. + /// The stream to save the image to. + /// The quality to save the image to. Between 1 and 100. + /// Thrown if the stream is null. + public static void SaveAsJpeg(this Image source, Stream stream, int quality = 75) + where TColor : IPackedVector + where TPacked : struct + => new JpegEncoder { Quality = quality }.Encode(source, stream); + + /// + /// Saves the image to the given stream with the gif format. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The image this method extends. + /// The stream to save the image to. + /// The quality to save the image to representing the number of colors. Between 1 and 256. + /// Thrown if the stream is null. + internal static void SaveAsGif(this Image source, Stream stream, int quality = 256) + where TColor : IPackedVector + where TPacked : struct + => new GifEncoder { Quality = quality }.Encode(source, stream); + } +} diff --git a/src/ImageProcessorCore/Image/ImageExtensions.cs b/src/ImageProcessorCore/Image/ImageProcessingExtensions.cs similarity index 70% rename from src/ImageProcessorCore/Image/ImageExtensions.cs rename to src/ImageProcessorCore/Image/ImageProcessingExtensions.cs index 103f8c3eb..25e41bf28 100644 --- a/src/ImageProcessorCore/Image/ImageExtensions.cs +++ b/src/ImageProcessorCore/Image/ImageProcessingExtensions.cs @@ -6,9 +6,6 @@ namespace ImageProcessorCore { using System; - using System.IO; - - using Formats; using Processors; /// @@ -17,65 +14,42 @@ namespace ImageProcessorCore public static partial class ImageExtensions { /// - /// Saves the image to the given stream with the bmp format. + /// Applies the processor to the image. + /// This method does not resize the target image. /// /// The pixel format. /// The packed format. uint, long, float. /// The image this method extends. - /// The stream to save the image to. - /// Thrown if the stream is null. - public static void SaveAsBmp(this Image source, Stream stream) + /// The processor to apply to the image. + /// The . + internal static Image Process(this Image source, IImageFilter processor) where TColor : IPackedVector where TPacked : struct - => new BmpEncoder().Encode(source, stream); - + { + return Process(source, source.Bounds, processor); + } /// - /// Saves the image to the given stream with the png format. + /// Applies the processor to the image. + /// This method does not resize the target image. /// /// The pixel format. /// The packed format. uint, long, float. /// The image this method extends. - /// The stream to save the image to. - /// The quality to save the image to representing the number of colors. - /// Anything equal to 256 and below will cause the encoder to save the image in an indexed format. + /// + /// The structure that specifies the portion of the image object to draw. /// - /// Thrown if the stream is null. - public static void SaveAsPng(this Image source, Stream stream, int quality = int.MaxValue) - where TColor : IPackedVector - where TPacked : struct - => new PngEncoder { Quality = quality }.Encode(source, stream); - - /// - /// Saves the image to the given stream with the jpeg format. - /// - /// The pixel format. - /// The packed format. uint, long, float. - /// The image this method extends. - /// The stream to save the image to. - /// The quality to save the image to. Between 1 and 100. - /// Thrown if the stream is null. - public static void SaveAsJpeg(this Image source, Stream stream, int quality = 75) - where TColor : IPackedVector - where TPacked : struct - => new JpegEncoder { Quality = quality }.Encode(source, stream); - - /// - /// Saves the image to the given stream with the gif format. - /// - /// The pixel format. - /// The packed format. uint, long, float. - /// The image this method extends. - /// The stream to save the image to. - /// The quality to save the image to representing the number of colors. Between 1 and 256. - /// Thrown if the stream is null. - internal static void SaveAsGif(this Image source, Stream stream, int quality = 256) + /// The processors to apply to the image. + /// The . + internal static Image Process(this Image source, Rectangle sourceRectangle, IImageFilter processor) where TColor : IPackedVector where TPacked : struct - => new GifEncoder { Quality = quality }.Encode(source, stream); + { + return PerformAction(source, (sourceImage) => processor.Apply(sourceImage, sourceRectangle)); + } /// - /// Applies the collection of processors to the image. + /// Applies the processor to the image. /// This method does not resize the target image. /// /// The pixel format. @@ -83,7 +57,7 @@ namespace ImageProcessorCore /// The image this method extends. /// The processor to apply to the image. /// The . - internal static Image Process(this Image source, IImageProcessor processor) + internal static Image Process(this Image source, IImageSampler processor) where TColor : IPackedVector where TPacked : struct { @@ -91,7 +65,7 @@ namespace ImageProcessorCore } /// - /// Applies the collection of processors to the image. + /// Applies the processor to the image. /// This method does not resize the target image. /// /// The pixel format. @@ -102,7 +76,7 @@ namespace ImageProcessorCore /// /// The processors to apply to the image. /// The . - internal static Image Process(this Image source, Rectangle sourceRectangle, IImageProcessor processor) + internal static Image Process(this Image source, Rectangle sourceRectangle, IImageSampler processor) where TColor : IPackedVector where TPacked : struct { @@ -110,12 +84,12 @@ namespace ImageProcessorCore } /// - /// Applies the collection of processors to the image. + /// Applies the processor to the image. /// - /// This method is not chainable. + /// This method resizes the image. /// /// - /// The pixel format. + /// The pixel format. /// The packed format. long, float. /// The source image. Cannot be null. /// The target image width. @@ -130,12 +104,12 @@ namespace ImageProcessorCore } /// - /// Applies the collection of processors to the image. + /// Applies the processor to the image. /// /// This method does will resize the target image if the source and target rectangles are different. /// /// - /// The pixel format. + /// The pixel format. /// The packed format. long, float. /// The source image. Cannot be null. /// The target image width. @@ -159,7 +133,29 @@ namespace ImageProcessorCore /// /// Performs the given action on the source image. /// - /// The pixel format. + /// The pixel format. + /// The packed format. long, float. + /// The image to perform the action against. + /// The to perform against the image. + /// The . + private static Image PerformAction(Image source, Action> action) + where TColor : IPackedVector + where TPacked : struct + { + action(source); + + foreach (ImageFrame sourceFrame in source.Frames) + { + action(sourceFrame); + } + + return source; + } + + /// + /// Performs the given action on the source image. + /// + /// The pixel format. /// The packed format. long, float. /// The image to perform the action against. /// Whether to clone the image. diff --git a/src/ImageProcessorCore/ImageProcessor.cs b/src/ImageProcessorCore/ImageProcessor.cs index 10014e0f3..4ec10a6a5 100644 --- a/src/ImageProcessorCore/ImageProcessor.cs +++ b/src/ImageProcessorCore/ImageProcessor.cs @@ -5,7 +5,6 @@ namespace ImageProcessorCore.Processors { - using System; using System.Threading; using System.Threading.Tasks; @@ -14,7 +13,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class ImageProcessor : IImageProcessor + public abstract class ImageProcessor : IImageProcessor where TColor : IPackedVector where TPacked : struct { @@ -24,12 +23,12 @@ namespace ImageProcessorCore.Processors /// /// The number of rows processed by a derived class. /// - private int numRowsProcessed; + protected int NumRowsProcessed; /// /// The total number of rows that will be processed by a derived class. /// - private int totalRows; + protected int TotalRows; /// public virtual ParallelOptions ParallelOptions { get; set; } = Bootstrapper.Instance.ParallelOptions; @@ -37,114 +36,6 @@ namespace ImageProcessorCore.Processors /// public virtual bool Compand { get; set; } = false; - /// - public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) - { - try - { - this.OnApply(target, source, target.Bounds, sourceRectangle); - - this.numRowsProcessed = 0; - this.totalRows = sourceRectangle.Height; - - this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); - - this.AfterApply(target, source, target.Bounds, sourceRectangle); - } - catch (Exception ex) - { - - throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); - } - } - - /// - public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle)) - { - try - { - TColor[] pixels = new TColor[width * height]; - target.SetPixels(width, height, pixels); - - // Ensure we always have bounds. - if (sourceRectangle == Rectangle.Empty) - { - sourceRectangle = source.Bounds; - } - - if (targetRectangle == Rectangle.Empty) - { - targetRectangle = target.Bounds; - } - - this.OnApply(target, source, targetRectangle, sourceRectangle); - - this.numRowsProcessed = 0; - this.totalRows = targetRectangle.Height; - - this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); - - this.AfterApply(target, source, target.Bounds, sourceRectangle); - } - catch (Exception ex) - { - throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); - } - } - - /// - /// This method is called before the process is applied to prepare the processor. - /// - /// Target image to apply the process to. - /// The source image. Cannot be null. - /// - /// The structure that specifies the location and size of the drawn image. - /// The image is scaled to fit the rectangle. - /// - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) - { - } - - /// - /// Applies the process to the specified portion of the specified at the specified location - /// and with the specified size. - /// - /// Target image to apply the process to. - /// The source image. Cannot be null. - /// - /// The structure that specifies the location and size of the drawn image. - /// The image is scaled to fit the rectangle. - /// - /// - /// The structure that specifies the portion of the image object to draw. - /// - /// The index of the row within the source image to start processing. - /// The index of the row within the source image to end processing. - /// - /// The method keeps the source image unchanged and returns the - /// the result of image process as new image. - /// - protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); - - /// - /// This method is called after the process is applied to prepare the processor. - /// - /// Target image to apply the process to. - /// The source image. Cannot be null. - /// - /// The structure that specifies the location and size of the drawn image. - /// The image is scaled to fit the rectangle. - /// - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) - { - } - /// /// Must be called by derived classes after processing a single row. /// @@ -152,17 +43,17 @@ namespace ImageProcessorCore.Processors { if (this.OnProgress != null) { - int currThreadNumRows = Interlocked.Add(ref this.numRowsProcessed, 1); + int currThreadNumRows = Interlocked.Add(ref this.NumRowsProcessed, 1); // Multi-pass filters process multiple times more rows than totalRows, so update totalRows on the fly - if (currThreadNumRows > this.totalRows) + if (currThreadNumRows > this.TotalRows) { - this.totalRows = currThreadNumRows; + this.TotalRows = currThreadNumRows; } // Report progress. This may be on the client's thread, or on a Task library thread. - this.OnProgress(this, new ProgressEventArgs { RowsProcessed = currThreadNumRows, TotalRows = this.totalRows }); + this.OnProgress(this, new ProgressEventArgs { RowsProcessed = currThreadNumRows, TotalRows = this.TotalRows }); } } } -} +} \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/BoxBlur.cs b/src/ImageProcessorCore/Samplers/BoxBlur.cs similarity index 100% rename from src/ImageProcessorCore/Filters/BoxBlur.cs rename to src/ImageProcessorCore/Samplers/BoxBlur.cs diff --git a/src/ImageProcessorCore/Filters/DetectEdges.cs b/src/ImageProcessorCore/Samplers/DetectEdges.cs similarity index 100% rename from src/ImageProcessorCore/Filters/DetectEdges.cs rename to src/ImageProcessorCore/Samplers/DetectEdges.cs diff --git a/src/ImageProcessorCore/Filters/GuassianBlur.cs b/src/ImageProcessorCore/Samplers/GuassianBlur.cs similarity index 100% rename from src/ImageProcessorCore/Filters/GuassianBlur.cs rename to src/ImageProcessorCore/Samplers/GuassianBlur.cs diff --git a/src/ImageProcessorCore/Filters/GuassianSharpen.cs b/src/ImageProcessorCore/Samplers/GuassianSharpen.cs similarity index 100% rename from src/ImageProcessorCore/Filters/GuassianSharpen.cs rename to src/ImageProcessorCore/Samplers/GuassianSharpen.cs diff --git a/src/ImageProcessorCore/Filters/Pixelate.cs b/src/ImageProcessorCore/Samplers/Pixelate.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Pixelate.cs rename to src/ImageProcessorCore/Samplers/Pixelate.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/BoxBlurProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/BoxBlurProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/BoxBlurProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2DFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs similarity index 99% rename from src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2DFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs index 264406b88..a923c0bfc 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2DFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2DFilter.cs @@ -14,7 +14,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class Convolution2DFilter : ImageProcessor + public abstract class Convolution2DFilter : ImageSampler where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2PassFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs similarity index 99% rename from src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2PassFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs index 74a600d22..a73113554 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/Convolution2PassFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/Convolution2PassFilter.cs @@ -13,7 +13,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class Convolution2PassFilter : ImageProcessor + public abstract class Convolution2PassFilter : ImageSampler where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/ConvolutionFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs similarity index 99% rename from src/ImageProcessorCore/Filters/Processors/Convolution/ConvolutionFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs index da0c11df5..60c03218a 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/ConvolutionFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/ConvolutionFilter.cs @@ -13,7 +13,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public abstract class ConvolutionFilter : ImageProcessor + public abstract class ConvolutionFilter : ImageSampler where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs similarity index 96% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs index 34a589630..88414ca3a 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetector2DFilter.cs @@ -23,7 +23,7 @@ namespace ImageProcessorCore.Processors { if (this.Grayscale) { - new GrayscaleBt709Processor().Apply(source, source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle); } } } diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs similarity index 96% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs index 04cd2cddd..1c1a2cba7 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/EdgeDetectorFilter.cs @@ -23,7 +23,7 @@ namespace ImageProcessorCore.Processors { if (this.Grayscale) { - new GrayscaleBt709Processor().Apply(source, source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle); } } } diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs similarity index 95% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs index 620db328e..0f0fedb8e 100644 --- a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs +++ b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/IEdgeDetectorFilter.cs @@ -10,7 +10,7 @@ namespace ImageProcessorCore.Processors /// /// The pixel format. /// The packed format. uint, long, float. - public interface IEdgeDetectorFilter : IImageProcessor, IEdgeDetectorFilter + public interface IEdgeDetectorFilter : IImageSampler, IEdgeDetectorFilter where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KayyaliProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/KirschProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/KirschProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian3X3Processor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/Laplacian5X5Processor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/LaplacianOfGaussianProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/PrewittProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/PrewittProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/RobertsCrossProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/ScharrProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/ScharrProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/EdgeDetection/SobelProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/EdgeDetection/SobelProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/GuassianBlurProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/GuassianBlurProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianBlurProcessor.cs diff --git a/src/ImageProcessorCore/Filters/Processors/Convolution/GuassianSharpenProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianSharpenProcessor.cs similarity index 100% rename from src/ImageProcessorCore/Filters/Processors/Convolution/GuassianSharpenProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/Convolution/GuassianSharpenProcessor.cs diff --git a/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs index 1f858631d..847c90d6e 100644 --- a/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/EntropyCropProcessor.cs @@ -50,7 +50,7 @@ namespace ImageProcessorCore.Processors new SobelProcessor().Apply(temp, source, sourceRectangle); // Apply threshold binarization filter. - new BinaryThresholdProcessor(.5f).Apply(temp, temp, sourceRectangle); + new BinaryThresholdProcessor(.5f).Apply(temp, sourceRectangle); // Search for the first white pixels Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); diff --git a/src/ImageProcessorCore/Samplers/Processors/IImageSampler.cs b/src/ImageProcessorCore/Samplers/Processors/IImageSampler.cs index edf293b1f..4484356d0 100644 --- a/src/ImageProcessorCore/Samplers/Processors/IImageSampler.cs +++ b/src/ImageProcessorCore/Samplers/Processors/IImageSampler.cs @@ -6,11 +6,53 @@ namespace ImageProcessorCore.Processors { /// - /// Acts as a marker for generic parameters that require an image sampler. + /// Encapsulates methods to alter the pixels of an image. The processor creates a copy of the original image to operate on. /// - public interface IImageSampler : IImageProcessor + /// The pixel format. + /// The packed format. uint, long, float. + public interface IImageSampler : IImageProcessor where TColor : IPackedVector where TPacked : struct { + /// + /// Applies the process to the specified portion of the specified . + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// The method keeps the source image unchanged and returns the + /// the result of image processing filter as new image. + /// + /// + /// is null or is null. + /// + /// + /// doesnt fit the dimension of the image. + /// + void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle); + + /// + /// Applies the process to the specified portion of the specified at the specified + /// location and with the specified size. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// The target width. + /// The target height. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// + /// The method keeps the source image unchanged and returns the + /// the result of image process as new image. + /// + void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle, Rectangle sourceRectangle); } } diff --git a/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs b/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs index 1256897db..956ce4df0 100644 --- a/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs +++ b/src/ImageProcessorCore/Samplers/Processors/ImageSampler.cs @@ -5,9 +5,10 @@ namespace ImageProcessorCore.Processors { + using System; + /// - /// Applies sampling methods to an image. - /// All processors requiring resampling or resizing should inherit from this. + /// Encapsulates methods to alter the pixels of an image. The processor creates a copy of the original image to operate on. /// /// The pixel format. /// The packed format. uint, long, float. @@ -15,5 +16,111 @@ namespace ImageProcessorCore.Processors where TColor : IPackedVector where TPacked : struct { + /// + public void Apply(ImageBase target, ImageBase source, Rectangle sourceRectangle) + { + try + { + this.OnApply(target, source, target.Bounds, sourceRectangle); + + this.NumRowsProcessed = 0; + this.TotalRows = sourceRectangle.Height; + + this.Apply(target, source, target.Bounds, sourceRectangle, sourceRectangle.Y, sourceRectangle.Bottom); + + this.AfterApply(target, source, target.Bounds, sourceRectangle); + } + catch (Exception ex) + { + + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + public void Apply(ImageBase target, ImageBase source, int width, int height, Rectangle targetRectangle = default(Rectangle), Rectangle sourceRectangle = default(Rectangle)) + { + try + { + TColor[] pixels = new TColor[width * height]; + target.SetPixels(width, height, pixels); + + // Ensure we always have bounds. + if (sourceRectangle == Rectangle.Empty) + { + sourceRectangle = source.Bounds; + } + + if (targetRectangle == Rectangle.Empty) + { + targetRectangle = target.Bounds; + } + + this.OnApply(target, source, targetRectangle, sourceRectangle); + + this.NumRowsProcessed = 0; + this.TotalRows = targetRectangle.Height; + + this.Apply(target, source, targetRectangle, sourceRectangle, targetRectangle.Y, targetRectangle.Bottom); + + this.AfterApply(target, source, target.Bounds, sourceRectangle); + } + catch (Exception ex) + { + throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. See the inner exception for more detail.", ex); + } + } + + /// + /// Applies the process to the specified portion of the specified at the specified location + /// and with the specified size. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// The index of the row within the source image to start processing. + /// The index of the row within the source image to end processing. + /// + /// The method keeps the source image unchanged and returns the the result of image process as new image. + /// + protected abstract void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY); + + /// + /// This method is called before the process is applied to prepare the processor. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void OnApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + { + } + + /// + /// This method is called after the process is applied to prepare the processor. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + protected virtual void AfterApply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle) + { + } } } \ No newline at end of file diff --git a/src/ImageProcessorCore/Filters/Processors/PixelateProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs similarity index 95% rename from src/ImageProcessorCore/Filters/Processors/PixelateProcessor.cs rename to src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs index 300081050..f0d75eb8a 100644 --- a/src/ImageProcessorCore/Filters/Processors/PixelateProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/PixelateProcessor.cs @@ -10,11 +10,11 @@ namespace ImageProcessorCore.Processors using System.Threading.Tasks; /// - /// An to pixelate the colors of an . + /// An to pixelate the colors of an . /// /// The pixel format. /// The packed format. uint, long, float. - public class PixelateProcessor : ImageProcessor + public class PixelateProcessor : ImageSampler where TColor : IPackedVector where TPacked : struct { diff --git a/src/ImageProcessorCore/Samplers/Processors/ResamplingWeightedProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/ResamplingWeightedProcessor.cs index 16f2ec292..338b52906 100644 --- a/src/ImageProcessorCore/Samplers/Processors/ResamplingWeightedProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/ResamplingWeightedProcessor.cs @@ -65,7 +65,6 @@ namespace ImageProcessorCore.Processors } } - /// /// Computes the weights to apply at each pixel when resizing. /// diff --git a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs index 44d1efd8f..6f3344f32 100644 --- a/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs +++ b/src/ImageProcessorCore/Samplers/Processors/SkewProcessor.cs @@ -5,6 +5,7 @@ namespace ImageProcessorCore.Processors { + using System; using System.Numerics; using System.Threading.Tasks;