From 07e9f23dec36dace67d17eb9f20249bf83930361 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Mon, 4 Sep 2017 23:09:37 +0100 Subject: [PATCH 01/24] wip - pixel data only on image frames --- src/ImageSharp.Drawing/Brushes/IBrush.cs | 2 +- .../Brushes/ImageBrush{TPixel}.cs | 10 +- .../Brushes/PatternBrush{TPixel}.cs | 4 +- .../Brushes/Processors/BrushApplicator.cs | 4 +- .../Brushes/RecolorBrush{TPixel}.cs | 4 +- .../Brushes/SolidBrush{TPixel}.cs | 4 +- .../Processors/DrawImageProcessor.cs | 4 +- .../Processors/FillProcessor.cs | 4 +- .../Processors/FillRegionProcessor.cs | 2 +- .../Advanced/IPixelSource{TPixel}.cs | 21 -- src/ImageSharp/Advanced/ImageExtensions.cs | 29 +- src/ImageSharp/Common/Helpers/ImageMaths.cs | 12 +- .../ErrorDiffusion/ErrorDiffuserBase.cs | 4 +- .../ErrorDiffusion/IErrorDiffuser.cs | 4 +- .../Dithering/Ordered/IOrderedDither.cs | 2 +- .../Dithering/Ordered/OrderedDitherBase.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 10 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 8 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 37 +- src/ImageSharp/Formats/IImageDecoder.cs | 2 +- .../Common/Decoder/JpegImagePostProcessor.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 8 +- .../Image/ICloningImageProcessor.cs | 2 +- src/ImageSharp/Image/IImage.cs | 19 - src/ImageSharp/Image/IImageBase.cs | 28 -- src/ImageSharp/Image/IImageFrame.cs | 34 +- src/ImageSharp/Image/IImageProcessor.cs | 2 +- src/ImageSharp/Image/ImageBase{TPixel}.cs | 333 ------------------ src/ImageSharp/Image/ImageExtensions.cs | 50 ++- src/ImageSharp/Image/ImageFrameCollection.cs | 148 ++++++++ src/ImageSharp/Image/ImageFrame{TPixel}.cs | 220 +++++++++--- src/ImageSharp/Image/Image{TPixel}.cs | 193 +++++----- .../Image/PixelAccessorExtensions.cs | 36 ++ src/ImageSharp/Image/PixelAccessor{TPixel}.cs | 39 +- .../Binarization/BinaryThresholdProcessor.cs | 6 +- .../ErrorDiffusionDitherProcessor.cs | 4 +- .../Binarization/OrderedDitherProcessor.cs | 4 +- .../Processors/CloningImageProcessor.cs | 18 +- .../ColorMatrix/ColorMatrixProcessor.cs | 4 +- .../ColorMatrix/LomographProcessor.cs | 2 +- .../ColorMatrix/PolaroidProcessor.cs | 2 +- .../Convolution/BoxBlurProcessor.cs | 2 +- .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 6 +- .../Convolution/ConvolutionProcessor.cs | 4 +- .../EdgeDetection/EdgeDetector2DProcessor.cs | 4 +- .../EdgeDetectorCompassProcessor.cs | 10 +- .../EdgeDetection/EdgeDetectorProcessor.cs | 4 +- .../Convolution/GaussianBlurProcessor.cs | 2 +- .../Convolution/GaussianSharpenProcessor.cs | 2 +- .../Processors/DelegateProcessor.cs | 2 +- .../Processors/Effects/AlphaProcessor.cs | 4 +- .../Effects/BackgroundColorProcessor.cs | 4 +- .../Processors/Effects/BrightnessProcessor.cs | 4 +- .../Processors/Effects/ContrastProcessor.cs | 4 +- .../Processors/Effects/InvertProcessor.cs | 4 +- .../Effects/OilPaintingProcessor.cs | 4 +- .../Processors/Effects/PixelateProcessor.cs | 4 +- .../Processing/Processors/ImageProcessor.cs | 10 +- .../Processors/Overlays/GlowProcessor.cs | 4 +- .../Processors/Overlays/VignetteProcessor.cs | 4 +- .../Transforms/AutoRotateProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 4 +- .../Transforms/EntropyCropProcessor.cs | 4 +- .../Processors/Transforms/FlipProcessor.cs | 10 +- .../Transforms/Matrix3x2Processor.cs | 2 +- .../Transforms/ResamplingWeightedProcessor.cs | 4 +- .../Processors/Transforms/ResizeProcessor.cs | 19 +- .../Processors/Transforms/RotateProcessor.cs | 20 +- .../Processors/Transforms/SkewProcessor.cs | 6 +- .../Transforms/Options/ResizeHelper.cs | 12 +- .../Processing/Transforms/Resize.cs | 6 +- .../Quantizers/IQuantizer{TPixel}.cs | 2 +- .../Quantizers/OctreeQuantizer{TPixel}.cs | 4 +- .../Quantizers/PaletteQuantizer{TPixel}.cs | 4 +- src/ImageSharp/Quantizers/Quantize.cs | 2 +- .../Quantizers/QuantizerBase{TPixel}.cs | 8 +- .../Quantizers/WuQuantizer{TPixel}.cs | 6 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 4 +- .../ImageComparison/ExactImageComparer.cs | 4 +- .../ImageComparison/ImageComparer.cs | 22 +- .../ImageComparison/ImageSimilarityReport.cs | 8 +- .../ImageComparison/TolerantImageComparer.cs | 2 +- .../TestUtilities/ImagingTestCaseUtility.cs | 14 +- 85 files changed, 788 insertions(+), 792 deletions(-) delete mode 100644 src/ImageSharp/Advanced/IPixelSource{TPixel}.cs delete mode 100644 src/ImageSharp/Image/IImage.cs delete mode 100644 src/ImageSharp/Image/IImageBase.cs delete mode 100644 src/ImageSharp/Image/ImageBase{TPixel}.cs create mode 100644 src/ImageSharp/Image/ImageFrameCollection.cs create mode 100644 src/ImageSharp/Image/PixelAccessorExtensions.cs diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs index 8b163d7f67..bb907281b0 100644 --- a/src/ImageSharp.Drawing/Brushes/IBrush.cs +++ b/src/ImageSharp.Drawing/Brushes/IBrush.cs @@ -32,6 +32,6 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// The when being applied to things like shapes would usually be the /// bounding box of the shape not necessarily the bounds of the whole image /// - BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options); + BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs index 850775ce05..4cd3585ec7 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs @@ -21,19 +21,19 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// /// The image to paint. /// - private readonly ImageBase image; + private readonly ImageFrame image; /// /// Initializes a new instance of the class. /// /// The image. - public ImageBrush(ImageBase image) + public ImageBrush(ImageFrame image) { this.image = image; } /// - public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) { return new ImageBrushApplicator(source, this.image, region, options); } @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// /// The source image. /// - private readonly ImageBase source; + private readonly ImageFrame source; /// /// The y-length. @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// The image. /// The region. /// The options - public ImageBrushApplicator(ImageBase target, ImageBase image, RectangleF region, GraphicsOptions options) + public ImageBrushApplicator(ImageFrame target, ImageFrame image, RectangleF region, GraphicsOptions options) : base(target, options) { this.source = image; diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs index b1dab0ea9c..844df0e0e9 100644 --- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes } /// - public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) { return new PatternBrushApplicator(source, this.pattern, this.patternVector, options); } @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// The pattern. /// The patternVector. /// The options - public PatternBrushApplicator(ImageBase source, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options) + public PatternBrushApplicator(ImageFrame source, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options) : base(source, options) { this.pattern = pattern; diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs index 258d69721c..ca6f7630d9 100644 --- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes.Processors /// /// The target. /// The options. - internal BrushApplicator(ImageBase target, GraphicsOptions options) + internal BrushApplicator(ImageFrame target, GraphicsOptions options) { this.Target = target; @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes.Processors /// /// Gets the destinaion /// - protected ImageBase Target { get; } + protected ImageFrame Target { get; } /// /// Gets the blend percentage diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs index bbd0e4d864..ba2fca4e4b 100644 --- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes public TPixel TargeTPixel { get; } /// - public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) { return new RecolorBrushApplicator(source, this.SourceColor, this.TargeTPixel, this.Threshold, options); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// Color of the target. /// The threshold . /// The options - public RecolorBrushApplicator(ImageBase source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) + public RecolorBrushApplicator(ImageFrame source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) : base(source, options) { this.sourceColor = sourceColor.ToVector4(); diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs index 27bce86bfb..658164339d 100644 --- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes public TPixel Color => this.color; /// - public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) { return new SolidBrushApplicator(source, this.color, options); } @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes /// The source image. /// The color. /// The options - public SolidBrushApplicator(ImageBase source, TPixel color, GraphicsOptions options) + public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOptions options) : base(source, options) { this.Colors = new Buffer(source.Width); diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs index e1ce6b0133..2a8e2cf4ca 100644 --- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors public Point Location { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { Image disposableImage = null; Image targetImage = this.Image; @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span background = sourcePixels.GetRowSpan(y).Slice(minX, width); diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index fbd9654262..57c4e3d9b8 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { int offsetY = y - startY; diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 3e0dedb3b0..1022f63083 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors public GraphicsOptions Options { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { Region region = this.Region; Rectangle rect = region.Bounds; diff --git a/src/ImageSharp/Advanced/IPixelSource{TPixel}.cs b/src/ImageSharp/Advanced/IPixelSource{TPixel}.cs deleted file mode 100644 index 777cb76e2e..0000000000 --- a/src/ImageSharp/Advanced/IPixelSource{TPixel}.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Advanced -{ - /// - /// Allows access to the pixels as an area of contiguous memory in the given pixel format. - /// - /// The type of the pixel. - internal interface IPixelSource - where TPixel : struct, IPixel - { - /// - /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. - /// - Span Span { get; } - } -} diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index 7377e6ca0b..1bd7c0cc4d 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -22,10 +22,31 @@ namespace SixLabors.ImageSharp.Advanced /// The type of the pixel. /// The source. /// The - public static Span GetPixelSpan(this ImageBase source) + public static Span GetPixelSpan(this ImageFrame source) where TPixel : struct, IPixel => GetSpan(source); + /// + /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. + /// + /// The type of the pixel. + /// The source. + /// The + public static Span GetPixelSpan(this Image source) + where TPixel : struct, IPixel + => GetSpan(source); + + /// + /// Gets a representing the row 'y' beginning from the the first pixel on that row. + /// + /// The type of the pixel. + /// The source. + /// The row. + /// The + public static Span GetPixelRowSpan(this ImageFrame source, int row) + where TPixel : struct, IPixel + => GetSpan(source).Slice(row * source.Width, source.Width); + /// /// Gets a representing the row 'y' beginning from the the first pixel on that row. /// @@ -33,7 +54,7 @@ namespace SixLabors.ImageSharp.Advanced /// The source. /// The row. /// The - public static Span GetPixelRowSpan(this ImageBase source, int row) + public static Span GetPixelRowSpan(this Image source, int row) where TPixel : struct, IPixel => GetSpan(source).Slice(row * source.Width, source.Width); @@ -43,8 +64,8 @@ namespace SixLabors.ImageSharp.Advanced /// The type of the pixel. /// The source. /// The span retuned from Pixel source - private static Span GetSpan(IPixelSource source) + private static Span GetSpan(IImageFrame source) where TPixel : struct, IPixel - => source.Span; + => source.PixelBuffer.Span; } } diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 8cf220b300..2fda9341a6 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - public static Rectangle GetFilteredBoundingRectangle(ImageBase bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) + public static Rectangle GetFilteredBoundingRectangle(ImageFrame bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) where TPixel : struct, IPixel { int width = bitmap.Width; @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp var topLeft = default(Point); var bottomRight = default(Point); - Func, int, int, float, bool> delegateFunc; + Func, int, int, float, bool> delegateFunc; // Determine which channel to check against switch (channel) @@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp break; } - int GetMinY(ImageBase pixels) + int GetMinY(ImageFrame pixels) { for (int y = 0; y < height; y++) { @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp return 0; } - int GetMaxY(ImageBase pixels) + int GetMaxY(ImageFrame pixels) { for (int y = height - 1; y > -1; y--) { @@ -212,7 +212,7 @@ namespace SixLabors.ImageSharp return height; } - int GetMinX(ImageBase pixels) + int GetMinX(ImageFrame pixels) { for (int x = 0; x < width; x++) { @@ -228,7 +228,7 @@ namespace SixLabors.ImageSharp return 0; } - int GetMaxX(ImageBase pixels) + int GetMaxX(ImageFrame pixels) { for (int x = width - 1; x > -1; x--) { diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs index 3fb86f1924..510a097eaf 100644 --- a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs +++ b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Dithering.Base /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dither(ImageBase pixels, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY) + public void Dither(ImageFrame pixels, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY) where TPixel : struct, IPixel { this.Dither(pixels, source, transformed, x, y, minX, minY, maxX, maxY, true); @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Dithering.Base /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel) + public void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel) where TPixel : struct, IPixel { if (replacePixel) diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs index 850c978fef..c538d643c6 100644 --- a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs +++ b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Dithering /// The maximum column value. /// The maximum row value. /// The pixel format. - void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY) + void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY) where TPixel : struct, IPixel; /// @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Dithering /// Generally this would be true for standard two-color dithering but when used in conjunction with color quantization this should be false. /// /// The pixel format. - void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel) + void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs index e3c7c5cbaf..e0e11ad9ee 100644 --- a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs +++ b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Dithering /// The column index. /// The row index. /// The pixel format. - void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y) + void Dither(ImageFrame image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs b/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs index 6fa406bec8..09c30eb272 100644 --- a/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs +++ b/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Dithering.Base } /// - public void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y) + public void Dither(ImageFrame image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y) where TPixel : struct, IPixel { // TODO: This doesn't really cut it for me. diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 12dd0f91a3..6ac1243620 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp } /// - /// Encodes the image to the specified stream from the . + /// Encodes the image to the specified stream from the . /// /// The pixel format. - /// The to encode from. + /// The to encode from. /// The to encode the image data to. - public void Encode(ImageBase image, Stream stream) + public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { Guard.NotNull(image, nameof(image)); @@ -125,9 +125,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The pixel format. /// The containing the stream to write to. /// - /// The containing pixel data. + /// The containing pixel data. /// - private void WriteImage(EndianBinaryWriter writer, ImageBase image) + private void WriteImage(EndianBinaryWriter writer, IImageFrame image) where TPixel : struct, IPixel { using (PixelAccessor pixels = image.Lock()) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index cb124d305a..8666dca7ae 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Gif ImageFrame currentFrame = null; - ImageBase image; + ImageFrame image; if (this.previousFrame == null) { @@ -378,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.SetFrameMetaData(this.metaData); - image = this.image; + image = (ImageFrame)this.image; } else { @@ -471,7 +471,7 @@ namespace SixLabors.ImageSharp.Formats.Gif return; } - this.previousFrame = currentFrame == null ? this.image.ToFrame() : currentFrame; + this.previousFrame = currentFrame == null ? this.image : currentFrame; if (this.graphicsControlExtension != null && this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground) @@ -484,7 +484,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Restores the current frame area to the background. /// /// The frame. - private void RestoreToBackground(ImageBase frame) + private void RestoreToBackground(ImageFrame frame) { if (this.restoreArea == null) { diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 5022678384..7b12b95b14 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Get the number of bits. this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); - this.hasFrames = image.Frames.Any(); + this.hasFrames = image.Frames.Count > 1; // Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames. var ditheredQuantizer = (IQuantizer)this.quantizer; @@ -114,28 +114,29 @@ namespace SixLabors.ImageSharp.Formats.Gif this.WriteLogicalScreenDescriptor(image, writer, index); // Write the first frame. - this.WriteGraphicalControlExtension(image.MetaData, writer, index); this.WriteComments(image, writer); - this.WriteImageDescriptor(image, writer); - this.WriteColorTable(quantized, writer); - this.WriteImageData(quantized, writer); // Write additional frames. if (this.hasFrames) { this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count); + } - // ReSharper disable once ForCanBeConvertedToForeach - for (int i = 0; i < image.Frames.Count; i++) + // ReSharper disable once ForCanBeConvertedToForeach + for (int i = 0; i < image.Frames.Count; i++) + { + ImageFrame frame = image.Frames[i]; + if (quantized == null) { - ImageFrame frame = image.Frames[i]; - QuantizedImage quantizedFrame = ditheredQuantizer.Quantize(frame, paletteSize); - - this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantizedFrame)); - this.WriteImageDescriptor(frame, writer); - this.WriteColorTable(quantizedFrame, writer); - this.WriteImageData(quantizedFrame, writer); + quantized = ditheredQuantizer.Quantize(frame, paletteSize); } + + this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantized)); + this.WriteImageDescriptor(frame, writer); + this.WriteColorTable(quantized, writer); + this.WriteImageData(quantized, writer); + + quantized = null; // so next frame can regenerate it } // TODO: Write extension etc @@ -253,7 +254,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the image comments to the stream. /// /// The pixel format. - /// The to be encoded. + /// The to be encoded. /// The stream to write to. private void WriteComments(Image image, EndianBinaryWriter writer) where TPixel : struct, IPixel @@ -321,9 +322,9 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the image descriptor to the stream. /// /// The pixel format. - /// The to be encoded. + /// The to be encoded. /// The stream to write to. - private void WriteImageDescriptor(ImageBase image, EndianBinaryWriter writer) + private void WriteImageDescriptor(ImageFrame image, EndianBinaryWriter writer) where TPixel : struct, IPixel { writer.Write(GifConstants.ImageDescriptorLabel); // 2c @@ -347,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Writes the color table to the stream. /// /// The pixel format. - /// The to encode. + /// The to encode. /// The writer to write to the stream with. private void WriteColorTable(QuantizedImage image, EndianBinaryWriter writer) where TPixel : struct, IPixel diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs index 86d5f5375b..e392cf7c61 100644 --- a/src/ImageSharp/Formats/IImageDecoder.cs +++ b/src/ImageSharp/Formats/IImageDecoder.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats public interface IImageDecoder { /// - /// Decodes the image from the specified stream to the . + /// Decodes the image from the specified stream to the . /// /// The pixel format. /// The configuration for the image. diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs index 57b29e8ab4..52fc1c2286 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// (4) Packing pixels from the buffer.
/// These operations are executed in steps. /// image rows are converted in one step, - /// which means that size of the allocated memory is limited (does not depend on ). + /// which means that size of the allocated memory is limited (does not depend on ). /// internal class JpegImagePostProcessor : IDisposable { diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index 786f3fe901..739fd6051e 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Png public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding; /// - /// Decodes the image from the specified stream to the . + /// Decodes the image from the specified stream to the . /// /// The pixel format. /// The configuration for the image. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index dfc905bfa3..6ca27d5333 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// Encodes the image to the specified stream from the . /// /// The pixel format. - /// The to encode from. + /// The to encode from. /// The to encode the image data to. public void Encode(Image image, Stream stream) where TPixel : struct, IPixel @@ -233,7 +233,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Collect the indexed pixel data if (this.pngColorType == PngColorType.Palette) { - this.CollectIndexedBytes(image, stream, header); + this.CollectIndexedBytes(image, stream, header); } this.WritePhysicalChunk(stream, image); @@ -304,7 +304,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image to encode. /// The containing image data. /// The . - private void CollectIndexedBytes(ImageBase image, Stream stream, PngHeader header) + private void CollectIndexedBytes(ImageFrame image, Stream stream, PngHeader header) where TPixel : struct, IPixel { // Quantize the image and get the pixels. @@ -529,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . /// The image to encode. /// The - private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageBase image) + private QuantizedImage WritePaletteChunk(Stream stream, PngHeader header, ImageFrame image) where TPixel : struct, IPixel { if (this.paletteSize > 256) diff --git a/src/ImageSharp/Image/ICloningImageProcessor.cs b/src/ImageSharp/Image/ICloningImageProcessor.cs index 1e7d6e4f0a..aeb3c815ec 100644 --- a/src/ImageSharp/Image/ICloningImageProcessor.cs +++ b/src/ImageSharp/Image/ICloningImageProcessor.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Processing where TPixel : struct, IPixel { /// - /// Applies the process to the specified portion of the specified . + /// Applies the process to the specified portion of the specified . /// /// The source image. Cannot be null. /// diff --git a/src/ImageSharp/Image/IImage.cs b/src/ImageSharp/Image/IImage.cs deleted file mode 100644 index 3223e20f75..0000000000 --- a/src/ImageSharp/Image/IImage.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.MetaData; - -namespace SixLabors.ImageSharp -{ - /// - /// Encapsulates the basic properties and methods required to manipulate images. - /// - internal interface IImage : IImageBase - { - /// - /// Gets the meta data of the image. - /// - ImageMetaData MetaData { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs deleted file mode 100644 index 9aea1517d6..0000000000 --- a/src/ImageSharp/Image/IImageBase.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp -{ - /// - /// Encapsulates the basic properties and methods required to manipulate images. - /// - public interface IImageBase - { - /// - /// Gets the width in pixels. - /// - int Width { get; } - - /// - /// Gets the height in pixels. - /// - int Height { get; } - - /// - /// Gets the configuration providing initialization code which allows extending the library. - /// - Configuration Configuration { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs index 31a8165887..244a60a892 100644 --- a/src/ImageSharp/Image/IImageFrame.cs +++ b/src/ImageSharp/Image/IImageFrame.cs @@ -1,18 +1,50 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp { /// /// Encapsulates the basic properties and methods required to manipulate images. /// - internal interface IImageFrame : IImageBase + /// The type of the pixel. + internal interface IImageFrame : IImageFrame + where TPixel : struct, IPixel + { + /// + /// Gets the parent. + /// + Image Parent { get; } + + /// + /// Gets the pixel buffer. + /// + Buffer2D PixelBuffer { get; } + } + + /// + /// Encapsulates the basic properties and methods required to manipulate images. + /// + public interface IImageFrame : IDisposable { /// /// Gets the meta data of the image. /// ImageFrameMetaData MetaData { get; } + + /// + /// Gets the width. + /// + int Width { get; } + + /// + /// Gets the height. + /// + int Height { get; } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/IImageProcessor.cs b/src/ImageSharp/Image/IImageProcessor.cs index b81f08e150..bd6df8d835 100644 --- a/src/ImageSharp/Image/IImageProcessor.cs +++ b/src/ImageSharp/Image/IImageProcessor.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { /// - /// Applies the process to the specified portion of the specified . + /// Applies the process to the specified portion of the specified . /// /// The source image. Cannot be null. /// diff --git a/src/ImageSharp/Image/ImageBase{TPixel}.cs b/src/ImageSharp/Image/ImageBase{TPixel}.cs deleted file mode 100644 index e9987e0c76..0000000000 --- a/src/ImageSharp/Image/ImageBase{TPixel}.cs +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Diagnostics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp -{ - /// - /// The base class of all images. Encapsulates the basic properties and methods required to manipulate - /// images in different pixel formats. - /// - /// The pixel format. - public abstract class ImageBase : IImageBase, IDisposable, IPixelSource - where TPixel : struct, IPixel - { -#pragma warning disable SA1401 // Fields must be private - /// - /// The image pixels. Not private as Buffer2D requires an array in its constructor. - /// - internal TPixel[] PixelBuffer; -#pragma warning restore SA1401 // Fields must be private - - /// - /// A value indicating whether this instance of the given entity has been disposed. - /// - /// if this instance has been disposed; otherwise, . - /// - /// If the entity is disposed, it must not be disposed a second time. The isDisposed field is set the first time the entity - /// is disposed. If the isDisposed field is true, then the Dispose() method will not dispose again. This help not to prolong the entity's - /// life in the Garbage Collector. - /// - private bool isDisposed; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - protected ImageBase(Configuration configuration) - { - this.Configuration = configuration ?? Configuration.Default; - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The configuration providing initialization code which allows extending the library. - /// - /// The width of the image in pixels. - /// The height of the image in pixels. - /// - /// Thrown if either or are less than or equal to 0. - /// - protected ImageBase(Configuration configuration, int width, int height) - : this(configuration) - { - Guard.MustBeGreaterThan(width, 0, nameof(width)); - Guard.MustBeGreaterThan(height, 0, nameof(height)); - - this.Width = width; - this.Height = height; - this.RentPixels(); - this.ClearPixels(); - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The other to create this instance from. - /// - /// - /// Thrown if the given is null. - /// - protected ImageBase(ImageBase other) - : this(other.Configuration) - { - Guard.NotNull(other, nameof(other), "Other image cannot be null."); - - this.Width = other.Width; - this.Height = other.Height; - this.CopyProperties(other); - - // Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here. - this.RentPixels(); - - other.GetPixelSpan().CopyTo(this.GetPixelSpan()); - } - - /// - Span IPixelSource.Span => new Span(this.PixelBuffer, 0, this.Width * this.Height); - - /// - public int Width { get; private set; } - - /// - public int Height { get; private set; } - - /// - /// Gets the configuration providing initialization code which allows extending the library. - /// - public Configuration Configuration { get; private set; } - - /// - /// Gets or sets the pixel at the specified position. - /// - /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image. - /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. - /// The at the specified position. - public TPixel this[int x, int y] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - this.CheckCoordinates(x, y); - return this.PixelBuffer[(y * this.Width) + x]; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.CheckCoordinates(x, y); - this.PixelBuffer[(y * this.Width) + x] = value; - } - } - - /// - /// Gets a reference to the pixel at the specified position. - /// - /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image. - /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. - /// The at the specified position. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref TPixel GetPixelReference(int x, int y) - { - this.CheckCoordinates(x, y); - return ref this.PixelBuffer[(y * this.Width) + x]; - } - - /// - /// Clones the image - /// - /// A new items which is a clone of the original. - public ImageBase Clone() - { - return this.CloneImageBase(); - } - - /// - public void Dispose() - { - this.Dispose(true); - - // This object will be cleaned up by the Dispose method. - // Therefore, you should call GC.SuppressFinalize to - // take this object off the finalization queue - // and prevent finalization code for this object - // from executing a second time. - GC.SuppressFinalize(this); - } - - /// - /// Locks the image providing access to the pixels. - /// - /// It is imperative that the accessor is correctly disposed off after use. - /// - /// - /// The - internal PixelAccessor Lock() - { - return new PixelAccessor(this); - } - - /// - /// Copies the pixels to another of the same size. - /// - /// The target pixel buffer accessor. - internal void CopyTo(PixelAccessor target) - { - SpanHelper.Copy(this.GetPixelSpan(), target.PixelBuffer.Span); - } - - /// - /// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer. - /// - /// The pixel source. - internal void SwapPixelsBuffers(PixelAccessor pixelSource) - { - Guard.NotNull(pixelSource, nameof(pixelSource)); - - int newWidth = pixelSource.Width; - int newHeight = pixelSource.Height; - - // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use) - TPixel[] newPixels = pixelSource.ReturnCurrentColorsAndReplaceThemInternally(this.Width, this.Height, this.PixelBuffer); - this.Width = newWidth; - this.Height = newHeight; - this.PixelBuffer = newPixels; - } - - /// - /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. - /// - /// The pixel source. - internal void SwapPixelsData(ImageBase pixelSource) - { - Guard.NotNull(pixelSource, nameof(pixelSource)); - - int newWidth = pixelSource.Width; - int newHeight = pixelSource.Height; - TPixel[] newPixels = pixelSource.PixelBuffer; - - pixelSource.PixelBuffer = this.PixelBuffer; - pixelSource.Width = this.Width; - pixelSource.Height = this.Height; - - this.Width = newWidth; - this.Height = newHeight; - this.PixelBuffer = newPixels; - } - - /// - /// Clones the image - /// - /// A new items which is a clone of the original. - protected abstract ImageBase CloneImageBase(); - - /// - /// Copies the properties from the other . - /// - /// - /// The other to copy the properties from. - /// - protected void CopyProperties(IImageBase other) - { - DebugGuard.NotNull(other, nameof(other)); - - this.Configuration = other.Configuration; - } - - /// - /// Disposes the object and frees resources for the Garbage Collector. - /// - /// If true, the object gets disposed. - protected virtual void Dispose(bool disposing) - { - if (this.isDisposed) - { - return; - } - - if (disposing) - { - this.ReturnPixels(); - } - - // Note disposing is done. - this.isDisposed = true; - } - - /// - /// Rents the pixel array from the pool. - /// - private void RentPixels() - { - this.PixelBuffer = PixelDataPool.Rent(this.Width * this.Height); - } - - /// - /// Returns the rented pixel array back to the pool. - /// - private void ReturnPixels() - { - PixelDataPool.Return(this.PixelBuffer); - this.PixelBuffer = null; - } - - /// - /// Clears the pixel array. - /// - private void ClearPixels() - { - Array.Clear(this.PixelBuffer, 0, this.Width * this.Height); - } - - /// - /// Checks the coordinates to ensure they are within bounds. - /// - /// The y-coordinate of the pixel. Must be greater than zero and less than the height of the image. - /// - /// Thrown if the coordinates are not within the bounds of the image. - /// - [Conditional("DEBUG")] - private void CheckCoordinates(int y) - { - if (y < 0 || y >= this.Height) - { - throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds."); - } - } - - /// - /// Checks the coordinates to ensure they are within bounds. - /// - /// The x-coordinate of the pixel. Must be greater than zero and less than the width of the image. - /// The y-coordinate of the pixel. Must be greater than zero and less than the height of the image. - /// - /// Thrown if the coordinates are not within the bounds of the image. - /// - [Conditional("DEBUG")] - private void CheckCoordinates(int x, int y) - { - if (x < 0 || x >= this.Width) - { - throw new ArgumentOutOfRangeException(nameof(x), x, $"{x} is outwith the image bounds."); - } - - if (y < 0 || y >= this.Height) - { - throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds."); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageExtensions.cs b/src/ImageSharp/Image/ImageExtensions.cs index 6844bdc813..9c7b0962ea 100644 --- a/src/ImageSharp/Image/ImageExtensions.cs +++ b/src/ImageSharp/Image/ImageExtensions.cs @@ -24,7 +24,27 @@ namespace SixLabors.ImageSharp /// The Pixel format. /// The source image /// Returns the bounds of the image - public static Rectangle Bounds(this ImageBase source) + public static Configuration Configuration(this ImageFrame source) + where TPixel : struct, IPixel + => source.Parent?.Configuration ?? SixLabors.ImageSharp.Configuration.Default; + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Rectangle Bounds(this Image source) + where TPixel : struct, IPixel + => new Rectangle(0, 0, source.Width, source.Height); + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Rectangle Bounds(this ImageFrame source) where TPixel : struct, IPixel => new Rectangle(0, 0, source.Width, source.Height); @@ -34,7 +54,17 @@ namespace SixLabors.ImageSharp /// The Pixel format. /// The source image /// Returns the bounds of the image - public static Size Size(this ImageBase source) + public static Size Size(this Image source) + where TPixel : struct, IPixel + => new Size(source.Width, source.Height); + + /// + /// Gets the size of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Size Size(this ImageFrame source) where TPixel : struct, IPixel => new Size(source.Width, source.Height); @@ -131,6 +161,22 @@ namespace SixLabors.ImageSharp source.Save(stream, encoder); } + /// + /// Saves the raw image to the given bytes. + /// + /// The Pixel format. + /// The source image + /// The buffer to save the raw pixel data to. + /// Thrown if the stream is null. + public static void SavePixelData(this ImageFrame source, Span buffer) + where TPixel : struct, IPixel + { + Span byteBuffer = source.GetPixelSpan().AsBytes(); + Guard.MustBeGreaterThanOrEqualTo(buffer.Length, byteBuffer.Length, nameof(buffer)); + + byteBuffer.CopyTo(buffer); + } + /// /// Saves the raw image to the given bytes. /// diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs new file mode 100644 index 0000000000..186f94762e --- /dev/null +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -0,0 +1,148 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.MetaData; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp +{ + /// + /// Encapsulates an imaged collection of frames. + /// + /// The type of the pixel. + public sealed class ImageFrameCollection : IEnumerable> + where TPixel : struct, IPixel + { + private IList> frames = new List>(); + private readonly Image parent; + + internal ImageFrameCollection(Image parent) + { + this.parent = parent; + } + + /// + /// Gets the count. + /// + public int Count { get => this.frames.Count; } + + /// + /// Gets or sets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// The at the specified index. + public ImageFrame this[int index] + { + get + { + return this.frames[index]; + } + + set + { + this.ValidateFrameSize(value); + this.frames[index] = value; + } + } + + /// + /// Determines the index of a specific in the . + /// + /// The to locate in the . + /// The index of item if found in the list; otherwise, -1. + public int IndexOf(ImageFrame frame) => this.frames.IndexOf(frame); + + /// + /// Inserts the to the at the specified . + /// + /// The zero-based index at which item should be inserted.. + /// The to insert into the . + public void Insert(int index, ImageFrame frame) + { + this.ValidateFrameSize(frame); + this.frames.Insert(index, frame); + } + + /// + /// Removes the from the at the specified index. + /// + /// The zero-based index of the item to remove. + /// Cannot remove last frame. + public void RemoveAt(int index) + { + if (index > 0 || this.frames.Count > 1) + { + this.frames.RemoveAt(index); + } + + throw new InvalidOperationException("Cannot remove last frame."); + } + + /// + /// Adds the specified frame. + /// + /// The frame. + /// Frame must have the same dimensions as the image - frame + public void Add(ImageFrame frame) + { + this.ValidateFrameSize(frame); + this.frames.Add(frame); + } + + private void ValidateFrameSize(ImageFrame frame) + { + if (this.parent.Width != frame.Width || this.parent.Height != frame.Height) + { + throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); + } + } + + /// + /// Determines whether the contains the . + /// + /// The frame. + /// + /// true if the the specified frame; otherwise, false. + /// + public bool Contains(ImageFrame frame) + { + return this.frames.Contains(frame); + } + + /// + /// Removes the specified frame. + /// + /// The frame. + /// true if item is found in the ; otherwise, + /// Cannot remove last frame + public bool Remove(ImageFrame frame) + { + if (this.frames.Count == 1 && this.frames.Contains(frame)) + { + throw new InvalidOperationException("Cannot remove last frame"); + } + + return this.frames.Remove(frame); + } + + /// + IEnumerator> IEnumerable>.GetEnumerator() => this.frames.GetEnumerator(); + + /// + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.frames).GetEnumerator(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index bd5e272618..cc5c8b1ac9 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -2,8 +2,12 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Diagnostics; using System.Numerics; +using System.Runtime.CompilerServices; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; @@ -13,74 +17,194 @@ namespace SixLabors.ImageSharp /// Represents a single frame in a animation. /// /// The pixel format. - public sealed class ImageFrame : ImageBase, IImageFrame + public sealed class ImageFrame : IImageFrame where TPixel : struct, IPixel { /// - /// Initializes a new instance of the class. + /// The image pixels. Not private as Buffer2D requires an array in its constructor. + /// + private Buffer2D pixelBuffer; + + private bool isDisposed = false; + + /// + /// Initializes a new instance of the class. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// /// The width of the image in pixels. /// The height of the image in pixels. - public ImageFrame(Configuration configuration, int width, int height) - : base(configuration, width, height) + internal ImageFrame(int width, int height) + : this(width, height, new ImageFrameMetaData()) { - this.MetaData = new ImageFrameMetaData(); } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// /// The width of the image in pixels. /// The height of the image in pixels. - /// The metadata of the frame. - public ImageFrame(Configuration configuration, int width, int height, ImageFrameMetaData metadata) - : base(configuration, width, height) + /// The meta data. + internal ImageFrame(int width, int height, ImageFrameMetaData metaData) { - Guard.NotNull(metadata, nameof(metadata)); - this.MetaData = metadata; + Guard.MustBeGreaterThan(width, 0, nameof(width)); + Guard.MustBeGreaterThan(height, 0, nameof(height)); + Guard.NotNull(metaData, nameof(metaData)); + + this.Width = width; + this.Height = height; + this.pixelBuffer = Buffer2D.CreateClean(width, height); + this.MetaData = metaData; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The width of the image in pixels. - /// The height of the image in pixels. - public ImageFrame(int width, int height) - : this(null, width, height) + /// The source. + internal ImageFrame(ImageFrame source) + { + this.Width = source.Width; + this.Height = source.Height; + this.pixelBuffer = new Buffer2D(source.Width, source.Height); + source.pixelBuffer.Span.CopyTo(this.pixelBuffer.Span); + this.MetaData = source.MetaData.Clone(); + } + + /// + Buffer2D IImageFrame.PixelBuffer => this.pixelBuffer; + + /// + public int Width { get; private set; } + + /// + public int Height { get; private set; } + + /// + /// Gets the configuration providing initialization code which allows extending the library. + /// + public Image Parent { get; private set; } + + /// + /// Gets the meta data of the frame. + /// + public ImageFrameMetaData MetaData { get; private set; } + + /// + /// Gets or sets the pixel at the specified position. + /// + /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image. + /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. + /// The at the specified position. + public TPixel this[int x, int y] { - this.MetaData = new ImageFrameMetaData(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return this.pixelBuffer[x, y]; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + this.pixelBuffer[x, y] = value; + } } /// - /// Initializes a new instance of the class. + /// Performs an explicit conversion from to . /// - /// The image to create the frame from. - internal ImageFrame(ImageBase image) - : base(image) + /// The image. + /// + /// The result of the conversion. + /// + public static implicit operator ImageFrame(Image image) => image.Frames[0]; + + /// + /// Gets a reference to the pixel at the specified position. + /// + /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image. + /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. + /// The at the specified position. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ref TPixel GetPixelReference(int x, int y) { - this.MetaData = new ImageFrameMetaData(); + return ref this.pixelBuffer[x, y]; } /// - /// Initializes a new instance of the class. + /// Locks the image providing access to the pixels. + /// + /// It is imperative that the accessor is correctly disposed off after use. + /// /// - /// The image to create the frame from. - private ImageFrame(ImageFrame image) - : base(image) + /// The + internal PixelAccessor Lock() { - this.CopyProperties(image); + return new PixelAccessor(this); } /// - /// Gets the meta data of the frame. + /// Copies the pixels to another of the same size. /// - public ImageFrameMetaData MetaData { get; private set; } + /// The target pixel buffer accessor. + internal void CopyTo(PixelAccessor target) + { + SpanHelper.Copy(this.GetPixelSpan(), target.PixelBuffer.Span); + } + + /// + /// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer. + /// + /// The pixel source. + internal void SwapPixelsBuffers(PixelAccessor pixelSource) + { + Guard.NotNull(pixelSource, nameof(pixelSource)); + + int newWidth = pixelSource.Width; + int newHeight = pixelSource.Height; + + // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use) + var newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer); + this.Width = newWidth; + this.Height = newHeight; + this.pixelBuffer = newPixels; + } + + /// + /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. + /// + /// The pixel source. + internal void SwapPixelsBuffers(ImageFrame pixelSource) + { + Guard.NotNull(pixelSource, nameof(pixelSource)); + + int newWidth = pixelSource.Width; + int newHeight = pixelSource.Height; + var newPixels = pixelSource.pixelBuffer; + + pixelSource.pixelBuffer = this.pixelBuffer; + pixelSource.Width = this.Width; + pixelSource.Height = this.Height; + + this.Width = newWidth; + this.Height = newHeight; + this.pixelBuffer = newPixels; + } + + /// + /// Disposes the object and frees resources for the Garbage Collector. + /// + public void Dispose() + { + if (this.isDisposed) + { + return; + } + + this.pixelBuffer?.Dispose(); + this.pixelBuffer = null; + + // Note disposing is done. + this.isDisposed = true; + } /// public override string ToString() @@ -103,8 +227,7 @@ namespace SixLabors.ImageSharp Func scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(); - var target = new ImageFrame(this.Configuration, this.Width, this.Height); - target.CopyProperties(this); + var target = new ImageFrame(this.Width, this.Height, this.MetaData.Clone()); using (PixelAccessor pixels = this.Lock()) using (PixelAccessor targetPixels = target.Lock()) @@ -112,7 +235,7 @@ namespace SixLabors.ImageSharp Parallel.For( 0, target.Height, - this.Configuration.ParallelOptions, + this.Configuration().ParallelOptions, y => { for (int x = 0; x < target.Width; x++) @@ -131,28 +254,9 @@ namespace SixLabors.ImageSharp /// Clones the current instance. /// /// The - public new ImageFrame Clone() + public ImageFrame Clone() { return new ImageFrame(this); } - - /// - protected override ImageBase CloneImageBase() - { - return this.Clone(); - } - - /// - /// Copies the properties from the other . - /// - /// - /// The other to copy the properties from. - /// - private void CopyProperties(IImageFrame other) - { - base.CopyProperties(other); - - this.MetaData = new ImageFrameMetaData(other.MetaData); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 900045dbad..94d6ddb6ab 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -2,13 +2,17 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; +using System.Linq; using System.Numerics; using System.Text; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; @@ -20,7 +24,7 @@ namespace SixLabors.ImageSharp /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// /// The pixel format. - public sealed class Image : ImageBase, IImage + public sealed partial class Image : IImageFrame where TPixel : struct, IPixel { /// @@ -59,41 +63,78 @@ namespace SixLabors.ImageSharp /// The height of the image in pixels. /// The images metadata. internal Image(Configuration configuration, int width, int height, ImageMetaData metadata) - : base(configuration, width, height) + : this(configuration, width, height, metadata, null) { - this.MetaData = metadata ?? new ImageMetaData(); } /// - /// Initializes a new instance of the class - /// by making a copy from another image. + /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// - /// The other image, where the clone should be made from. - /// is null. - private Image(Image other) - : base(other) + /// The pixel source. + internal void SwapPixelsBuffers(Image pixelSource) { - foreach (ImageFrame frame in other.Frames) + Guard.NotNull(pixelSource, nameof(pixelSource)); + + this.Width = pixelSource.Width; + this.Height = pixelSource.Height; + int newHeight = pixelSource.Height; + + for (int i = 0; i < this.Frames.Count; i++) + { + this.Frames[i].SwapPixelsBuffers(pixelSource.Frames[i]); + } + } + + + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// The configuration providing initialization code which allows extending the library. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The images metadata. + /// The frames that will be owned by this image instance. + internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable> frames) + { + this.Configuration = configuration ?? Configuration.Default; + this.Width = width; + this.Height = height; + this.MetaData = metadata ?? new ImageMetaData(); + + this.Frames = new ImageFrameCollection(this); + + if (frames != null) { - if (frame != null) + foreach (ImageFrame f in frames) { - this.Frames.Add(frame.Clone()); + this.Frames.Add(f); } } - this.CopyProperties(other); + if (this.Frames.Count == 0) + { + this.Frames.Add(new ImageFrame(this.Width, this.Height)); + } } /// - /// Initializes a new instance of the class - /// by making a copy from another image. + /// Gets the configuration. /// - /// The other image, where the clone should be made from. - /// is null. - private Image(ImageBase other) - : base(other) - { - } + /// + /// The configuration. + /// + public Configuration Configuration { get; } + + /// + /// Gets the width. + /// + public int Width { get; private set; } + + /// + /// Gets the height. + /// + public int Height { get; private set; } /// /// Gets the meta data of the image. @@ -101,10 +142,42 @@ namespace SixLabors.ImageSharp public ImageMetaData MetaData { get; private set; } = new ImageMetaData(); /// - /// Gets the other frames associated with this image. + /// Gets the frames. + /// + public ImageFrameCollection Frames { get; private set; } + + /// + /// Gets the root frame. + /// + private IImageFrame RootFrame => this.Frames[0]; + + /// + Buffer2D IImageFrame.PixelBuffer => this.RootFrame.PixelBuffer; + + /// + ImageFrameMetaData IImageFrame.MetaData => this.RootFrame.MetaData; + + /// + Image IImageFrame.Parent => this.RootFrame.Parent; + + /// + /// Gets or sets the pixel at the specified position. /// - /// The list of frame images. - public IList> Frames { get; } = new List>(); + /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image. + /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. + /// The at the specified position. + public TPixel this[int x, int y] + { + get + { + return this.RootFrame.PixelBuffer[x, y]; + } + + set + { + this.RootFrame.PixelBuffer[x, y] = value; + } + } /// /// Saves the image to the given stream using the given image encoder. @@ -124,9 +197,11 @@ namespace SixLabors.ImageSharp /// Clones the current image /// /// Returns a new image with all the same metadata as the original. - public new Image Clone() + public Image Clone() { - return new Image(this); + IEnumerable> frames = this.Frames.Select(x => x.Clone()).ToArray(); + + return new Image(this.Configuration, this.Width, this.Height, this.MetaData.Clone(), frames); } /// @@ -143,79 +218,21 @@ namespace SixLabors.ImageSharp public Image CloneAs() where TPixel2 : struct, IPixel { - if (typeof(TPixel2) == typeof(TPixel)) - { - // short circuit when same pixel types - return this.Clone() as Image; - } - - Func scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(); - - var target = new Image(this.Configuration, this.Width, this.Height); - target.CopyProperties(this); - - using (PixelAccessor pixels = this.Lock()) - using (PixelAccessor targetPixels = target.Lock()) - { - Parallel.For( - 0, - target.Height, - this.Configuration.ParallelOptions, - y => - { - for (int x = 0; x < target.Width; x++) - { - var color = default(TPixel2); - color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4())); - targetPixels[x, y] = color; - } - }); - } - - for (int i = 0; i < this.Frames.Count; i++) - { - target.Frames.Add(this.Frames[i].CloneAs()); - } + IEnumerable> frames = this.Frames.Select(x => x.CloneAs()).ToArray(); + var target = new Image(this.Configuration, this.Width, this.Height, this.MetaData, frames); return target; } /// - /// Creates a new from this instance + /// Releases managed resources. /// - /// The - internal ImageFrame ToFrame() + public void Dispose() { - return new ImageFrame(this); - } - - /// - protected override void Dispose(bool disposing) - { - // ReSharper disable once ForCanBeConvertedToForeach for (int i = 0; i < this.Frames.Count; i++) { this.Frames[i].Dispose(); } - - base.Dispose(disposing); - } - - /// - protected override ImageBase CloneImageBase() - { - return this.Clone(); - } - - /// - /// Copies the properties from the other . - /// - /// - /// The other to copy the properties from. - /// - private void CopyProperties(IImage other) - { - this.MetaData = new ImageMetaData(other.MetaData); } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessorExtensions.cs b/src/ImageSharp/Image/PixelAccessorExtensions.cs new file mode 100644 index 0000000000..3c90a55c99 --- /dev/null +++ b/src/ImageSharp/Image/PixelAccessorExtensions.cs @@ -0,0 +1,36 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using Unsafe = System.Runtime.CompilerServices.Unsafe; + +namespace SixLabors.ImageSharp +{ + /// + /// Helper methods fro acccess pixel accessors + /// + internal static class PixelAccessorExtensions + { + /// + /// Locks the image providing access to the pixels. + /// + /// It is imperative that the accessor is correctly disposed off after use. + /// + /// + /// The type of the pixel. + /// The frame. + /// + /// The + /// + internal static PixelAccessor Lock(this IImageFrame frame) + where TPixel : struct, IPixel + { + return new PixelAccessor(frame); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index 90908529f5..0204c9e771 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -23,6 +23,7 @@ namespace SixLabors.ImageSharp /// The containing the pixel data. /// internal Buffer2D PixelBuffer; + private bool ownedBuffer; #pragma warning restore SA1401 // Fields must be private /// @@ -40,14 +41,15 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class. /// /// The image to provide pixel access for. - public PixelAccessor(ImageBase image) + public PixelAccessor(IImageFrame image) { Guard.NotNull(image, nameof(image)); Guard.MustBeGreaterThan(image.Width, 0, "image width"); Guard.MustBeGreaterThan(image.Height, 0, "image height"); - this.SetPixelBufferUnsafe(image.Width, image.Height, image.PixelBuffer); - this.ParallelOptions = image.Configuration.ParallelOptions; + this.SetPixelBufferUnsafe(image.PixelBuffer, false); + Configuration config = image.Parent?.Configuration ?? Configuration.Default; + this.ParallelOptions = config.ParallelOptions; } /// @@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp /// The width of the image represented by the pixel buffer. /// The height of the image represented by the pixel buffer. public PixelAccessor(int width, int height) - : this(width, height, Buffer2D.CreateClean(width, height)) + : this(width, height, Buffer2D.CreateClean(width, height), true) { } @@ -66,13 +68,14 @@ namespace SixLabors.ImageSharp /// The width of the image represented by the pixel buffer. /// The height of the image represented by the pixel buffer. /// The pixel buffer. - private PixelAccessor(int width, int height, Buffer2D pixels) + /// if set to true [owned buffer]. + private PixelAccessor(int width, int height, Buffer2D pixels, bool ownedBuffer) { Guard.NotNull(pixels, nameof(pixels)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - this.SetPixelBufferUnsafe(width, height, pixels); + this.SetPixelBufferUnsafe(pixels, ownedBuffer); this.ParallelOptions = Configuration.Default.ParallelOptions; } @@ -148,7 +151,7 @@ namespace SixLabors.ImageSharp /// public void Dispose() { - if (this.isDisposed) + if (this.isDisposed || !this.ownedBuffer) { return; } @@ -236,15 +239,13 @@ namespace SixLabors.ImageSharp /// /// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!! /// - /// The width. - /// The height. /// The pixels. /// Returns the old pixel data thats has gust been replaced. /// If is true then caller is responsible for ensuring is called. - internal TPixel[] ReturnCurrentColorsAndReplaceThemInternally(int width, int height, TPixel[] pixels) + internal Buffer2D SwapBufferOwnership(Buffer2D pixels) { - TPixel[] oldPixels = this.PixelBuffer.TakeArrayOwnership(); - this.SetPixelBufferUnsafe(width, height, pixels); + var oldPixels = this.PixelBuffer; + this.SetPixelBufferUnsafe(pixels, this.ownedBuffer); return oldPixels; } @@ -412,23 +413,17 @@ namespace SixLabors.ImageSharp } } - private void SetPixelBufferUnsafe(int width, int height, TPixel[] pixels) - { - this.SetPixelBufferUnsafe(width, height, new Buffer2D(pixels, width, height)); - } - /// /// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!! /// - /// The width. - /// The height. /// The pixel buffer - private void SetPixelBufferUnsafe(int width, int height, Buffer2D pixels) + private void SetPixelBufferUnsafe(Buffer2D pixels, bool ownedBuffer) { this.PixelBuffer = pixels; + this.ownedBuffer = ownedBuffer; - this.Width = width; - this.Height = height; + this.Width = pixels.Width; + this.Height = pixels.Height; this.PixelSize = Unsafe.SizeOf(); this.RowStride = this.Width * this.PixelSize; } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index c4aa98d319..4a2ca38077 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -48,13 +48,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { new GrayscaleBt709Processor().Apply(source, sourceRectangle); } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { float threshold = this.Threshold; TPixel upper = this.UpperColor; @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs index ba79d2a80e..d2a68094e4 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs @@ -54,13 +54,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { new GrayscaleBt709Processor().Apply(source, sourceRectangle); } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs index 2f76ecda57..c4499a3729 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs @@ -62,13 +62,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { new GrayscaleBt709Processor().Apply(source, sourceRectangle); } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index a1fa3c9cba..1279792dc4 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -29,10 +29,6 @@ namespace SixLabors.ImageSharp.Processing this.BeforeImageApply(source, clone, sourceRectangle); - this.BeforeApply(source, clone, sourceRectangle); - this.OnApply(source, clone, sourceRectangle); - this.AfterApply(source, clone, sourceRectangle); - for (int i = 0; i < source.Frames.Count; i++) { ImageFrame sourceFrame = source.Frames[i]; @@ -71,11 +67,7 @@ namespace SixLabors.ImageSharp.Processing throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } - source.SwapPixelsData(cloned); - for (int i = 0; i < source.Frames.Count; i++) - { - source.Frames[i].SwapPixelsData(cloned.Frames[i]); - } + source.SwapPixelsBuffers(cloned); } } @@ -110,12 +102,12 @@ namespace SixLabors.ImageSharp.Processing /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void BeforeApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle) + protected virtual void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) { } /// - /// Applies the process to the specified portion of the specified at the specified location + /// 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. @@ -123,7 +115,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The structure that specifies the portion of the image object to draw. /// - protected abstract void OnApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle); + protected abstract void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle); /// /// This method is called after the process is applied to prepare the processor. @@ -133,7 +125,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void AfterApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle) + protected virtual void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs index c4da8dee7d..b48da3a144 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public virtual bool Compand { get; set; } = true; /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs index dcb5955c00..5c702af211 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors }; /// - protected override void AfterApply(ImageBase source, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle) { new VignetteProcessor(VeryDarkGreen, this.options).Apply(source, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs index 928a641a00..78e25c147d 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors }; /// - protected override void AfterApply(ImageBase source, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle) { new VignetteProcessor(VeryDarkOrange, this.options).Apply(source, sourceRectangle); new GlowProcessor(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 3c95d29974..75d134137b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index d109cb10e8..37174c49da 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int kernelYHeight = this.KernelY.Height; int kernelYWidth = this.KernelY.Width; @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, endY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 08ea5a6412..d6efce35b3 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -39,11 +39,11 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int width = source.Width; int height = source.Height; - ParallelOptions parallelOptions = source.Configuration.ParallelOptions; + ParallelOptions parallelOptions = source.Configuration().ParallelOptions; using (var firstPassPixels = new PixelAccessor(width, height)) using (PixelAccessor sourcePixels = source.Lock()) @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - /// Applies the process to the specified portion of the specified at the specified location + /// Applies the process to the specified portion of the specified at the specified location /// and with the specified size. /// /// The target pixels to apply the process to. diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index fa1f18ea96..f2bc82f3b4 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelXY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int kernelLength = this.KernelXY.Height; int radius = kernelLength >> 1; @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, endY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs index af7a5e276e..3198ae0a28 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs @@ -40,13 +40,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Grayscale { get; set; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { if (this.Grayscale) { diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs index aa3c605355..86f33c345e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Grayscale { get; set; } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { if (this.Grayscale) { @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { Fast2DArray[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast }; @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors int maxY = Math.Min(source.Height, endY); // we need a clean copy for each pass to start from - using (ImageBase cleanCopy = source.Clone()) + using (ImageFrame cleanCopy = source.Clone()) { new ConvolutionProcessor(kernels[0]).Apply(source, sourceRectangle); @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Processing.Processors // ReSharper disable once ForCanBeConvertedToForeach for (int i = 1; i < kernels.Length; i++) { - using (ImageBase pass = cleanCopy.Clone()) + using (ImageFrame pass = cleanCopy.Clone()) { new ConvolutionProcessor(kernels[i]).Apply(pass, sourceRectangle); @@ -123,7 +123,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { int offsetY = y - shiftY; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs index b8e5106b7f..d43ee6d64d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelXY { get; } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { if (this.Grayscale) { @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { new ConvolutionProcessor(this.KernelXY).Apply(source, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index 583d38bf7f..2a1da29382 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index e22904ae1c..263abbdcf1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/DelegateProcessor.cs b/src/ImageSharp/Processing/Processors/DelegateProcessor.cs index e1bd8c5265..7fc70bd79c 100644 --- a/src/ImageSharp/Processing/Processors/DelegateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/DelegateProcessor.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { // NOP, we did all we wanted to do inside BeforeImageApply } diff --git a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs index 5cdf63210b..fbc5a15d77 100644 --- a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public float Value { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs index da3b78c3fb..9e4813f2b6 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel Value { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); diff --git a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs index 2c96ddb11e..8143d662e4 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Value { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { float brightness = this.Value / 100F; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs index d4ec49fd11..545363e271 100644 --- a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Value { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { float contrast = (100F + this.Value) / 100F; @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs index 35443fdd51..3fe179cd80 100644 --- a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors where TPixel : struct, IPixel { /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index ab55885560..88b4a2babe 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int BrushSize { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) { @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index a7513d1cbf..64522b67e5 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Size { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width) { @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.ForEach( range, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { int offsetY = y - startY; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 1a4d52d3ed..ed1ec1c294 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing /// /// the source image /// the target - public void Apply(ImageBase source, Rectangle sourceRectangle) + public void Apply(ImageFrame source, Rectangle sourceRectangle) { try { @@ -91,19 +91,19 @@ namespace SixLabors.ImageSharp.Processing /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected virtual void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { } /// - /// Applies the process to the specified portion of the specified at the specified location + /// 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. /// - protected abstract void OnApply(ImageBase source, Rectangle sourceRectangle); + protected abstract void OnApply(ImageFrame source, Rectangle sourceRectangle); /// /// This method is called after the process is applied to prepare the processor. @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The structure that specifies the portion of the image object to draw. /// - protected virtual void AfterApply(ImageBase source, Rectangle sourceRectangle) + protected virtual void AfterApply(ImageFrame source, Rectangle sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 47ca3b1357..eeb9ae8e88 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public ValueSize Radius { get; set; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { using (var amounts = new Buffer(width)) diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index bad6cbf419..7d3da8c89c 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public ValueSize RadiusY { get; set; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { using (var amounts = new Buffer(width)) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs index 76271529d7..a84a7b189b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void OnApply(ImageBase sourceBase, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame sourceBase, Rectangle sourceRectangle) { // can only apply to the origional image var source = sourceBase as Image; diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 1d0ab6d1f1..4228bb34bd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Rectangle CropRectangle { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { if (this.CropRectangle == sourceRectangle) { @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y).Slice(minX); diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index 89e22a7e6b..7ca7008a30 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -34,9 +34,9 @@ namespace SixLabors.ImageSharp.Processing.Processors public float Threshold { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { - using (ImageBase temp = source.Clone()) + using (ImageFrame temp = source.Clone()) { // Detect the edges. new SobelProcessor().Apply(temp, sourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index 1cb92cca90..17ce08318a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public FlipType FlipType { get; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { switch (this.FlipType) { @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// at half the height of the image. /// /// The source image to apply the process to. - private void FlipX(ImageBase source) + private void FlipX(ImageFrame source) { int width = source.Width; int height = source.Height; @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, halfHeight, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { int newY = height - y - 1; @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// at half of the width of the image. /// /// The source image to apply the process to. - private void FlipY(ImageBase source) + private void FlipY(ImageFrame source) { int width = source.Width; int height = source.Height; @@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs index 54724ee782..4a15254ab2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Matrix3x2Processor.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// The . /// - protected Matrix3x2 GetCenteredMatrix(ImageBase source, Matrix3x2 matrix) + protected Matrix3x2 GetCenteredMatrix(ImageFrame source, Matrix3x2 matrix) { var translationToTargetCenter = Matrix3x2.CreateTranslation(-this.CanvasRectangle.Width * .5F, -this.CanvasRectangle.Height * .5F); var translateToSourceCenter = Matrix3x2.CreateTranslation(source.Width * .5F, source.Height * .5F); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs index 8d5eeded15..708d7a273f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) { if (!(this.Sampler is NearestNeighborResampler)) { @@ -152,7 +152,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void AfterApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) { base.AfterApply(source, destination, sourceRectangle); this.HorizontalWeights?.Dispose(); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 57b9a81f90..a56afd4509 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Linq; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; @@ -55,20 +56,14 @@ namespace SixLabors.ImageSharp.Processing.Processors // ------------ // For resize we know we are going to populate every pixel with fresh data and we want a different target size so // let's manually clone an empty set of images at the correct target and then have the base class processs them in turn. - var image = new Image(source.Configuration, this.Width, this.Height, source.MetaData.Clone()); - - // Now 'clone' the ImageFrames - foreach (ImageFrame sourceFrame in source.Frames) - { - var targetFrame = new ImageFrame(sourceFrame.Configuration, this.Width, this.Height, sourceFrame.MetaData.Clone()); - image.Frames.Add(targetFrame); - } + var frames = source.Frames.Select(x => new ImageFrame(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders + var image = new Image(source.Configuration, this.Width, this.Height, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added return image; } /// - protected override unsafe void OnApply(ImageBase source, ImageBase cloned, Rectangle sourceRectangle) + protected override unsafe void OnApply(ImageFrame source, ImageFrame cloned, Rectangle sourceRectangle) { // Jump out, we'll deal with that later. if (source.Width == cloned.Width && source.Height == cloned.Height && sourceRectangle == this.ResizeRectangle) @@ -101,7 +96,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { // Y coordinates of source points @@ -130,7 +125,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, sourceRectangle.Bottom, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { // TODO: Without Parallel.For() this buffer object could be reused: @@ -163,7 +158,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { // Ensure offsets are normalised for cropping and padding. diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 5b8952dc8a..be865be0a9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Expand { get; set; } = true; /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { if (this.OptimizedApply(source)) { @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span targetRow = targetPixels.GetRowSpan(y); @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon) { @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// /// The source image. /// The - private bool OptimizedApply(ImageBase source) + private bool OptimizedApply(ImageFrame source) { if (MathF.Abs(this.Angle) < Constants.Epsilon) { @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 270 degrees clockwise at the centre point. /// /// The source image. - private void Rotate270(ImageBase source) + private void Rotate270(ImageFrame source) { int width = source.Width; int height = source.Height; @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { for (int x = 0; x < width; x++) @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 180 degrees clockwise at the centre point. /// /// The source image. - private void Rotate180(ImageBase source) + private void Rotate180(ImageFrame source) { int width = source.Width; int height = source.Height; @@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 90 degrees clockwise at the centre point. /// /// The source image. - private void Rotate90(ImageBase source) + private void Rotate90(ImageFrame source) { int width = source.Width; int height = source.Height; @@ -197,7 +197,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index 85bf1b6938..5d4578e8c1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Expand { get; set; } = true; /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int height = this.CanvasRectangle.Height; int width = this.CanvasRectangle.Width; @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { Span targetRow = targetPixels.GetRowSpan(y); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) { this.processMatrix = Matrix3x2Extensions.CreateSkewDegrees(-this.AngleX, -this.AngleY, new Point(0, 0)); if (this.Expand) diff --git a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs index 90f50ec3dc..152b451e29 100644 --- a/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs +++ b/src/ImageSharp/Processing/Transforms/Options/ResizeHelper.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - public static Rectangle CalculateTargetLocationAndBounds(ImageBase source, ResizeOptions options) + public static Rectangle CalculateTargetLocationAndBounds(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { switch (options.Mode) @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - private static Rectangle CalculateCropRectangle(ImageBase source, ResizeOptions options) + private static Rectangle CalculateCropRectangle(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { int width = options.Size.Width; @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - private static Rectangle CalculatePadRectangle(ImageBase source, ResizeOptions options) + private static Rectangle CalculatePadRectangle(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { int width = options.Size.Width; @@ -253,7 +253,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - private static Rectangle CalculateBoxPadRectangle(ImageBase source, ResizeOptions options) + private static Rectangle CalculateBoxPadRectangle(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { int width = options.Size.Width; @@ -340,7 +340,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - private static Rectangle CalculateMaxRectangle(ImageBase source, ResizeOptions options) + private static Rectangle CalculateMaxRectangle(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { int width = options.Size.Width; @@ -381,7 +381,7 @@ namespace SixLabors.ImageSharp.Processing /// /// The . /// - private static Rectangle CalculateMinRectangle(ImageBase source, ResizeOptions options) + private static Rectangle CalculateMinRectangle(ImageFrame source, ResizeOptions options) where TPixel : struct, IPixel { int width = options.Size.Width; diff --git a/src/ImageSharp/Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs index dc23eb4fba..826741d94e 100644 --- a/src/ImageSharp/Processing/Transforms/Resize.cs +++ b/src/ImageSharp/Processing/Transforms/Resize.cs @@ -38,14 +38,14 @@ namespace SixLabors.ImageSharp options.Size = new Size(options.Size.Width, (int)MathF.Round(img.Height * options.Size.Width / (float)img.Width)); } - Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img, options); + Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img, options); img.Mutate(x => Resize(x, options.Size.Width, options.Size.Height, options.Sampler, targetRectangle, options.Compand)); }); } /// - /// Resizes an image to the given . + /// Resizes an image to the given . /// /// The pixel format. /// The image to resize. @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp } /// - /// Resizes an image to the given . + /// Resizes an image to the given . /// /// The pixel format. /// The image to resize. diff --git a/src/ImageSharp/Quantizers/IQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/IQuantizer{TPixel}.cs index 1e992c894d..82f6146a3e 100644 --- a/src/ImageSharp/Quantizers/IQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/IQuantizer{TPixel}.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Quantizers /// /// A representing a quantized version of the image pixels. /// - QuantizedImage Quantize(ImageBase image, int maxColors); + QuantizedImage Quantize(ImageFrame image, int maxColors); } /// diff --git a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs index 77771c792c..49adce23b3 100644 --- a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Quantizers } /// - public override QuantizedImage Quantize(ImageBase image, int maxColors) + public override QuantizedImage Quantize(ImageFrame image, int maxColors) { this.colors = (byte)maxColors.Clamp(1, 255); this.octree = new Octree(this.GetBitsNeededForColorDepth(this.colors)); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Quantizers } /// - protected override void SecondPass(ImageBase source, byte[] output, int width, int height) + protected override void SecondPass(ImageFrame source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color. diff --git a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs index 545004bc2f..ca11a042fb 100644 --- a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs @@ -55,14 +55,14 @@ namespace SixLabors.ImageSharp.Quantizers } /// - public override QuantizedImage Quantize(ImageBase image, int maxColors) + public override QuantizedImage Quantize(ImageFrame image, int maxColors) { Array.Resize(ref this.colors, maxColors.Clamp(1, 255)); return base.Quantize(image, maxColors); } /// - protected override void SecondPass(ImageBase source, byte[] output, int width, int height) + protected override void SecondPass(ImageFrame source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color. diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index ad166f6065..26d37615bf 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp } }); - img.SwapPixelsBuffers(pixels); + img.Frames[0].SwapPixelsBuffers(pixels); } }); } diff --git a/src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs b/src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs index 48c4df5e42..7f58ff1bf5 100644 --- a/src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs +++ b/src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base public IErrorDiffuser DitherType { get; set; } = new SierraLiteDiffuser(); /// - public virtual QuantizedImage Quantize(ImageBase image, int maxColors) + public virtual QuantizedImage Quantize(ImageFrame image, int maxColors) { Guard.NotNull(image, nameof(image)); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base if (this.Dither) { // We clone the image as we don't want to alter the original. - using (ImageBase clone = image.Clone()) + using (ImageFrame clone = image.Clone()) { this.SecondPass(clone, quantizedPixels, width, height); } @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base /// The source data /// The width in pixels of the image. /// The height in pixels of the image. - protected virtual void FirstPass(ImageBase source, int width, int height) + protected virtual void FirstPass(ImageFrame source, int width, int height) { // Loop through each row for (int y = 0; y < height; y++) @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base /// The output pixel array /// The width in pixels of the image /// The height in pixels of the image - protected abstract void SecondPass(ImageBase source, byte[] output, int width, int height); + protected abstract void SecondPass(ImageFrame source, byte[] output, int width, int height); /// /// Override this to process the pixel in the first pass of the algorithm diff --git a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs index 5955ec9894..77c421468d 100644 --- a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Quantizers } /// - public override QuantizedImage Quantize(ImageBase image, int maxColors) + public override QuantizedImage Quantize(ImageFrame image, int maxColors) { Guard.NotNull(image, nameof(image)); @@ -221,7 +221,7 @@ namespace SixLabors.ImageSharp.Quantizers } /// - protected override void FirstPass(ImageBase source, int width, int height) + protected override void FirstPass(ImageFrame source, int width, int height) { // Build up the 3-D color histogram // Loop through each row @@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Quantizers } /// - protected override void SecondPass(ImageBase source, byte[] output, int width, int height) + protected override void SecondPass(ImageFrame source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color. diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 1530905c7e..64eb9e8b5d 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Benchmarks public float Radius { get; set; } /// - protected override void OnApply(ImageBase source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -112,7 +112,7 @@ namespace SixLabors.ImageSharp.Benchmarks Parallel.For( minY, maxY, - source.Configuration.ParallelOptions, + source.Configuration().ParallelOptions, y => { int offsetY = y - startY; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 3fe7fe007e..521d30fd9d 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -12,8 +12,8 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison public static ExactImageComparer Instance { get; } = new ExactImageComparer(); public override ImageSimilarityReport CompareImagesOrFrames( - ImageBase expected, - ImageBase actual) + ImageFrame expected, + ImageFrame actual) { if (expected.Size() != actual.Size()) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index 4fabd60761..effebdecf6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -23,13 +23,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } public abstract ImageSimilarityReport CompareImagesOrFrames( - ImageBase expected, - ImageBase actual) + ImageFrame expected, + ImageFrame actual) where TPixelA : struct, IPixel where TPixelB : struct, IPixel; } public static class ImageComparerExtensions { + public static ImageSimilarityReport CompareImagesOrFrames( + this ImageComparer comparer, + Image expected, + Image actual) + where TPixelA : struct, IPixel where TPixelB : struct, IPixel + { + return comparer.CompareImagesOrFrames((ImageFrame)expected, (ImageFrame)actual); + } + public static IEnumerable CompareImages( this ImageComparer comparer, Image expected, @@ -37,12 +46,6 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison where TPixelA : struct, IPixel where TPixelB : struct, IPixel { var result = new List(); - ImageSimilarityReport report = comparer.CompareImagesOrFrames(expected, actual); - - if (!report.IsEmpty) - { - result.Add(report); - } if (expected.Frames.Count != actual.Frames.Count) { @@ -50,12 +53,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } for (int i = 0; i < expected.Frames.Count; i++) { - report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]); + ImageSimilarityReport report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]); if (!report.IsEmpty) { result.Add(report); } } + return result; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs index 8a992b17d3..aa61c7f5ac 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs @@ -8,8 +8,8 @@ public class ImageSimilarityReport { public ImageSimilarityReport( - IImageBase expectedImage, - IImageBase actualImage, + IImageFrame expectedImage, + IImageFrame actualImage, IEnumerable differences, float? totalNormalizedDifference = null) { @@ -29,9 +29,9 @@ ? $"{this.TotalNormalizedDifference.Value * 100:0.0000}%" : "?"; - public IImageBase ExpectedImage { get; } + public IImageFrame ExpectedImage { get; } - public IImageBase ActualImage { get; } + public IImageFrame ActualImage { get; } public PixelDifference[] Differences { get; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index ab0ab287de..9688262d0a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -45,7 +45,7 @@ /// public int PerPixelManhattanThreshold { get; } - public override ImageSimilarityReport CompareImagesOrFrames(ImageBase expected, ImageBase actual) + public override ImageSimilarityReport CompareImagesOrFrames(ImageFrame expected, ImageFrame actual) { if (expected.Size() != actual.Size()) { diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 1b3ebf016a..f4faa94565 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Tests /// The name of the test case (by default) /// public string TestName { get; set; } = string.Empty; - + private string GetTestOutputFileNameImpl(string extension, string details, bool appendPixelTypeToFileName) { string fn = string.Empty; @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Tests { string path = this.GetTestOutputFileName(extension, testOutputDetails, appendPixelTypeToFileName); encoder = encoder ?? TestEnvironment.GetReferenceEncoder(path); - + using (FileStream stream = File.OpenWrite(path)) { image.Save(stream, encoder); @@ -187,7 +187,7 @@ namespace SixLabors.ImageSharp.Tests // pngEncoder.PngColorType = PngColorType.Grayscale; // } // } - + // return encoder; //} @@ -197,8 +197,14 @@ namespace SixLabors.ImageSharp.Tests return TestEnvironment.CreateOutputDirectory(testGroupName); } - public static void ModifyPixel(ImageBase img, int x, int y, byte perChannelChange) + public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel + { + ModifyPixel((ImageFrame)img, x, y, perChannelChange); + } + + public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) + where TPixel : struct, IPixel { TPixel pixel = img[x, y]; var rgbaPixel = default(Rgba32); From d8a821141752ac7f8e53f51cea2e0a22167bd566 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 5 Sep 2017 21:07:14 +0100 Subject: [PATCH 02/24] fix frame double processing moved some extensions into new namespace --- .../Processors/DrawImageProcessor.cs | 2 + .../Processors/FillProcessor.cs | 6 +- src/ImageSharp/Advanced/ImageExtensions.cs | 37 +++++- src/ImageSharp/ApplyProcessors.cs | 9 +- .../DefaultInternalImageProcessorContext.cs | 1 + src/ImageSharp/Formats/Bmp/ImageExtensions.cs | 3 +- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 3 +- .../Common/Decoder/JpegImagePostProcessor.cs | 1 + .../Formats/Jpeg/ImageExtensions.cs | 3 +- src/ImageSharp/Formats/Png/ImageExtensions.cs | 3 +- src/ImageSharp/Helpers/ImageExtensions.cs | 63 ++++++++++ src/ImageSharp/Image/ImageExtensions.cs | 108 +++++++++--------- .../Image/ImageFrame.LoadPixelData.cs | 54 +++++++++ src/ImageSharp/Image/ImageFrameCollection.cs | 23 +++- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 19 +-- src/ImageSharp/Image/Image{TPixel}.cs | 21 ++-- src/ImageSharp/Image/PixelAccessor{TPixel}.cs | 3 +- .../ErrorDiffusionDitherProcessor.cs | 1 + .../Binarization/OrderedDitherProcessor.cs | 1 + .../Convolution/Convolution2PassProcessor.cs | 2 + .../EdgeDetectorCompassProcessor.cs | 1 + .../Processing/Processors/ImageProcessor.cs | 4 - .../Processors/Overlays/GlowProcessor.cs | 1 + .../Processors/Overlays/VignetteProcessor.cs | 1 + .../Processors/Transforms/ResizeProcessor.cs | 3 +- .../Processors/Transforms/RotateProcessor.cs | 1 + .../Processors/Transforms/SkewProcessor.cs | 2 + src/ImageSharp/Quantizers/Quantize.cs | 3 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 6 +- .../Image/ImageRotationTests.cs | 5 +- .../Processors/Transforms/ResizeTests.cs | 1 + tests/ImageSharp.Tests/TestFile.cs | 3 +- .../ImageComparison/ExactImageComparer.cs | 1 + .../ImageComparison/ImageComparer.cs | 2 +- .../ImageComparison/TolerantImageComparer.cs | 1 + 35 files changed, 283 insertions(+), 115 deletions(-) create mode 100644 src/ImageSharp/Helpers/ImageExtensions.cs create mode 100644 src/ImageSharp/Image/ImageFrame.LoadPixelData.cs diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs index 2a8e2cf4ca..25eddaf0bb 100644 --- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs @@ -4,6 +4,8 @@ using System; using System.Numerics; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index 57c4e3d9b8..3c0883d666 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Drawing; using SixLabors.ImageSharp.Drawing.Brushes; using SixLabors.ImageSharp.Drawing.Brushes.Processors; @@ -64,10 +65,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors } int width = maxX - minX; - - // We could possibly do some optimization by having knowledge about the individual brushes operate - // for example If brush is SolidBrush then we could just get the color upfront - // and skip using the IBrushApplicator?. + using (var amount = new Buffer(width)) using (BrushApplicator applicator = this.brush.CreateApplicator(source, sourceRectangle, this.options)) { diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index 1bd7c0cc4d..d3d563fae2 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.Advanced /// The public static Span GetPixelRowSpan(this ImageFrame source, int row) where TPixel : struct, IPixel - => GetSpan(source).Slice(row * source.Width, source.Width); + => GetSpan(source, row); /// /// Gets a representing the row 'y' beginning from the the first pixel on that row. @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Advanced /// The public static Span GetPixelRowSpan(this Image source, int row) where TPixel : struct, IPixel - => GetSpan(source).Slice(row * source.Width, source.Width); + => GetSpan(source, row); /// /// Gets the span. @@ -67,5 +67,38 @@ namespace SixLabors.ImageSharp.Advanced private static Span GetSpan(IImageFrame source) where TPixel : struct, IPixel => source.PixelBuffer.Span; + + /// + /// Gets the span. + /// + /// The type of the pixel. + /// The source. + /// The row. + /// + /// The span retuned from Pixel source + /// + private static Span GetSpan(IImageFrame source, int row) + where TPixel : struct, IPixel + => source.PixelBuffer.Span.Slice(row * source.Width, source.Width); + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Configuration Configuration(this ImageFrame source) + where TPixel : struct, IPixel + => source?.Parent?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default; + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Configuration Configuration(this Image source) + where TPixel : struct, IPixel + => source?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default; } } diff --git a/src/ImageSharp/ApplyProcessors.cs b/src/ImageSharp/ApplyProcessors.cs index 1788332755..3184bc592b 100644 --- a/src/ImageSharp/ApplyProcessors.cs +++ b/src/ImageSharp/ApplyProcessors.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; @@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operation, nameof(operation)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, true); operation(operationsRunner); operationsRunner.Apply(); } @@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operations, nameof(operations)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, true); operationsRunner.ApplyProcessors(operations); operationsRunner.Apply(); } @@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operation, nameof(operation)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, false); operation(operationsRunner); return operationsRunner.Apply(); } @@ -77,7 +78,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operations, nameof(operations)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, false); operationsRunner.ApplyProcessors(operations); return operationsRunner.Apply(); } diff --git a/src/ImageSharp/DefaultInternalImageProcessorContext.cs b/src/ImageSharp/DefaultInternalImageProcessorContext.cs index 8eb1c09fee..2e2602d3c0 100644 --- a/src/ImageSharp/DefaultInternalImageProcessorContext.cs +++ b/src/ImageSharp/DefaultInternalImageProcessorContext.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.Primitives; diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs index 558ce69c55..3bcbed49ad 100644 --- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.PixelFormats; @@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Bmp)); + => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Bmp)); } } diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index b5f358f583..8174ec6f47 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; @@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Gif)); + => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Gif)); } } diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs index 52fc1c2286..e3ca1d74c2 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs @@ -2,6 +2,7 @@ using System; using System.Linq; using System.Numerics; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index c7d7b26da6..bc87b3a1bd 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -3,6 +3,7 @@ using System; using System.IO; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; @@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Jpeg)); + => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Jpeg)); } } diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index 5d7539915c..e237d6a4e1 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.IO; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; @@ -34,6 +35,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Png)); + => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Png)); } } diff --git a/src/ImageSharp/Helpers/ImageExtensions.cs b/src/ImageSharp/Helpers/ImageExtensions.cs new file mode 100644 index 0000000000..9f3d293326 --- /dev/null +++ b/src/ImageSharp/Helpers/ImageExtensions.cs @@ -0,0 +1,63 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Text; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Helpers +{ + /// + /// Extension methods over Image{TPixel} + /// + public static partial class ImageExtensions + { + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Rectangle Bounds(this Image source) + where TPixel : struct, IPixel + => new Rectangle(0, 0, source.Width, source.Height); + + /// + /// Gets the bounds of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Rectangle Bounds(this ImageFrame source) + where TPixel : struct, IPixel + => new Rectangle(0, 0, source.Width, source.Height); + + /// + /// Gets the size of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Size Size(this Image source) + where TPixel : struct, IPixel + => new Size(source.Width, source.Height); + + /// + /// Gets the size of the image. + /// + /// The Pixel format. + /// The source image + /// Returns the bounds of the image + public static Size Size(this ImageFrame source) + where TPixel : struct, IPixel + => new Size(source.Width, source.Height); + + } +} diff --git a/src/ImageSharp/Image/ImageExtensions.cs b/src/ImageSharp/Image/ImageExtensions.cs index 9c7b0962ea..8e78de0563 100644 --- a/src/ImageSharp/Image/ImageExtensions.cs +++ b/src/ImageSharp/Image/ImageExtensions.cs @@ -18,56 +18,6 @@ namespace SixLabors.ImageSharp /// public static partial class ImageExtensions { - /// - /// Gets the bounds of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Configuration Configuration(this ImageFrame source) - where TPixel : struct, IPixel - => source.Parent?.Configuration ?? SixLabors.ImageSharp.Configuration.Default; - - /// - /// Gets the bounds of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Rectangle Bounds(this Image source) - where TPixel : struct, IPixel - => new Rectangle(0, 0, source.Width, source.Height); - - /// - /// Gets the bounds of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Rectangle Bounds(this ImageFrame source) - where TPixel : struct, IPixel - => new Rectangle(0, 0, source.Width, source.Height); - - /// - /// Gets the size of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Size Size(this Image source) - where TPixel : struct, IPixel - => new Size(source.Width, source.Height); - - /// - /// Gets the size of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Size Size(this ImageFrame source) - where TPixel : struct, IPixel - => new Size(source.Width, source.Height); - #if !NETSTANDARD1_1 /// /// Saves the image to the given stream using the currently loaded image format. @@ -82,12 +32,12 @@ namespace SixLabors.ImageSharp Guard.NotNullOrEmpty(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath).Trim('.'); - IImageFormat format = source.Configuration.FindFormatByFileExtension(ext); + IImageFormat format = source.Configuration().FindFormatByFileExtension(ext); if (format == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); - foreach (IImageFormat fmt in source.Configuration.ImageFormats) + foreach (IImageFormat fmt in source.Configuration().ImageFormats) { stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); } @@ -95,13 +45,13 @@ namespace SixLabors.ImageSharp throw new NotSupportedException(stringBuilder.ToString()); } - IImageEncoder encoder = source.Configuration.FindEncoder(format); + IImageEncoder encoder = source.Configuration().FindEncoder(format); if (encoder == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); - foreach (KeyValuePair enc in source.Configuration.ImageEncoders) + foreach (KeyValuePair enc in source.Configuration().ImageEncoders) { stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); } @@ -124,7 +74,7 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { Guard.NotNull(encoder, nameof(encoder)); - using (Stream fs = source.Configuration.FileSystem.Create(filePath)) + using (Stream fs = source.Configuration().FileSystem.Create(filePath)) { source.Save(fs, encoder); } @@ -143,14 +93,14 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { Guard.NotNull(format, nameof(format)); - IImageEncoder encoder = source.Configuration.FindEncoder(format); + IImageEncoder encoder = source.Configuration().FindEncoder(format); if (encoder == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - foreach (KeyValuePair val in source.Configuration.ImageEncoders) + foreach (KeyValuePair val in source.Configuration().ImageEncoders) { stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } @@ -161,6 +111,28 @@ namespace SixLabors.ImageSharp source.Save(stream, encoder); } + /// + /// Saves the raw image to the given bytes. + /// + /// The Pixel format. + /// The source image + /// A copy of the pixel data as bytes from this frame. + /// Thrown if the stream is null. + public static byte[] SavePixelData(this ImageFrame source) + where TPixel : struct, IPixel + => source.GetPixelSpan().AsBytes().ToArray(); + + /// + /// Saves the raw image to the given bytes. + /// + /// The Pixel format. + /// The source image + /// The buffer to save the raw pixel data to. + /// Thrown if the stream is null. + public static void SavePixelData(this ImageFrame source, byte[] buffer) + where TPixel : struct, IPixel + => SavePixelData(source, new Span(buffer)); + /// /// Saves the raw image to the given bytes. /// @@ -177,6 +149,28 @@ namespace SixLabors.ImageSharp byteBuffer.CopyTo(buffer); } + /// + /// Saves the raw image to the given bytes. + /// + /// The Pixel format. + /// The source image + /// A copy of the pixel data from the first frame as bytes. + /// Thrown if the stream is null. + public static byte[] SavePixelData(this Image source) + where TPixel : struct, IPixel + => source.GetPixelSpan().AsBytes().ToArray(); + + /// + /// Saves the raw image to the given bytes. + /// + /// The Pixel format. + /// The source image + /// The buffer to save the raw pixel data to. + /// Thrown if the stream is null. + public static void SavePixelData(this Image source, byte[] buffer) + where TPixel : struct, IPixel + => SavePixelData(source, new Span(buffer)); + /// /// Saves the raw image to the given bytes. /// diff --git a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs new file mode 100644 index 0000000000..3f63b9c648 --- /dev/null +++ b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs @@ -0,0 +1,54 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp +{ + /// + /// Adds static methods allowing the creation of new image from raw pixel data. + /// + public static partial class ImageFrame + { + /// + /// Create a new instance of the class from the given byte array in format. + /// + /// The config for the decoder. + /// The byte array containing image data. + /// The width of the final image. + /// The height of the final image. + /// The pixel format. + /// A new . + public static ImageFrame LoadPixelData(Span data, int width, int height) + where TPixel : struct, IPixel + => LoadPixelData(data.NonPortableCast(), width, height); + + /// + /// Create a new instance of the class from the raw data. + /// + /// The config for the decoder. + /// The Span containing the image Pixel data. + /// The width of the final image. + /// The height of the final image. + /// The pixel format. + /// A new . + public static ImageFrame LoadPixelData(Span data, int width, int height) + where TPixel : struct, IPixel + { + int count = width * height; + Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); + + var image = new ImageFrame(width, height); + SpanHelper.Copy(data, image.GetPixelSpan(), count); + + return image; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index 186f94762e..92e068ec8f 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -37,6 +37,22 @@ namespace SixLabors.ImageSharp /// public int Count { get => this.frames.Count; } + /// + /// Gets the root frame. + /// + public ImageFrame RootFrame + { + get + { + if (this.frames.Count > 0) + { + return this.frames[0]; + } + + return null; + } + } + /// /// Gets or sets the at the specified index. /// @@ -105,9 +121,12 @@ namespace SixLabors.ImageSharp private void ValidateFrameSize(ImageFrame frame) { - if (this.parent.Width != frame.Width || this.parent.Height != frame.Height) + if (this.Count != 0) { - throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); + if (this.parent.Width != frame.Width || this.parent.Height != frame.Height) + { + throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); + } } } diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index cc5c8b1ac9..9d6b945abd 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -49,8 +49,6 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metaData, nameof(metaData)); - this.Width = width; - this.Height = height; this.pixelBuffer = Buffer2D.CreateClean(width, height); this.MetaData = metaData; } @@ -61,9 +59,7 @@ namespace SixLabors.ImageSharp /// The source. internal ImageFrame(ImageFrame source) { - this.Width = source.Width; - this.Height = source.Height; - this.pixelBuffer = new Buffer2D(source.Width, source.Height); + this.pixelBuffer = new Buffer2D(source.pixelBuffer.Width, source.pixelBuffer.Height); source.pixelBuffer.Span.CopyTo(this.pixelBuffer.Span); this.MetaData = source.MetaData.Clone(); } @@ -72,10 +68,10 @@ namespace SixLabors.ImageSharp Buffer2D IImageFrame.PixelBuffer => this.pixelBuffer; /// - public int Width { get; private set; } + public int Width => this.pixelBuffer.Width; /// - public int Height { get; private set; } + public int Height => this.pixelBuffer.Height; /// /// Gets the configuration providing initialization code which allows extending the library. @@ -158,13 +154,8 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - int newWidth = pixelSource.Width; - int newHeight = pixelSource.Height; - // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use) var newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer); - this.Width = newWidth; - this.Height = newHeight; this.pixelBuffer = newPixels; } @@ -181,11 +172,7 @@ namespace SixLabors.ImageSharp var newPixels = pixelSource.pixelBuffer; pixelSource.pixelBuffer = this.pixelBuffer; - pixelSource.Width = this.Width; - pixelSource.Height = this.Height; - this.Width = newWidth; - this.Height = newHeight; this.pixelBuffer = newPixels; } diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 94d6ddb6ab..ce8a6f7211 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -75,8 +75,6 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - this.Width = pixelSource.Width; - this.Height = pixelSource.Height; int newHeight = pixelSource.Height; for (int i = 0; i < this.Frames.Count; i++) @@ -85,7 +83,6 @@ namespace SixLabors.ImageSharp } } - /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -97,9 +94,7 @@ namespace SixLabors.ImageSharp /// The frames that will be owned by this image instance. internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable> frames) { - this.Configuration = configuration ?? Configuration.Default; - this.Width = width; - this.Height = height; + this.ImageConfiguration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); this.Frames = new ImageFrameCollection(this); @@ -114,7 +109,7 @@ namespace SixLabors.ImageSharp if (this.Frames.Count == 0) { - this.Frames.Add(new ImageFrame(this.Width, this.Height)); + this.Frames.Add(new ImageFrame(width, height)); } } @@ -124,17 +119,17 @@ namespace SixLabors.ImageSharp /// /// The configuration. /// - public Configuration Configuration { get; } + internal Configuration ImageConfiguration { get; } /// /// Gets the width. /// - public int Width { get; private set; } + public int Width => this.RootFrame?.Width ?? 0; /// /// Gets the height. /// - public int Height { get; private set; } + public int Height => this.RootFrame?.Height ?? 0; /// /// Gets the meta data of the image. @@ -149,7 +144,7 @@ namespace SixLabors.ImageSharp /// /// Gets the root frame. /// - private IImageFrame RootFrame => this.Frames[0]; + private IImageFrame RootFrame => this.Frames.RootFrame; /// Buffer2D IImageFrame.PixelBuffer => this.RootFrame.PixelBuffer; @@ -201,7 +196,7 @@ namespace SixLabors.ImageSharp { IEnumerable> frames = this.Frames.Select(x => x.Clone()).ToArray(); - return new Image(this.Configuration, this.Width, this.Height, this.MetaData.Clone(), frames); + return new Image(this.ImageConfiguration, this.Width, this.Height, this.MetaData.Clone(), frames); } /// @@ -219,7 +214,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> frames = this.Frames.Select(x => x.CloneAs()).ToArray(); - var target = new Image(this.Configuration, this.Width, this.Height, this.MetaData, frames); + var target = new Image(this.ImageConfiguration, this.Width, this.Height, this.MetaData, frames); return target; } diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index 0204c9e771..006429a17d 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Unsafe = System.Runtime.CompilerServices.Unsafe; @@ -48,7 +49,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(image.Height, 0, "image height"); this.SetPixelBufferUnsafe(image.PixelBuffer, false); - Configuration config = image.Parent?.Configuration ?? Configuration.Default; + Configuration config = image.Parent.Configuration(); this.ParallelOptions = config.ParallelOptions; } diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs index d2a68094e4..719a7ea34b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs @@ -4,6 +4,7 @@ using System; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Dithering; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs index c4499a3729..d8b132c6c5 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Buffers; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Dithering; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index d6efce35b3..1aeb37862c 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -4,6 +4,8 @@ using System; using System.Numerics; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs index 86f33c345e..bbe527eb70 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index ed1ec1c294..46f8f25257 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -22,10 +22,6 @@ namespace SixLabors.ImageSharp.Processing { this.BeforeImageApply(source, sourceRectangle); - this.BeforeApply(source, sourceRectangle); - this.OnApply(source, sourceRectangle); - this.AfterApply(source, sourceRectangle); - foreach (ImageFrame sourceFrame in source.Frames) { this.BeforeApply(sourceFrame, sourceRectangle); diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index eeb9ae8e88..d8a611c0fd 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 7d3da8c89c..c9bfc27cf0 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index a56afd4509..d50a68defb 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -52,12 +52,13 @@ namespace SixLabors.ImageSharp.Processing.Processors /// protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { + var config = source.Configuration(); // We will always be creating the clone even for mutate because thats the way this base processor works // ------------ // For resize we know we are going to populate every pixel with fresh data and we want a different target size so // let's manually clone an empty set of images at the correct target and then have the base class processs them in turn. var frames = source.Frames.Select(x => new ImageFrame(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders - var image = new Image(source.Configuration, this.Width, this.Height, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added + var image = new Image(config, this.Width, this.Height, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added return image; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index be865be0a9..43bf19d495 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index 5d4578e8c1..bafda41db7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -4,6 +4,8 @@ using System; using System.Numerics; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index 26d37615bf..d9c3c84cd2 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Quantizers; @@ -65,7 +66,7 @@ namespace SixLabors.ImageSharp Parallel.For( 0, pixels.Height, - img.Configuration.ParallelOptions, + img.Configuration().ParallelOptions, y => { for (int x = 0; x < pixels.Width; x++) diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 64eb9e8b5d..39a6e92119 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks using SixLabors.ImageSharp.Memory; using SixLabors.Primitives; + using SixLabors.ImageSharp.Helpers; + using SixLabors.ImageSharp.Advanced; public class Glow : BenchmarkBase { @@ -35,7 +37,7 @@ namespace SixLabors.ImageSharp.Benchmarks { using (Image image = new Image(800, 800)) { - bulk.Apply(image, image.Bounds()); + this.bulk.Apply(image, image.Bounds()); return new CoreSize(image.Width, image.Height); } } @@ -45,7 +47,7 @@ namespace SixLabors.ImageSharp.Benchmarks { using (Image image = new Image(800, 800)) { - parallel.Apply(image, image.Bounds()); + this.parallel.Apply(image, image.Bounds()); return new CoreSize(image.Width, image.Height); } } diff --git a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs index 0e7dc5917e..73c2f78f40 100644 --- a/tests/ImageSharp.Tests/Image/ImageRotationTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageRotationTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Helpers; using SixLabors.Primitives; using Xunit; @@ -48,9 +49,9 @@ namespace SixLabors.ImageSharp.Tests var file = TestFile.Create(TestImages.Bmp.Car); using (var image = Image.Load(file.FullPath)) { - Size original = image.Bounds().Size; + Size original = image.Size(); image.Mutate(x => x.Rotate(angle)); - return (original, image.Bounds().Size); + return (original, image.Size()); } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 99520d887e..820ca8356e 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index f56802e548..e77b95f9ee 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -145,7 +146,7 @@ namespace SixLabors.ImageSharp.Tests /// public Image CreateImage(IImageDecoder decoder) { - return ImageSharp.Image.Load(this.Image.Configuration, this.Bytes, decoder); + return ImageSharp.Image.Load(this.Image.Configuration(), this.Bytes, decoder); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 521d30fd9d..86c5994dbf 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -3,6 +3,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison using System; using System.Collections.Generic; using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index effebdecf6..8378db4e3c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; - +using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 9688262d0a..828c669d52 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Helpers; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; From 05bb7c2c18e6b1181003461a2cfac6cc918367a6 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 5 Sep 2017 21:23:44 +0100 Subject: [PATCH 03/24] fix stylecop issues --- .../Processors/FillProcessor.cs | 2 +- src/ImageSharp/Helpers/ImageExtensions.cs | 2 -- .../Image/ImageFrame.LoadPixelData.cs | 2 -- src/ImageSharp/Image/Image{TPixel}.cs | 32 +++++++++---------- src/ImageSharp/Image/PixelAccessor{TPixel}.cs | 1 + .../Processors/Transforms/ResizeProcessor.cs | 6 ++-- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index 3c0883d666..c6f11891b9 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors } int width = maxX - minX; - + using (var amount = new Buffer(width)) using (BrushApplicator applicator = this.brush.CreateApplicator(source, sourceRectangle, this.options)) { diff --git a/src/ImageSharp/Helpers/ImageExtensions.cs b/src/ImageSharp/Helpers/ImageExtensions.cs index 9f3d293326..dbf2e34a42 100644 --- a/src/ImageSharp/Helpers/ImageExtensions.cs +++ b/src/ImageSharp/Helpers/ImageExtensions.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.Helpers /// public static partial class ImageExtensions { - /// /// Gets the bounds of the image. /// @@ -58,6 +57,5 @@ namespace SixLabors.ImageSharp.Helpers public static Size Size(this ImageFrame source) where TPixel : struct, IPixel => new Size(source.Width, source.Height); - } } diff --git a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs index 3f63b9c648..aecd9bba9e 100644 --- a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs +++ b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs @@ -20,7 +20,6 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the given byte array in format. /// - /// The config for the decoder. /// The byte array containing image data. /// The width of the final image. /// The height of the final image. @@ -33,7 +32,6 @@ namespace SixLabors.ImageSharp /// /// Create a new instance of the class from the raw data. /// - /// The config for the decoder. /// The Span containing the image Pixel data. /// The width of the final image. /// The height of the final image. diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index ce8a6f7211..cfd28f05d6 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -67,22 +67,6 @@ namespace SixLabors.ImageSharp { } - /// - /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. - /// - /// The pixel source. - internal void SwapPixelsBuffers(Image pixelSource) - { - Guard.NotNull(pixelSource, nameof(pixelSource)); - - int newHeight = pixelSource.Height; - - for (int i = 0; i < this.Frames.Count; i++) - { - this.Frames[i].SwapPixelsBuffers(pixelSource.Frames[i]); - } - } - /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -229,5 +213,21 @@ namespace SixLabors.ImageSharp this.Frames[i].Dispose(); } } + + /// + /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. + /// + /// The pixel source. + internal void SwapPixelsBuffers(Image pixelSource) + { + Guard.NotNull(pixelSource, nameof(pixelSource)); + + int newHeight = pixelSource.Height; + + for (int i = 0; i < this.Frames.Count; i++) + { + this.Frames[i].SwapPixelsBuffers(pixelSource.Frames[i]); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index 006429a17d..bb5f427dfd 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -418,6 +418,7 @@ namespace SixLabors.ImageSharp /// Sets the pixel buffer in an unsafe manor this should not be used unless you know what its doing!!! /// /// The pixel buffer + /// if set to true then this instance ownes the buffer and thus should dispose of it afterwards. private void SetPixelBufferUnsafe(Buffer2D pixels, bool ownedBuffer) { this.PixelBuffer = pixels; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index d50a68defb..98b8e12897 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Threading.Tasks; @@ -52,12 +53,13 @@ namespace SixLabors.ImageSharp.Processing.Processors /// protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { - var config = source.Configuration(); + Configuration config = source.Configuration(); + // We will always be creating the clone even for mutate because thats the way this base processor works // ------------ // For resize we know we are going to populate every pixel with fresh data and we want a different target size so // let's manually clone an empty set of images at the correct target and then have the base class processs them in turn. - var frames = source.Frames.Select(x => new ImageFrame(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders var image = new Image(config, this.Width, this.Height, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added return image; From 48fbc4f8328b31a21906822fdca0f881b172d620 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Wed, 6 Sep 2017 10:46:39 +1000 Subject: [PATCH 04/24] Fix AutoOrientProcessor --- .../DefaultInternalImageProcessorContext.cs | 3 +- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 6 +- .../Processing/Processors/ImageProcessor.cs | 1 - .../Transforms/AutoOrientProcessor.cs | 103 ++++++++++++++++ .../Transforms/AutoRotateProcessor.cs | 110 ------------------ .../Processing/Transforms/AutoOrient.cs | 2 +- .../Processing/Transforms/AutoOrientTests.cs | 2 +- 7 files changed, 109 insertions(+), 118 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs diff --git a/src/ImageSharp/DefaultInternalImageProcessorContext.cs b/src/ImageSharp/DefaultInternalImageProcessorContext.cs index 2e2602d3c0..575525a773 100644 --- a/src/ImageSharp/DefaultInternalImageProcessorContext.cs +++ b/src/ImageSharp/DefaultInternalImageProcessorContext.cs @@ -54,8 +54,7 @@ namespace SixLabors.ImageSharp // This will only work if the first processor applied is the cloning one thus // realistically for this optermissation to work the resize must the first processor // applied any only up processors will take the douple data path. - var cloningImageProcessor = processor as ICloningImageProcessor; - if (cloningImageProcessor != null) + if (processor is ICloningImageProcessor cloningImageProcessor) { this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle); return this; diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index 9d6b945abd..063108515b 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(pixelSource, nameof(pixelSource)); // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use) - var newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer); + Buffer2D newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer); this.pixelBuffer = newPixels; } @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp int newWidth = pixelSource.Width; int newHeight = pixelSource.Height; - var newPixels = pixelSource.pixelBuffer; + Buffer2D newPixels = pixelSource.pixelBuffer; pixelSource.pixelBuffer = this.pixelBuffer; @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp { for (int x = 0; x < target.Width; x++) { - TPixel2 color = default(TPixel2); + var color = default(TPixel2); color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4())); targetPixels[x, y] = color; } diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 46f8f25257..26e0843059 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -25,7 +25,6 @@ namespace SixLabors.ImageSharp.Processing foreach (ImageFrame sourceFrame in source.Frames) { this.BeforeApply(sourceFrame, sourceRectangle); - this.OnApply(sourceFrame, sourceRectangle); this.AfterApply(sourceFrame, sourceRectangle); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs new file mode 100644 index 0000000000..f18d775f5e --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs @@ -0,0 +1,103 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +using SixLabors.ImageSharp.MetaData.Profiles.Exif; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors +{ + /// + /// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image. + /// + /// The pixel format. + internal class AutoOrientProcessor : ImageProcessor + where TPixel : struct, IPixel + { + /// + protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + { + Orientation orientation = GetExifOrientation(source); + + switch (orientation) + { + case Orientation.TopRight: + new FlipProcessor(FlipType.Horizontal).Apply(source, sourceRectangle); + break; + + case Orientation.BottomRight: + new RotateProcessor { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle); + break; + + case Orientation.BottomLeft: + new FlipProcessor(FlipType.Vertical).Apply(source, sourceRectangle); + break; + + case Orientation.LeftTop: + new RotateProcessor { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); + new FlipProcessor(FlipType.Horizontal).Apply(source, sourceRectangle); + break; + + case Orientation.RightTop: + new RotateProcessor { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); + break; + + case Orientation.RightBottom: + new FlipProcessor(FlipType.Vertical).Apply(source, sourceRectangle); + new RotateProcessor { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); + break; + + case Orientation.LeftBottom: + new RotateProcessor { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); + break; + + case Orientation.Unknown: + case Orientation.TopLeft: + default: + break; + } + } + + /// + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + { + // Nothing required here + } + + /// + /// Returns the current EXIF orientation + /// + /// The image to auto rotate. + /// The + private static Orientation GetExifOrientation(Image source) + { + if (source.MetaData.ExifProfile == null) + { + return Orientation.Unknown; + } + + ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation); + if (value == null) + { + return Orientation.Unknown; + } + + Orientation orientation; + if (value.DataType == ExifDataType.Short) + { + orientation = (Orientation)value.Value; + } + else + { + orientation = (Orientation)Convert.ToUInt16(value.Value); + source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation); + } + + source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); + + return orientation; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs deleted file mode 100644 index a84a7b189b..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.MetaData.Profiles.Exif; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors -{ - /// - /// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image. - /// - /// The pixel format. - internal class AutoRotateProcessor : ImageProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - public AutoRotateProcessor() - { - } - - /// - protected override void OnApply(ImageFrame sourceBase, Rectangle sourceRectangle) - { - // can only apply to the origional image - var source = sourceBase as Image; - if (source != null) - { - Orientation orientation = GetExifOrientation(source); - - switch (orientation) - { - case Orientation.TopRight: - new FlipProcessor(FlipType.Horizontal).Apply(source, sourceRectangle); - break; - - case Orientation.BottomRight: - new RotateProcessor() { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle); - break; - - case Orientation.BottomLeft: - new FlipProcessor(FlipType.Vertical).Apply(source, sourceRectangle); - break; - - case Orientation.LeftTop: - new RotateProcessor() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); - new FlipProcessor(FlipType.Horizontal).Apply(source, sourceRectangle); - break; - - case Orientation.RightTop: - new RotateProcessor() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle); - break; - - case Orientation.RightBottom: - new FlipProcessor(FlipType.Vertical).Apply(source, sourceRectangle); - new RotateProcessor() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); - break; - - case Orientation.LeftBottom: - new RotateProcessor() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle); - break; - - case Orientation.Unknown: - case Orientation.TopLeft: - default: - break; - } - } - } - - /// - /// Returns the current EXIF orientation - /// - /// The image to auto rotate. - /// The - private static Orientation GetExifOrientation(Image source) - { - if (source.MetaData.ExifProfile == null) - { - return Orientation.Unknown; - } - - ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation); - if (value == null) - { - return Orientation.Unknown; - } - - Orientation orientation; - if (value.DataType == ExifDataType.Short) - { - orientation = (Orientation)value.Value; - } - else - { - orientation = (Orientation)Convert.ToUInt16(value.Value); - source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation); - } - - source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); - - return orientation; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Transforms/AutoOrient.cs b/src/ImageSharp/Processing/Transforms/AutoOrient.cs index 186c3b2236..6e5a8829f2 100644 --- a/src/ImageSharp/Processing/Transforms/AutoOrient.cs +++ b/src/ImageSharp/Processing/Transforms/AutoOrient.cs @@ -20,6 +20,6 @@ namespace SixLabors.ImageSharp /// The public static IImageProcessingContext AutoOrient(this IImageProcessingContext source) where TPixel : struct, IPixel - => source.ApplyProcessor(new Processing.Processors.AutoRotateProcessor()); + => source.ApplyProcessor(new Processing.Processors.AutoOrientProcessor()); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs index dbb2d8415e..fd4c333d51 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms public void AutoOrient_AutoRotateProcessor() { this.operations.AutoOrient(); - this.Verify>(); + this.Verify>(); } } } \ No newline at end of file From 1b1359995ecb44cd64ba2429fa14317e651f0ec7 Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Wed, 6 Sep 2017 12:39:54 +1000 Subject: [PATCH 05/24] Remove Parent property --- src/ImageSharp/Image/IImageFrame.cs | 5 --- src/ImageSharp/Image/ImageFrameCollection.cs | 40 +++++-------------- src/ImageSharp/Image/Image{TPixel}.cs | 3 -- src/ImageSharp/Image/PixelAccessor{TPixel}.cs | 26 +++--------- 4 files changed, 15 insertions(+), 59 deletions(-) diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs index 244a60a892..803f8a8695 100644 --- a/src/ImageSharp/Image/IImageFrame.cs +++ b/src/ImageSharp/Image/IImageFrame.cs @@ -16,11 +16,6 @@ namespace SixLabors.ImageSharp internal interface IImageFrame : IImageFrame where TPixel : struct, IPixel { - /// - /// Gets the parent. - /// - Image Parent { get; } - /// /// Gets the pixel buffer. /// diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index 92e068ec8f..65f52f9221 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -4,16 +4,8 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.MetaData; + using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; namespace SixLabors.ImageSharp { @@ -24,34 +16,25 @@ namespace SixLabors.ImageSharp public sealed class ImageFrameCollection : IEnumerable> where TPixel : struct, IPixel { - private IList> frames = new List>(); - private readonly Image parent; + private readonly IList> frames = new List>(); + private readonly int parentWidth; + private readonly int parentHeight; internal ImageFrameCollection(Image parent) { - this.parent = parent; + this.parentWidth = parent.Width; + this.parentHeight = parent.Height; } /// /// Gets the count. /// - public int Count { get => this.frames.Count; } + public int Count => this.frames.Count; /// /// Gets the root frame. /// - public ImageFrame RootFrame - { - get - { - if (this.frames.Count > 0) - { - return this.frames[0]; - } - - return null; - } - } + public ImageFrame RootFrame => this.frames.Count > 0 ? this.frames[0] : null; /// /// Gets or sets the at the specified index. @@ -63,10 +46,7 @@ namespace SixLabors.ImageSharp /// The at the specified index. public ImageFrame this[int index] { - get - { - return this.frames[index]; - } + get => this.frames[index]; set { @@ -123,7 +103,7 @@ namespace SixLabors.ImageSharp { if (this.Count != 0) { - if (this.parent.Width != frame.Width || this.parent.Height != frame.Height) + if (this.parentWidth != frame.Width || this.parentHeight != frame.Height) { throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); } diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index cfd28f05d6..7d8a48598b 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -136,9 +136,6 @@ namespace SixLabors.ImageSharp /// ImageFrameMetaData IImageFrame.MetaData => this.RootFrame.MetaData; - /// - Image IImageFrame.Parent => this.RootFrame.Parent; - /// /// Gets or sets the pixel at the specified position. /// diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index bb5f427dfd..0de76cbd13 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -4,8 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Unsafe = System.Runtime.CompilerServices.Unsafe; @@ -49,8 +48,6 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(image.Height, 0, "image height"); this.SetPixelBufferUnsafe(image.PixelBuffer, false); - Configuration config = image.Parent.Configuration(); - this.ParallelOptions = config.ParallelOptions; } /// @@ -77,8 +74,6 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThan(height, 0, nameof(height)); this.SetPixelBufferUnsafe(pixels, ownedBuffer); - - this.ParallelOptions = Configuration.Default.ParallelOptions; } /// @@ -104,21 +99,12 @@ namespace SixLabors.ImageSharp /// public int RowStride { get; private set; } - /// - /// Gets the width of the image. - /// + /// public int Width { get; private set; } - /// - /// Gets the height of the image. - /// + /// public int Height { get; private set; } - /// - /// Gets the global parallel options for processing tasks in parallel. - /// - public ParallelOptions ParallelOptions { get; } - /// Span IBuffer2D.Span => this.PixelBuffer; @@ -147,9 +133,7 @@ namespace SixLabors.ImageSharp } } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// + /// public void Dispose() { if (this.isDisposed || !this.ownedBuffer) @@ -245,7 +229,7 @@ namespace SixLabors.ImageSharp /// If is true then caller is responsible for ensuring is called. internal Buffer2D SwapBufferOwnership(Buffer2D pixels) { - var oldPixels = this.PixelBuffer; + Buffer2D oldPixels = this.PixelBuffer; this.SetPixelBufferUnsafe(pixels, this.ownedBuffer); return oldPixels; } From a478aed3933db3d707dee54f1727bc5ded96e2da Mon Sep 17 00:00:00 2001 From: JimBobSquarePants Date: Wed, 6 Sep 2017 16:29:46 +1000 Subject: [PATCH 06/24] Fix null reference execption TODO: I do not like this, far to flaky. --- src/ImageSharp/Image/Image{TPixel}.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 7d8a48598b..0b33528691 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp /// /// Gets the root frame. /// - private IImageFrame RootFrame => this.Frames.RootFrame; + private IImageFrame RootFrame => this.Frames?.RootFrame; /// Buffer2D IImageFrame.PixelBuffer => this.RootFrame.PixelBuffer; @@ -144,15 +144,9 @@ namespace SixLabors.ImageSharp /// The at the specified position. public TPixel this[int x, int y] { - get - { - return this.RootFrame.PixelBuffer[x, y]; - } + get => this.RootFrame.PixelBuffer[x, y]; - set - { - this.RootFrame.PixelBuffer[x, y] = value; - } + set => this.RootFrame.PixelBuffer[x, y] = value; } /// From 40433d8fea7699ad97865a4a603d7b4bcef1c225 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 6 Sep 2017 22:34:27 +1000 Subject: [PATCH 07/24] Use RootFrame for validation --- src/ImageSharp/Image/ImageFrameCollection.cs | 10 +--------- src/ImageSharp/Image/Image{TPixel}.cs | 12 ++---------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index 65f52f9221..bfd8e5e91d 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -17,14 +17,6 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { private readonly IList> frames = new List>(); - private readonly int parentWidth; - private readonly int parentHeight; - - internal ImageFrameCollection(Image parent) - { - this.parentWidth = parent.Width; - this.parentHeight = parent.Height; - } /// /// Gets the count. @@ -103,7 +95,7 @@ namespace SixLabors.ImageSharp { if (this.Count != 0) { - if (this.parentWidth != frame.Width || this.parentHeight != frame.Height) + if (this.RootFrame.Width != frame.Width || this.RootFrame.Height != frame.Height) { throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); } diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 0b33528691..1b8f8ec28d 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -1,22 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; + using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using SixLabors.Primitives; namespace SixLabors.ImageSharp { @@ -81,7 +73,7 @@ namespace SixLabors.ImageSharp this.ImageConfiguration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.Frames = new ImageFrameCollection(this); + this.Frames = new ImageFrameCollection(); if (frames != null) { From ee60eb3e8334e3346e8ca380725f912ef502662a Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 6 Sep 2017 18:46:18 +0100 Subject: [PATCH 08/24] exlusivly use frames to access pixel spans --- src/ImageSharp/Advanced/IPixelSource.cs | 24 ++++++++++++++ src/ImageSharp/Advanced/ImageExtensions.cs | 33 ++++++++----------- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 4 +-- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 4 +-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- .../Common/Decoder/JpegImagePostProcessor.cs | 6 ++-- .../Jpeg/GolangPort/OrigJpegDecoderCore.cs | 2 +- .../Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs | 14 ++++---- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 10 +++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 ++-- src/ImageSharp/Image/IImageFrame.cs | 13 -------- src/ImageSharp/Image/Image.LoadPixelData.cs | 2 +- src/ImageSharp/Image/ImageExtensions.cs | 11 ++----- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 4 +-- src/ImageSharp/Image/Image{TPixel}.cs | 21 +++++------- .../Image/PixelAccessorExtensions.cs | 20 ++++++++++- src/ImageSharp/Image/PixelAccessor{TPixel}.cs | 8 ++--- .../ImageSharp.Benchmarks/Image/CopyPixels.cs | 4 +-- .../Jpg/JpegImagePostProcessorTests.cs | 6 ++-- .../ImageSharp.Tests/Image/ImageLoadTests.cs | 2 +- .../Processors/ColorMatrix/GrayscaleTest.cs | 5 +-- .../ReferenceCodecs/SystemDrawingBridge.cs | 6 ++-- .../TestUtilities/TestImageExtensions.cs | 2 +- 23 files changed, 111 insertions(+), 98 deletions(-) create mode 100644 src/ImageSharp/Advanced/IPixelSource.cs diff --git a/src/ImageSharp/Advanced/IPixelSource.cs b/src/ImageSharp/Advanced/IPixelSource.cs new file mode 100644 index 0000000000..c9edf118c6 --- /dev/null +++ b/src/ImageSharp/Advanced/IPixelSource.cs @@ -0,0 +1,24 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.MetaData; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Encapsulates the basic properties and methods required to manipulate images. + /// + /// The type of the pixel. + internal interface IPixelSource + where TPixel : struct, IPixel + { + /// + /// Gets the pixel buffer. + /// + Buffer2D PixelBuffer { get; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index d3d563fae2..fdfbd923a6 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Text; using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -26,16 +27,6 @@ namespace SixLabors.ImageSharp.Advanced where TPixel : struct, IPixel => GetSpan(source); - /// - /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. - /// - /// The type of the pixel. - /// The source. - /// The - public static Span GetPixelSpan(this Image source) - where TPixel : struct, IPixel - => GetSpan(source); - /// /// Gets a representing the row 'y' beginning from the the first pixel on that row. /// @@ -48,25 +39,27 @@ namespace SixLabors.ImageSharp.Advanced => GetSpan(source, row); /// - /// Gets a representing the row 'y' beginning from the the first pixel on that row. + /// Gets the span. /// /// The type of the pixel. /// The source. - /// The row. - /// The - public static Span GetPixelRowSpan(this Image source, int row) + /// The span retuned from Pixel source + private static Span GetSpan(IPixelSource source) where TPixel : struct, IPixel - => GetSpan(source, row); + => source.PixelBuffer.Span; /// /// Gets the span. /// /// The type of the pixel. /// The source. - /// The span retuned from Pixel source - private static Span GetSpan(IImageFrame source) + /// The row. + /// + /// The span retuned from Pixel source + /// + private static Span GetSpan(IPixelSource source, int row) where TPixel : struct, IPixel - => source.PixelBuffer.Span; + => GetSpan(source.PixelBuffer, row); /// /// Gets the span. @@ -77,9 +70,9 @@ namespace SixLabors.ImageSharp.Advanced /// /// The span retuned from Pixel source /// - private static Span GetSpan(IImageFrame source, int row) + private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel - => source.PixelBuffer.Span.Slice(row * source.Width, source.Width); + => source.Span.Slice(row * source.Width, source.Width); /// /// Gets the bounds of the image. diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 6ac1243620..d34d170847 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp WriteHeader(writer, fileHeader); this.WriteInfo(writer, infoHeader); - this.WriteImage(writer, image); + this.WriteImage(writer, image.Frames.RootFrame); writer.Flush(); } @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// The containing pixel data. /// - private void WriteImage(EndianBinaryWriter writer, IImageFrame image) + private void WriteImage(EndianBinaryWriter writer, ImageFrame image) where TPixel : struct, IPixel { using (PixelAccessor pixels = image.Lock()) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 8666dca7ae..c3c395e852 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -378,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.SetFrameMetaData(this.metaData); - image = (ImageFrame)this.image; + image = this.image.Frames.RootFrame; } else { @@ -471,7 +471,7 @@ namespace SixLabors.ImageSharp.Formats.Gif return; } - this.previousFrame = currentFrame == null ? this.image : currentFrame; + this.previousFrame = currentFrame == null ? this.image.Frames.RootFrame : currentFrame; if (this.graphicsControlExtension != null && this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7b12b95b14..3da43967fe 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Gif ditheredQuantizer.Dither = !this.hasFrames; // Quantize the image returning a palette. - QuantizedImage quantized = ditheredQuantizer.Quantize(image, paletteSize); + QuantizedImage quantized = ditheredQuantizer.Quantize(image.Frames.RootFrame, paletteSize); int index = this.GetTransparentIndex(quantized); diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs index e3ca1d74c2..84867d2766 100644 --- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// /// The pixel type /// The destination image - public void PostProcess(Image destination) + public void PostProcess(ImageFrame destination) where TPixel : struct, IPixel { this.PixelRowCounter = 0; @@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// /// The pixel type /// The destination image. - public void DoPostProcessorStep(Image destination) + public void DoPostProcessorStep(ImageFrame destination) where TPixel : struct, IPixel { foreach (JpegComponentPostProcessor cpp in this.ComponentProcessors) @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder /// /// The pixel type /// The destination image - private void ConvertColorsInto(Image destination) + private void ConvertColorsInto(ImageFrame destination) where TPixel : struct, IPixel { int maxY = Math.Min(destination.Height, this.PixelRowCounter + PixelRowsPerStep); diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs index 33ebe72d01..8369e92366 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs @@ -815,7 +815,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort using (var postProcessor = new JpegImagePostProcessor(this)) { var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData); - postProcessor.PostProcess(image); + postProcessor.PostProcess(image.Frames.RootFrame); return image; } } diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs index c5225b5467..6c84597c99 100644 --- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort this.QuantizeAndInverseAllComponents(); var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, metadata); - this.FillPixelData(image); + this.FillPixelData(image.Frames.RootFrame); this.AssignResolution(image); return image; } @@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort /// /// The pixel format. /// The image - private void FillPixelData(Image image) + private void FillPixelData(ImageFrame image) where TPixel : struct, IPixel { if (this.NumberOfComponents > 4) @@ -856,7 +856,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void FillGrayScaleImage(Image image) + private void FillGrayScaleImage(ImageFrame image) where TPixel : struct, IPixel { for (int y = 0; y < image.Height; y++) @@ -875,7 +875,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void FillYCbCrImage(Image image) + private void FillYCbCrImage(ImageFrame image) where TPixel : struct, IPixel { for (int y = 0; y < image.Height; y++) @@ -894,7 +894,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void FillYcckImage(Image image) + private void FillYcckImage(ImageFrame image) where TPixel : struct, IPixel { for (int y = 0; y < image.Height; y++) @@ -915,7 +915,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void FillCmykImage(Image image) + private void FillCmykImage(ImageFrame image) where TPixel : struct, IPixel { for (int y = 0; y < image.Height; y++) @@ -941,7 +941,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void FillRgbImage(Image image) + private void FillRgbImage(ImageFrame image) where TPixel : struct, IPixel { for (int y = 0; y < image.Height; y++) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 48618c5eee..4fd57c2784 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -236,7 +236,7 @@ namespace SixLabors.ImageSharp.Formats.Png } deframeStream.AllocateNewBytes(currentChunk.Length); - this.ReadScanlines(deframeStream.CompressedStream, image); + this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); stream.Read(this.crcBuffer, 0, 4); break; case PngChunkTypes.Palette: @@ -442,7 +442,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The containing data. /// The pixel data. - private void ReadScanlines(Stream dataStream, Image image) + private void ReadScanlines(Stream dataStream, ImageFrame image) where TPixel : struct, IPixel { if (this.header.InterlaceMethod == PngInterlaceMode.Adam7) @@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The image to decode to. - private void DecodePixelData(Stream compressedStream, Image image) + private void DecodePixelData(Stream compressedStream, ImageFrame image) where TPixel : struct, IPixel { while (this.currentRow < this.header.Height) @@ -519,7 +519,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The compressed pixel data stream. /// The current image. - private void DecodeInterlacedPixelData(Stream compressedStream, Image image) + private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image) where TPixel : struct, IPixel { while (true) @@ -609,7 +609,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The de-filtered scanline /// The image - private void ProcessDefilteredScanline(byte[] defilteredScanline, Image pixels) + private void ProcessDefilteredScanline(byte[] defilteredScanline, ImageFrame pixels) where TPixel : struct, IPixel { var color = default(TPixel); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 6ca27d5333..660c371873 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -233,12 +233,12 @@ namespace SixLabors.ImageSharp.Formats.Png // Collect the indexed pixel data if (this.pngColorType == PngColorType.Palette) { - this.CollectIndexedBytes(image, stream, header); + this.CollectIndexedBytes(image.Frames.RootFrame, stream, header); } this.WritePhysicalChunk(stream, image); this.WriteGammaChunk(stream); - this.WriteDataChunks(image, stream); + this.WriteDataChunks(image.Frames.RootFrame, stream); this.WriteEndChunk(stream); stream.Flush(); } @@ -649,7 +649,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The pixel format. /// The image. /// The stream. - private void WriteDataChunks(Image pixels, Stream stream) + private void WriteDataChunks(ImageFrame pixels, Stream stream) where TPixel : struct, IPixel { this.bytesPerScanline = this.width * this.bytesPerPixel; diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs index 803f8a8695..a495b5ed8c 100644 --- a/src/ImageSharp/Image/IImageFrame.cs +++ b/src/ImageSharp/Image/IImageFrame.cs @@ -9,19 +9,6 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp { - /// - /// Encapsulates the basic properties and methods required to manipulate images. - /// - /// The type of the pixel. - internal interface IImageFrame : IImageFrame - where TPixel : struct, IPixel - { - /// - /// Gets the pixel buffer. - /// - Buffer2D PixelBuffer { get; } - } - /// /// Encapsulates the basic properties and methods required to manipulate images. /// diff --git a/src/ImageSharp/Image/Image.LoadPixelData.cs b/src/ImageSharp/Image/Image.LoadPixelData.cs index 6302eb66be..87edf0bc8c 100644 --- a/src/ImageSharp/Image/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image/Image.LoadPixelData.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data)); var image = new Image(config, width, height); - SpanHelper.Copy(data, image.GetPixelSpan(), count); + SpanHelper.Copy(data, image.Frames.RootFrame.GetPixelSpan(), count); return image; } diff --git a/src/ImageSharp/Image/ImageExtensions.cs b/src/ImageSharp/Image/ImageExtensions.cs index 8e78de0563..d1798abf3e 100644 --- a/src/ImageSharp/Image/ImageExtensions.cs +++ b/src/ImageSharp/Image/ImageExtensions.cs @@ -158,7 +158,7 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static byte[] SavePixelData(this Image source) where TPixel : struct, IPixel - => source.GetPixelSpan().AsBytes().ToArray(); + => source.Frames.RootFrame.SavePixelData(); /// /// Saves the raw image to the given bytes. @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SavePixelData(this Image source, byte[] buffer) where TPixel : struct, IPixel - => SavePixelData(source, new Span(buffer)); + => source.Frames.RootFrame.SavePixelData(buffer); /// /// Saves the raw image to the given bytes. @@ -180,12 +180,7 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SavePixelData(this Image source, Span buffer) where TPixel : struct, IPixel - { - Span byteBuffer = source.GetPixelSpan().AsBytes(); - Guard.MustBeGreaterThanOrEqualTo(buffer.Length, byteBuffer.Length, nameof(buffer)); - - byteBuffer.CopyTo(buffer); - } + => source.Frames.RootFrame.SavePixelData(buffer); /// /// Returns a Base64 encoded string from the given image. diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index 063108515b..a8cf640e20 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp /// Represents a single frame in a animation. /// /// The pixel format. - public sealed class ImageFrame : IImageFrame + public sealed class ImageFrame : IImageFrame, IPixelSource where TPixel : struct, IPixel { /// @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp } /// - Buffer2D IImageFrame.PixelBuffer => this.pixelBuffer; + Buffer2D IPixelSource.PixelBuffer => this.pixelBuffer; /// public int Width => this.pixelBuffer.Width; diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 1b8f8ec28d..f7ecae375a 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -1,10 +1,11 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using System.IO; using System.Linq; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; @@ -16,7 +17,7 @@ namespace SixLabors.ImageSharp /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// /// The pixel format. - public sealed partial class Image : IImageFrame + public sealed partial class Image : IDisposable where TPixel : struct, IPixel { /// @@ -100,12 +101,12 @@ namespace SixLabors.ImageSharp /// /// Gets the width. /// - public int Width => this.RootFrame?.Width ?? 0; + public int Width => this.Frames.RootFrame.Width; /// /// Gets the height. /// - public int Height => this.RootFrame?.Height ?? 0; + public int Height => this.Frames.RootFrame.Height; /// /// Gets the meta data of the image. @@ -120,13 +121,7 @@ namespace SixLabors.ImageSharp /// /// Gets the root frame. /// - private IImageFrame RootFrame => this.Frames?.RootFrame; - - /// - Buffer2D IImageFrame.PixelBuffer => this.RootFrame.PixelBuffer; - - /// - ImageFrameMetaData IImageFrame.MetaData => this.RootFrame.MetaData; + private IPixelSource PixelSource => this.Frames?.RootFrame; /// /// Gets or sets the pixel at the specified position. @@ -136,9 +131,9 @@ namespace SixLabors.ImageSharp /// The at the specified position. public TPixel this[int x, int y] { - get => this.RootFrame.PixelBuffer[x, y]; + get => this.PixelSource.PixelBuffer[x, y]; - set => this.RootFrame.PixelBuffer[x, y] = value; + set => this.PixelSource.PixelBuffer[x, y] = value; } /// diff --git a/src/ImageSharp/Image/PixelAccessorExtensions.cs b/src/ImageSharp/Image/PixelAccessorExtensions.cs index 3c90a55c99..9146ef48da 100644 --- a/src/ImageSharp/Image/PixelAccessorExtensions.cs +++ b/src/ImageSharp/Image/PixelAccessorExtensions.cs @@ -5,6 +5,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Unsafe = System.Runtime.CompilerServices.Unsafe; @@ -27,10 +28,27 @@ namespace SixLabors.ImageSharp /// /// The /// - internal static PixelAccessor Lock(this IImageFrame frame) + internal static PixelAccessor Lock(this IPixelSource frame) where TPixel : struct, IPixel { return new PixelAccessor(frame); } + + /// + /// Locks the image providing access to the pixels. + /// + /// It is imperative that the accessor is correctly disposed off after use. + /// + /// + /// The type of the pixel. + /// The image. + /// + /// The + /// + internal static PixelAccessor Lock(this Image image) + where TPixel : struct, IPixel + { + return image.Frames.RootFrame.Lock(); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index 0de76cbd13..3abe28aca0 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -4,7 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Unsafe = System.Runtime.CompilerServices.Unsafe; @@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class. /// /// The image to provide pixel access for. - public PixelAccessor(IImageFrame image) + public PixelAccessor(IPixelSource image) { Guard.NotNull(image, nameof(image)); - Guard.MustBeGreaterThan(image.Width, 0, "image width"); - Guard.MustBeGreaterThan(image.Height, 0, "image height"); + Guard.MustBeGreaterThan(image.PixelBuffer.Width, 0, "image width"); + Guard.MustBeGreaterThan(image.PixelBuffer.Height, 0, "image height"); this.SetPixelBufferUnsafe(image.PixelBuffer, false); } diff --git a/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs b/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs index b3f53949d1..674aef84c1 100644 --- a/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs +++ b/tests/ImageSharp.Benchmarks/Image/CopyPixels.cs @@ -103,8 +103,8 @@ namespace SixLabors.ImageSharp.Benchmarks.Image Configuration.Default.ParallelOptions, y => { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = target.GetPixelRowSpan(y); + Span sourceRow = source.Frames.RootFrame.GetPixelRowSpan(y); + Span targetRow = target.Frames.RootFrame.GetPixelRowSpan(y); for (int x = 0; x < source.Width; x++) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs index 871321df9d..df6d1ef1bb 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs @@ -56,9 +56,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg string imageFile = provider.SourceFileOrDescription; using (OrigJpegDecoderCore decoder = JpegFixture.ParseStream(imageFile)) using (var pp = new JpegImagePostProcessor(decoder)) - using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) + using (var imageFrame = new ImageFrame(decoder.ImageWidth, decoder.ImageHeight)) { - pp.DoPostProcessorStep(image); + pp.DoPostProcessorStep(imageFrame); JpegComponentPostProcessor[] cp = pp.ComponentProcessors; @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg using (var pp = new JpegImagePostProcessor(decoder)) using (var image = new Image(decoder.ImageWidth, decoder.ImageHeight)) { - pp.PostProcess(image); + pp.PostProcess(image.Frames.RootFrame); image.DebugSave(provider); diff --git a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs index cf5e484cfe..f61c73636e 100644 --- a/tests/ImageSharp.Tests/Image/ImageLoadTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageLoadTests.cs @@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.Tests using (Image img = image1Provider.GetImage()) { - Assert.Equal(166036, img.GetPixelSpan().Length); + Assert.Equal(166036, img.Frames.RootFrame.GetPixelSpan().Length); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs b/tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs index 31ddd14f8a..fe003da32b 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/ColorMatrix/GrayscaleTest.cs @@ -32,9 +32,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.ColorMatrix { image.Mutate(x => x.Grayscale(value)); byte[] data = new byte[3]; - for (int i = 0; i < image.GetPixelSpan().Length; i++) + System.Span span = image.Frames.RootFrame.GetPixelSpan(); + for (int i = 0; i < span.Length; i++) { - image.GetPixelSpan()[i].ToXyzBytes(data, 0); + span[i].ToXyzBytes(data, 0); Assert.Equal(data[0], data[1]); Assert.Equal(data[1], data[2]); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs index 5fedaa124e..a201b39bd2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingBridge.cs @@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var destPtr = (Argb32*)workBuffer.Pin(); for (int y = 0; y < h; y++) { - Span row = image.GetPixelRowSpan(y); + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); byte* sourcePtr = sourcePtrBase + data.Stride * y; @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs var destPtr = (Rgb24*)workBuffer.Pin(); for (int y = 0; y < h; y++) { - Span row = image.GetPixelRowSpan(y); + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); byte* sourcePtr = sourcePtrBase + data.Stride * y; @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs for (int y = 0; y < h; y++) { - Span row = image.GetPixelRowSpan(y); + Span row = image.Frames.RootFrame.GetPixelRowSpan(y); ToArgb32(row, workBuffer); byte* destPtr = destPtrBase + data.Stride * y; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index b79165f950..b3dd763c7f 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -196,7 +196,7 @@ namespace SixLabors.ImageSharp.Tests { var image = new Image(buffer.Width, buffer.Height); - Span pixels = image.GetPixelSpan(); + Span pixels = image.Frames.RootFrame.GetPixelSpan(); for (int i = 0; i < buffer.Length; i++) { From 09a667d3a5fc65082a45c96a95784415e1bb17ec Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 6 Sep 2017 20:11:15 +0100 Subject: [PATCH 09/24] pass configuation into processors --- .../Processors/DrawImageProcessor.cs | 4 +- .../Processors/FillProcessor.cs | 4 +- .../Processors/FillRegionProcessor.cs | 2 +- src/ImageSharp/Advanced/IConfigurable.cs | 22 +++++++++ src/ImageSharp/Advanced/ImageExtensions.cs | 10 ++-- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 7 +-- src/ImageSharp/Image/Image{TPixel}.cs | 17 ++++--- .../Binarization/BinaryThresholdProcessor.cs | 8 ++-- .../ErrorDiffusionDitherProcessor.cs | 6 +-- .../Binarization/OrderedDitherProcessor.cs | 6 +-- .../Processors/CloningImageProcessor.cs | 33 ++++++------- .../ColorMatrix/ColorMatrixProcessor.cs | 4 +- .../ColorMatrix/LomographProcessor.cs | 4 +- .../ColorMatrix/PolaroidProcessor.cs | 6 +-- .../Convolution/BoxBlurProcessor.cs | 4 +- .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 4 +- .../Convolution/ConvolutionProcessor.cs | 4 +- .../EdgeDetection/EdgeDetector2DProcessor.cs | 8 ++-- .../EdgeDetectorCompassProcessor.cs | 12 ++--- .../EdgeDetection/EdgeDetectorProcessor.cs | 8 ++-- .../Convolution/GaussianBlurProcessor.cs | 4 +- .../Convolution/GaussianSharpenProcessor.cs | 4 +- .../Processors/DelegateProcessor.cs | 2 +- .../Processors/Effects/AlphaProcessor.cs | 4 +- .../Effects/BackgroundColorProcessor.cs | 4 +- .../Processors/Effects/BrightnessProcessor.cs | 4 +- .../Processors/Effects/ContrastProcessor.cs | 4 +- .../Processors/Effects/InvertProcessor.cs | 4 +- .../Effects/OilPaintingProcessor.cs | 4 +- .../Processors/Effects/PixelateProcessor.cs | 4 +- .../Processing/Processors/ImageProcessor.cs | 47 ++++++++----------- .../Processors/Overlays/GlowProcessor.cs | 4 +- .../Processors/Overlays/VignetteProcessor.cs | 4 +- .../Transforms/AutoOrientProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 4 +- .../Transforms/EntropyCropProcessor.cs | 8 ++-- .../Processors/Transforms/FlipProcessor.cs | 16 ++++--- .../Transforms/ResamplingWeightedProcessor.cs | 6 +-- .../Processors/Transforms/ResizeProcessor.cs | 8 ++-- .../Processors/Transforms/RotateProcessor.cs | 36 ++++++++------ .../Processors/Transforms/SkewProcessor.cs | 6 +-- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 4 +- .../ImageComparison/ExactImageComparer.cs | 4 +- .../ImageComparison/ImageComparer.cs | 16 +++---- .../ImageComparison/ImageSimilarityReport.cs | 38 +++++++++++---- .../ImageComparison/TolerantImageComparer.cs | 6 +-- 47 files changed, 227 insertions(+), 197 deletions(-) create mode 100644 src/ImageSharp/Advanced/IConfigurable.cs diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs index 25eddaf0bb..213ab1b4a7 100644 --- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors public Point Location { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { Image disposableImage = null; Image targetImage = this.Image; @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span background = sourcePixels.GetRowSpan(y).Slice(minX, width); diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index c6f11891b9..679ca6a228 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startX = sourceRectangle.X; int endX = sourceRectangle.Right; @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { int offsetY = y - startY; diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index 1022f63083..6340b1db3e 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors public GraphicsOptions Options { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { Region region = this.Region; Rectangle rect = region.Bounds; diff --git a/src/ImageSharp/Advanced/IConfigurable.cs b/src/ImageSharp/Advanced/IConfigurable.cs new file mode 100644 index 0000000000..347bc9253b --- /dev/null +++ b/src/ImageSharp/Advanced/IConfigurable.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.MetaData; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Encapsulates the properties for configuration + /// + internal interface IConfigurable + { + /// + /// Gets the pixel buffer. + /// + Configuration Configuration { get; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index fdfbd923a6..135acefa48 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -80,18 +80,16 @@ namespace SixLabors.ImageSharp.Advanced /// The Pixel format. /// The source image /// Returns the bounds of the image - public static Configuration Configuration(this ImageFrame source) + public static Configuration Configuration(this Image source) where TPixel : struct, IPixel - => source?.Parent?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default; + => GetConfiguration(source); /// /// Gets the bounds of the image. /// - /// The Pixel format. /// The source image /// Returns the bounds of the image - public static Configuration Configuration(this Image source) - where TPixel : struct, IPixel - => source?.ImageConfiguration ?? SixLabors.ImageSharp.Configuration.Default; + private static Configuration GetConfiguration(IConfigurable source) + => source?.Configuration ?? SixLabors.ImageSharp.Configuration.Default; } } diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index a8cf640e20..bb00ebf115 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -73,11 +73,6 @@ namespace SixLabors.ImageSharp /// public int Height => this.pixelBuffer.Height; - /// - /// Gets the configuration providing initialization code which allows extending the library. - /// - public Image Parent { get; private set; } - /// /// Gets the meta data of the frame. /// @@ -222,7 +217,7 @@ namespace SixLabors.ImageSharp Parallel.For( 0, target.Height, - this.Configuration().ParallelOptions, + Configuration.Default.ParallelOptions, y => { for (int x = 0; x < target.Width; x++) diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index f7ecae375a..f228d766d1 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -17,9 +17,11 @@ namespace SixLabors.ImageSharp /// Encapsulates an image, which consists of the pixel data for a graphics image and its attributes. /// /// The pixel format. - public sealed partial class Image : IDisposable + public sealed partial class Image : IDisposable, IConfigurable where TPixel : struct, IPixel { + private Configuration configuration; + /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -71,7 +73,7 @@ namespace SixLabors.ImageSharp /// The frames that will be owned by this image instance. internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable> frames) { - this.ImageConfiguration = configuration ?? Configuration.Default; + this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); this.Frames = new ImageFrameCollection(); @@ -91,12 +93,9 @@ namespace SixLabors.ImageSharp } /// - /// Gets the configuration. + /// Gets the pixel buffer. /// - /// - /// The configuration. - /// - internal Configuration ImageConfiguration { get; } + Configuration IConfigurable.Configuration => this.configuration; /// /// Gets the width. @@ -158,7 +157,7 @@ namespace SixLabors.ImageSharp { IEnumerable> frames = this.Frames.Select(x => x.Clone()).ToArray(); - return new Image(this.ImageConfiguration, this.Width, this.Height, this.MetaData.Clone(), frames); + return new Image(this.configuration, this.Width, this.Height, this.MetaData.Clone(), frames); } /// @@ -176,7 +175,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> frames = this.Frames.Select(x => x.CloneAs()).ToArray(); - var target = new Image(this.ImageConfiguration, this.Width, this.Height, this.MetaData, frames); + var target = new Image(this.configuration, this.Width, this.Height, this.MetaData, frames); return target; } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 4a2ca38077..d736b91ee6 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -48,13 +48,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { float threshold = this.Threshold; TPixel upper = this.UpperColor; @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs index 719a7ea34b..8907770e15 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs @@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs index d8b132c6c5..203a64cf16 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs @@ -63,13 +63,13 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel LowerColor { get; set; } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index 1279792dc4..176266ca6e 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -27,6 +27,7 @@ namespace SixLabors.ImageSharp.Processing throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } + var configuration = source.Configuration(); this.BeforeImageApply(source, clone, sourceRectangle); for (int i = 0; i < source.Frames.Count; i++) @@ -34,10 +35,9 @@ namespace SixLabors.ImageSharp.Processing ImageFrame sourceFrame = source.Frames[i]; ImageFrame clonedFrame = clone.Frames[i]; - this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle); - - this.OnApply(sourceFrame, clonedFrame, sourceRectangle); - this.AfterApply(sourceFrame, clonedFrame, sourceRectangle); + this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle, configuration); + this.OnApply(sourceFrame, clonedFrame, sourceRectangle, configuration); + this.AfterApply(sourceFrame, clonedFrame, sourceRectangle, configuration); } this.AfterImageApply(source, clone, sourceRectangle); @@ -99,33 +99,30 @@ namespace SixLabors.ImageSharp.Processing /// /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected virtual void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { } /// - /// Applies the process to the specified portion of the specified at the specified location + /// 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 cloned/destination image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected abstract void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle); + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected abstract void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration); /// /// This method is called after the process is applied to prepare the processor. /// /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected virtual void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { } diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs index b48da3a144..4a64bfaa0d 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public virtual bool Compand { get; set; } = true; /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs index 5c702af211..1ec76bf554 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs @@ -39,9 +39,9 @@ namespace SixLabors.ImageSharp.Processing.Processors }; /// - protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new VignetteProcessor(VeryDarkGreen, this.options).Apply(source, sourceRectangle); + new VignetteProcessor(VeryDarkGreen, this.options).Apply(source, sourceRectangle, configuration); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs index 78e25c147d..f910562e64 100644 --- a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs @@ -46,10 +46,10 @@ namespace SixLabors.ImageSharp.Processing.Processors }; /// - protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new VignetteProcessor(VeryDarkOrange, this.options).Apply(source, sourceRectangle); - new GlowProcessor(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle); + new VignetteProcessor(VeryDarkOrange, this.options).Apply(source, sourceRectangle, configuration); + new GlowProcessor(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle, configuration); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 75d134137b..8056141a09 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); + new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); } /// diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 37174c49da..b85432ac54 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int kernelYHeight = this.KernelY.Height; int kernelYWidth = this.KernelY.Width; @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, endY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 1aeb37862c..362fa5c508 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -41,11 +41,11 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int width = source.Width; int height = source.Height; - ParallelOptions parallelOptions = source.Configuration().ParallelOptions; + ParallelOptions parallelOptions = configuration.ParallelOptions; using (var firstPassPixels = new PixelAccessor(width, height)) using (PixelAccessor sourcePixels = source.Lock()) diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index f2bc82f3b4..c0d3fdcfec 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelXY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int kernelLength = this.KernelXY.Height; int radius = kernelLength >> 1; @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, endY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs index 3198ae0a28..f93787d129 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetector2DProcessor.cs @@ -40,17 +40,17 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Grayscale { get; set; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); + new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.Grayscale) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs index bbe527eb70..32c22a8ce9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorCompassProcessor.cs @@ -62,16 +62,16 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Grayscale { get; set; } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.Grayscale) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { Fast2DArray[] kernels = { this.North, this.NorthWest, this.West, this.SouthWest, this.South, this.SouthEast, this.East, this.NorthEast }; @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors // we need a clean copy for each pass to start from using (ImageFrame cleanCopy = source.Clone()) { - new ConvolutionProcessor(kernels[0]).Apply(source, sourceRectangle); + new ConvolutionProcessor(kernels[0]).Apply(source, sourceRectangle, configuration); if (kernels.Length == 1) { @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Processing.Processors { using (ImageFrame pass = cleanCopy.Clone()) { - new ConvolutionProcessor(kernels[i]).Apply(pass, sourceRectangle); + new ConvolutionProcessor(kernels[i]).Apply(pass, sourceRectangle, configuration); using (PixelAccessor passPixels = pass.Lock()) using (PixelAccessor targetPixels = source.Lock()) @@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { int offsetY = y - shiftY; diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs index d43ee6d64d..3b98b77fc8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetection/EdgeDetectorProcessor.cs @@ -33,18 +33,18 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelXY { get; } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.Grayscale) { - new GrayscaleBt709Processor().Apply(source, sourceRectangle); + new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration); } } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new ConvolutionProcessor(this.KernelXY).Apply(source, sourceRectangle); + new ConvolutionProcessor(this.KernelXY).Apply(source, sourceRectangle, configuration); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index 2a1da29382..c897efeed8 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -85,9 +85,9 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); + new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); } /// diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 263abbdcf1..b960e9075f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -87,9 +87,9 @@ namespace SixLabors.ImageSharp.Processing.Processors public Fast2DArray KernelY { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle); + new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); } /// diff --git a/src/ImageSharp/Processing/Processors/DelegateProcessor.cs b/src/ImageSharp/Processing/Processors/DelegateProcessor.cs index 7fc70bd79c..f17c39681e 100644 --- a/src/ImageSharp/Processing/Processors/DelegateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/DelegateProcessor.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { // NOP, we did all we wanted to do inside BeforeImageApply } diff --git a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs index fbc5a15d77..7e5bd02abc 100644 --- a/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/AlphaProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public float Value { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs index 9e4813f2b6..72e9b8f555 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BackgroundColorProcessor.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public TPixel Value { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); diff --git a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs index 8143d662e4..c864330c9d 100644 --- a/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/BrightnessProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Value { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { float brightness = this.Value / 100F; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs index 545363e271..5ab2662110 100644 --- a/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/ContrastProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Value { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { float contrast = (100F + this.Value) / 100F; @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs index 3fe179cd80..448025f70a 100644 --- a/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/InvertProcessor.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Processing.Processors where TPixel : struct, IPixel { /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span row = source.GetPixelRowSpan(y - startY); diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 88b4a2babe..b22a497987 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int BrushSize { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) { @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( startY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index 64522b67e5..0ab21f65ac 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public int Size { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width) { @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.ForEach( range, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { int offsetY = y - startY; diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 26e0843059..4799b09951 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -20,13 +20,12 @@ namespace SixLabors.ImageSharp.Processing { try { + var config = source.Configuration(); this.BeforeImageApply(source, sourceRectangle); foreach (ImageFrame sourceFrame in source.Frames) { - this.BeforeApply(sourceFrame, sourceRectangle); - this.OnApply(sourceFrame, sourceRectangle); - this.AfterApply(sourceFrame, sourceRectangle); + this.Apply(sourceFrame, sourceRectangle, config); } this.AfterImageApply(source, sourceRectangle); @@ -48,13 +47,14 @@ namespace SixLabors.ImageSharp.Processing /// /// the source image /// the target - public void Apply(ImageFrame source, Rectangle sourceRectangle) + /// The configuration. + public void Apply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { try { - this.BeforeApply(source, sourceRectangle); - this.OnApply(source, sourceRectangle); - this.AfterApply(source, sourceRectangle); + this.BeforeApply(source, sourceRectangle, configuration); + this.OnApply(source, sourceRectangle, configuration); + this.AfterApply(source, sourceRectangle, configuration); } #if DEBUG catch (Exception) @@ -72,9 +72,7 @@ namespace SixLabors.ImageSharp.Processing /// 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. - /// + /// The structure that specifies the portion of the image object to draw. protected virtual void BeforeImageApply(Image source, Rectangle sourceRectangle) { } @@ -83,31 +81,28 @@ namespace SixLabors.ImageSharp.Processing /// 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 BeforeApply(ImageFrame source, Rectangle sourceRectangle) + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected virtual void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { } /// - /// Applies the process to the specified portion of the specified at the specified location + /// 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. - /// - protected abstract void OnApply(ImageFrame source, Rectangle sourceRectangle); + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected abstract void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration); /// /// 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(ImageFrame source, Rectangle sourceRectangle) + /// The structure that specifies the portion of the image object to draw. + /// The configuration. + protected virtual void AfterApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { } @@ -115,9 +110,7 @@ namespace SixLabors.ImageSharp.Processing /// 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. - /// + /// The structure that specifies the portion of the image object to draw. protected virtual void AfterImageApply(Image source, Rectangle sourceRectangle) { } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index d8a611c0fd..b02585d8fd 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public ValueSize Radius { get; set; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { using (var amounts = new Buffer(width)) diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index c9bfc27cf0..7b592a6a4d 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public ValueSize RadiusY { get; set; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { using (var amounts = new Buffer(width)) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs index f18d775f5e..63ccee982e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { // Nothing required here } diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 4228bb34bd..2657daaa8a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public Rectangle CropRectangle { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (this.CropRectangle == sourceRectangle) { @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y).Slice(minX); diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index 7ca7008a30..d2a08daba6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -34,15 +34,15 @@ namespace SixLabors.ImageSharp.Processing.Processors public float Threshold { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { using (ImageFrame temp = source.Clone()) { // Detect the edges. - new SobelProcessor().Apply(temp, sourceRectangle); + new SobelProcessor().Apply(temp, sourceRectangle, configuration); // Apply threshold binarization filter. - new BinaryThresholdProcessor(this.Threshold).Apply(temp, sourceRectangle); + new BinaryThresholdProcessor(this.Threshold).Apply(temp, sourceRectangle, configuration); // Search for the first white pixels Rectangle rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors return; } - new CropProcessor(rectangle).Apply(source, sourceRectangle); + new CropProcessor(rectangle).Apply(source, sourceRectangle, configuration); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index 17ce08318a..de60177f2f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -32,16 +32,16 @@ namespace SixLabors.ImageSharp.Processing.Processors public FlipType FlipType { get; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { switch (this.FlipType) { // No default needed as we have already set the pixels. case FlipType.Vertical: - this.FlipX(source); + this.FlipX(source, configuration); break; case FlipType.Horizontal: - this.FlipY(source); + this.FlipY(source, configuration); break; } } @@ -51,7 +51,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// at half the height of the image. /// /// The source image to apply the process to. - private void FlipX(ImageFrame source) + /// The configuration. + private void FlipX(ImageFrame source, Configuration configuration) { int width = source.Width; int height = source.Height; @@ -62,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, halfHeight, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { int newY = height - y - 1; @@ -84,7 +85,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// at half of the width of the image. /// /// The source image to apply the process to. - private void FlipY(ImageFrame source) + /// The configuration. + private void FlipY(ImageFrame source, Configuration configuration) { int width = source.Width; int height = source.Height; @@ -95,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs index 708d7a273f..781f3a01c7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { if (!(this.Sampler is NearestNeighborResampler)) { @@ -152,9 +152,9 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle) + protected override void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) { - base.AfterApply(source, destination, sourceRectangle); + base.AfterApply(source, destination, sourceRectangle, configuration); this.HorizontalWeights?.Dispose(); this.HorizontalWeights = null; this.VerticalWeights?.Dispose(); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 98b8e12897..5dfa343caa 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override unsafe void OnApply(ImageFrame source, ImageFrame cloned, Rectangle sourceRectangle) + protected override unsafe void OnApply(ImageFrame source, ImageFrame cloned, Rectangle sourceRectangle, Configuration configuration) { // Jump out, we'll deal with that later. if (source.Width == cloned.Width && source.Height == cloned.Height && sourceRectangle == this.ResizeRectangle) @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { // Y coordinates of source points @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, sourceRectangle.Bottom, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { // TODO: Without Parallel.For() this buffer object could be reused: @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { // Ensure offsets are normalised for cropping and padding. diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 43bf19d495..a7fb400acc 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -35,9 +35,9 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Expand { get; set; } = true; /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - if (this.OptimizedApply(source)) + if (this.OptimizedApply(source, configuration)) { return; } @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span targetRow = targetPixels.GetRowSpan(y); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon) { @@ -91,8 +91,11 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees. /// /// The source image. - /// The - private bool OptimizedApply(ImageFrame source) + /// The configuration. + /// + /// The + /// + private bool OptimizedApply(ImageFrame source, Configuration configuration) { if (MathF.Abs(this.Angle) < Constants.Epsilon) { @@ -102,19 +105,19 @@ namespace SixLabors.ImageSharp.Processing.Processors if (MathF.Abs(this.Angle - 90) < Constants.Epsilon) { - this.Rotate90(source); + this.Rotate90(source, configuration); return true; } if (MathF.Abs(this.Angle - 180) < Constants.Epsilon) { - this.Rotate180(source); + this.Rotate180(source, configuration); return true; } if (MathF.Abs(this.Angle - 270) < Constants.Epsilon) { - this.Rotate270(source); + this.Rotate270(source, configuration); return true; } @@ -125,7 +128,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 270 degrees clockwise at the centre point. /// /// The source image. - private void Rotate270(ImageFrame source) + /// The configuration. + private void Rotate270(ImageFrame source, Configuration configuration) { int width = source.Width; int height = source.Height; @@ -137,7 +141,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { for (int x = 0; x < width; x++) @@ -158,7 +162,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 180 degrees clockwise at the centre point. /// /// The source image. - private void Rotate180(ImageFrame source) + /// The configuration. + private void Rotate180(ImageFrame source, Configuration configuration) { int width = source.Width; int height = source.Height; @@ -168,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); @@ -188,7 +193,8 @@ namespace SixLabors.ImageSharp.Processing.Processors /// Rotates the image 90 degrees clockwise at the centre point. /// /// The source image. - private void Rotate90(ImageFrame source) + /// The configuration. + private void Rotate90(ImageFrame source, Configuration configuration) { int width = source.Width; int height = source.Height; @@ -198,7 +204,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span sourceRow = source.GetPixelRowSpan(y); diff --git a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs index bafda41db7..316e2a2af3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/SkewProcessor.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors public bool Expand { get; set; } = true; /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int height = this.CanvasRectangle.Height; int width = this.CanvasRectangle.Width; @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors Parallel.For( 0, height, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { Span targetRow = targetPixels.GetRowSpan(y); @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors } /// - protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle) + protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { this.processMatrix = Matrix3x2Extensions.CreateSkewDegrees(-this.AngleX, -this.AngleY, new Point(0, 0)); if (this.Expand) diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index 39a6e92119..884ae35017 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks public float Radius { get; set; } /// - protected override void OnApply(ImageFrame source, Rectangle sourceRectangle) + protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Benchmarks Parallel.For( minY, maxY, - source.Configuration().ParallelOptions, + configuration.ParallelOptions, y => { int offsetY = y - startY; diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs index 86c5994dbf..dbe2523661 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison { public static ExactImageComparer Instance { get; } = new ExactImageComparer(); - public override ImageSimilarityReport CompareImagesOrFrames( + public override ImageSimilarityReport CompareImagesOrFrames( ImageFrame expected, ImageFrame actual) { @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } } - return new ImageSimilarityReport(expected, actual, differences); + return new ImageSimilarityReport(expected, actual, differences); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index 8378db4e3c..829bf3d10a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison return new TolerantImageComparer(imageThreshold, perPixelManhattanThreshold); } - public abstract ImageSimilarityReport CompareImagesOrFrames( + public abstract ImageSimilarityReport CompareImagesOrFrames( ImageFrame expected, ImageFrame actual) where TPixelA : struct, IPixel where TPixelB : struct, IPixel; @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison public static class ImageComparerExtensions { - public static ImageSimilarityReport CompareImagesOrFrames( + public static ImageSimilarityReport CompareImagesOrFrames( this ImageComparer comparer, Image expected, Image actual) @@ -39,13 +39,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison return comparer.CompareImagesOrFrames((ImageFrame)expected, (ImageFrame)actual); } - public static IEnumerable CompareImages( + public static IEnumerable> CompareImages( this ImageComparer comparer, Image expected, Image actual) where TPixelA : struct, IPixel where TPixelB : struct, IPixel { - var result = new List(); + var result = new List>(); if (expected.Frames.Count != actual.Frames.Count) { @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison } for (int i = 0; i < expected.Frames.Count; i++) { - ImageSimilarityReport report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]); + ImageSimilarityReport report = comparer.CompareImagesOrFrames(expected.Frames[i], actual.Frames[i]); if (!report.IsEmpty) { result.Add(report); @@ -104,10 +104,10 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison throw new ImagesSimilarityException("Image frame count does not match!"); } - IEnumerable reports = comparer.CompareImages(expected, actual); + IEnumerable> reports = comparer.CompareImages(expected, actual); if (reports.Any()) { - List cleanedReports = new List(reports.Count()); + List> cleanedReports = new List>(reports.Count()); foreach (var r in reports) { var outsideChanges = r.Differences.Where(x => !( @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison x.Position.Y <= ignoredRegion.Bottom)); if (outsideChanges.Any()) { - cleanedReports.Add(new ImageSimilarityReport(r.ExpectedImage, r.ActualImage, outsideChanges, null)); + cleanedReports.Add(new ImageSimilarityReport(r.ExpectedImage, r.ActualImage, outsideChanges, null)); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs index aa61c7f5ac..78e390bbd2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageSimilarityReport.cs @@ -4,12 +4,13 @@ using System.Collections.Generic; using System.Linq; using System.Text; + using SixLabors.ImageSharp.PixelFormats; public class ImageSimilarityReport { - public ImageSimilarityReport( - IImageFrame expectedImage, - IImageFrame actualImage, + protected ImageSimilarityReport( + object expectedImage, + object actualImage, IEnumerable differences, float? totalNormalizedDifference = null) { @@ -18,9 +19,9 @@ this.TotalNormalizedDifference = totalNormalizedDifference; this.Differences = differences.ToArray(); } + public object ExpectedImage { get; } - public static ImageSimilarityReport Empty => - new ImageSimilarityReport(null, null, Enumerable.Empty(), 0f); + public object ActualImage { get; } // TODO: This should not be a nullable value! public float? TotalNormalizedDifference { get; } @@ -29,10 +30,6 @@ ? $"{this.TotalNormalizedDifference.Value * 100:0.0000}%" : "?"; - public IImageFrame ExpectedImage { get; } - - public IImageFrame ActualImage { get; } - public PixelDifference[] Differences { get; } public bool IsEmpty => this.Differences.Length == 0; @@ -41,7 +38,7 @@ { return this.IsEmpty ? "[SimilarImages]" : this.PrintDifference(); } - + private string PrintDifference() { var sb = new StringBuilder(); @@ -66,4 +63,25 @@ return sb.ToString(); } } + + public class ImageSimilarityReport : ImageSimilarityReport + where TPixelA : struct, IPixel + where TPixelB : struct, IPixel + { + public ImageSimilarityReport( + ImageFrame expectedImage, + ImageFrame actualImage, + IEnumerable differences, + float? totalNormalizedDifference = null) + : base(expectedImage, actualImage, differences, totalNormalizedDifference) + { + } + + public static ImageSimilarityReport Empty => + new ImageSimilarityReport(null, null, Enumerable.Empty(), 0f); + + public new ImageFrame ExpectedImage => (ImageFrame)base.ExpectedImage; + + public new ImageFrame ActualImage => (ImageFrame)base.ActualImage; + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs index 828c669d52..d20bd72ac1 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs @@ -46,7 +46,7 @@ /// public int PerPixelManhattanThreshold { get; } - public override ImageSimilarityReport CompareImagesOrFrames(ImageFrame expected, ImageFrame actual) + public override ImageSimilarityReport CompareImagesOrFrames(ImageFrame expected, ImageFrame actual) { if (expected.Size() != actual.Size()) { @@ -91,11 +91,11 @@ if (normalizedDifference > this.ImageThreshold) { - return new ImageSimilarityReport(expected, actual, differences, normalizedDifference); + return new ImageSimilarityReport(expected, actual, differences, normalizedDifference); } else { - return ImageSimilarityReport.Empty; + return ImageSimilarityReport.Empty; } } From 31ad6159d5e4a88ef92f08007bda338af6f1ce6d Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Wed, 6 Sep 2017 20:38:30 +0100 Subject: [PATCH 10/24] remove IImageFrame interface --- .../{Image => }/ICloningImageProcessor.cs | 0 src/ImageSharp/{Image => }/IImageProcessor.cs | 0 src/ImageSharp/Image/IImageFrame.cs | 32 ------------------- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 10 ++++-- 4 files changed, 7 insertions(+), 35 deletions(-) rename src/ImageSharp/{Image => }/ICloningImageProcessor.cs (100%) rename src/ImageSharp/{Image => }/IImageProcessor.cs (100%) delete mode 100644 src/ImageSharp/Image/IImageFrame.cs diff --git a/src/ImageSharp/Image/ICloningImageProcessor.cs b/src/ImageSharp/ICloningImageProcessor.cs similarity index 100% rename from src/ImageSharp/Image/ICloningImageProcessor.cs rename to src/ImageSharp/ICloningImageProcessor.cs diff --git a/src/ImageSharp/Image/IImageProcessor.cs b/src/ImageSharp/IImageProcessor.cs similarity index 100% rename from src/ImageSharp/Image/IImageProcessor.cs rename to src/ImageSharp/IImageProcessor.cs diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs deleted file mode 100644 index a495b5ed8c..0000000000 --- a/src/ImageSharp/Image/IImageFrame.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.MetaData; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp -{ - /// - /// Encapsulates the basic properties and methods required to manipulate images. - /// - public interface IImageFrame : IDisposable - { - /// - /// Gets the meta data of the image. - /// - ImageFrameMetaData MetaData { get; } - - /// - /// Gets the width. - /// - int Width { get; } - - /// - /// Gets the height. - /// - int Height { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index bb00ebf115..421750d226 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp /// Represents a single frame in a animation. /// /// The pixel format. - public sealed class ImageFrame : IImageFrame, IPixelSource + public sealed class ImageFrame : IPixelSource, IDisposable where TPixel : struct, IPixel { /// @@ -67,10 +67,14 @@ namespace SixLabors.ImageSharp /// Buffer2D IPixelSource.PixelBuffer => this.pixelBuffer; - /// + /// + /// Gets the width. + /// public int Width => this.pixelBuffer.Width; - /// + /// + /// Gets the height. + /// public int Height => this.pixelBuffer.Height; /// From bd0d188997c3746ee4ac251eb01c2afd371e7959 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 6 Sep 2017 22:38:30 +0200 Subject: [PATCH 11/24] Minor refactor. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 3da43967fe..fe1e4d83e2 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -122,10 +122,8 @@ namespace SixLabors.ImageSharp.Formats.Gif this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count); } - // ReSharper disable once ForCanBeConvertedToForeach - for (int i = 0; i < image.Frames.Count; i++) + foreach (ImageFrame frame in image.Frames) { - ImageFrame frame = image.Frames[i]; if (quantized == null) { quantized = ditheredQuantizer.Quantize(frame, paletteSize); From cd75248320449096701601c3282cef23298f47ee Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 6 Sep 2017 22:52:14 +0200 Subject: [PATCH 12/24] Added new extension method for IConfigurable to get the configuration and remove the one from Image. --- src/ImageSharp/Advanced/IConfigurable.cs | 8 +------- .../Advanced/IConfigurableExtensions.cs | 19 +++++++++++++++++++ src/ImageSharp/Advanced/ImageExtensions.cs | 18 ------------------ src/ImageSharp/ApplyProcessors.cs | 8 ++++---- src/ImageSharp/Formats/Bmp/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 2 +- .../Formats/Jpeg/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/Png/ImageExtensions.cs | 2 +- src/ImageSharp/Image/ImageExtensions.cs | 14 +++++++------- .../Processors/CloningImageProcessor.cs | 2 +- .../Processing/Processors/ImageProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- src/ImageSharp/Quantizers/Quantize.cs | 2 +- tests/ImageSharp.Tests/TestFile.cs | 2 +- 14 files changed, 40 insertions(+), 45 deletions(-) create mode 100644 src/ImageSharp/Advanced/IConfigurableExtensions.cs diff --git a/src/ImageSharp/Advanced/IConfigurable.cs b/src/ImageSharp/Advanced/IConfigurable.cs index 347bc9253b..fd97ae921a 100644 --- a/src/ImageSharp/Advanced/IConfigurable.cs +++ b/src/ImageSharp/Advanced/IConfigurable.cs @@ -1,12 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.MetaData; -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp.Advanced { /// @@ -15,7 +9,7 @@ namespace SixLabors.ImageSharp.Advanced internal interface IConfigurable { /// - /// Gets the pixel buffer. + /// Gets the configuration. /// Configuration Configuration { get; } } diff --git a/src/ImageSharp/Advanced/IConfigurableExtensions.cs b/src/ImageSharp/Advanced/IConfigurableExtensions.cs new file mode 100644 index 0000000000..e4257ccc2f --- /dev/null +++ b/src/ImageSharp/Advanced/IConfigurableExtensions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Advanced +{ + /// + /// Extension methods over + /// + internal static partial class IConfigurableExtensions + { + /// + /// Gets the configuration. + /// + /// The configurable + /// Returns the configuration. + public static Configuration GetConfiguration(this IConfigurable self) + => self?.Configuration ?? Configuration.Default; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index 135acefa48..ea7bb53497 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -73,23 +73,5 @@ namespace SixLabors.ImageSharp.Advanced private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel => source.Span.Slice(row * source.Width, source.Width); - - /// - /// Gets the bounds of the image. - /// - /// The Pixel format. - /// The source image - /// Returns the bounds of the image - public static Configuration Configuration(this Image source) - where TPixel : struct, IPixel - => GetConfiguration(source); - - /// - /// Gets the bounds of the image. - /// - /// The source image - /// Returns the bounds of the image - private static Configuration GetConfiguration(IConfigurable source) - => source?.Configuration ?? SixLabors.ImageSharp.Configuration.Default; } } diff --git a/src/ImageSharp/ApplyProcessors.cs b/src/ImageSharp/ApplyProcessors.cs index 3184bc592b..58a952c406 100644 --- a/src/ImageSharp/ApplyProcessors.cs +++ b/src/ImageSharp/ApplyProcessors.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operation, nameof(operation)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, true); operation(operationsRunner); operationsRunner.Apply(); } @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operations, nameof(operations)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, true); + IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, true); operationsRunner.ApplyProcessors(operations); operationsRunner.Apply(); } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operation, nameof(operation)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, false); operation(operationsRunner); return operationsRunner.Apply(); } @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp Guard.NotNull(operations, nameof(operations)); Guard.NotNull(source, nameof(source)); - IInternalImageProcessingContext operationsRunner = source.Configuration().ImageOperationsProvider.CreateImageProcessingContext(source, false); + IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, false); operationsRunner.ApplyProcessors(operations); return operationsRunner.Apply(); } diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs index 3bcbed49ad..935ce8f4ad 100644 --- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs @@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Bmp)); + => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Bmp)); } } diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 8174ec6f47..939eb456e1 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Gif)); + => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Gif)); } } diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index bc87b3a1bd..9cd7b3a8bd 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -36,6 +36,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Jpeg)); + => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Jpeg)); } } diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index e237d6a4e1..10970fc16a 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.Configuration().FindEncoder(ImageFormats.Png)); + => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Png)); } } diff --git a/src/ImageSharp/Image/ImageExtensions.cs b/src/ImageSharp/Image/ImageExtensions.cs index d1798abf3e..377dc2580b 100644 --- a/src/ImageSharp/Image/ImageExtensions.cs +++ b/src/ImageSharp/Image/ImageExtensions.cs @@ -32,12 +32,12 @@ namespace SixLabors.ImageSharp Guard.NotNullOrEmpty(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath).Trim('.'); - IImageFormat format = source.Configuration().FindFormatByFileExtension(ext); + IImageFormat format = source.GetConfiguration().FindFormatByFileExtension(ext); if (format == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); - foreach (IImageFormat fmt in source.Configuration().ImageFormats) + foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats) { stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}"); } @@ -45,13 +45,13 @@ namespace SixLabors.ImageSharp throw new NotSupportedException(stringBuilder.ToString()); } - IImageEncoder encoder = source.Configuration().FindEncoder(format); + IImageEncoder encoder = source.GetConfiguration().FindEncoder(format); if (encoder == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); - foreach (KeyValuePair enc in source.Configuration().ImageEncoders) + foreach (KeyValuePair enc in source.GetConfiguration().ImageEncoders) { stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}"); } @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { Guard.NotNull(encoder, nameof(encoder)); - using (Stream fs = source.Configuration().FileSystem.Create(filePath)) + using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath)) { source.Save(fs, encoder); } @@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { Guard.NotNull(format, nameof(format)); - IImageEncoder encoder = source.Configuration().FindEncoder(format); + IImageEncoder encoder = source.GetConfiguration().FindEncoder(format); if (encoder == null) { var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:"); - foreach (KeyValuePair val in source.Configuration().ImageEncoders) + foreach (KeyValuePair val in source.GetConfiguration().ImageEncoders) { stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}"); } diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index 176266ca6e..fdd7ae17cd 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } - var configuration = source.Configuration(); + var configuration = source.GetConfiguration(); this.BeforeImageApply(source, clone, sourceRectangle); for (int i = 0; i < source.Frames.Count; i++) diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 4799b09951..993bbe54b8 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing { try { - var config = source.Configuration(); + var config = source.GetConfiguration(); this.BeforeImageApply(source, sourceRectangle); foreach (ImageFrame sourceFrame in source.Frames) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 5dfa343caa..05c70b75e8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Processing.Processors /// protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { - Configuration config = source.Configuration(); + Configuration config = source.GetConfiguration(); // We will always be creating the clone even for mutate because thats the way this base processor works // ------------ diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index d9c3c84cd2..049090f432 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp Parallel.For( 0, pixels.Height, - img.Configuration().ParallelOptions, + img.GetConfiguration().ParallelOptions, y => { for (int x = 0; x < pixels.Width; x++) diff --git a/tests/ImageSharp.Tests/TestFile.cs b/tests/ImageSharp.Tests/TestFile.cs index e77b95f9ee..b736dce207 100644 --- a/tests/ImageSharp.Tests/TestFile.cs +++ b/tests/ImageSharp.Tests/TestFile.cs @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.Tests /// public Image CreateImage(IImageDecoder decoder) { - return ImageSharp.Image.Load(this.Image.Configuration(), this.Bytes, decoder); + return ImageSharp.Image.Load(this.Image.GetConfiguration(), this.Bytes, decoder); } } } From 10926cc05e78997c796efbd93455532673457a9c Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 6 Sep 2017 22:54:46 +0200 Subject: [PATCH 13/24] Silence warnings. --- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 +- .../Processing/Processors/CloningImageProcessor.cs | 2 +- src/ImageSharp/Processing/Processors/ImageProcessor.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 2c3bb29299..ccf46a17d6 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Gif public void Encode(Image image, Stream stream) where TPixel : struct, IPixel { - GifEncoderCore encoder = new GifEncoderCore(this); + var encoder = new GifEncoderCore(this); encoder.Encode(image, stream); } } diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index fdd7ae17cd..fdee21ed6a 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Processing throw new ImageProcessingException($"An error occured when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } - var configuration = source.GetConfiguration(); + Configuration configuration = source.GetConfiguration(); this.BeforeImageApply(source, clone, sourceRectangle); for (int i = 0; i < source.Frames.Count; i++) diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 993bbe54b8..cab99112c1 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Processing { try { - var config = source.GetConfiguration(); + Configuration config = source.GetConfiguration(); this.BeforeImageApply(source, sourceRectangle); foreach (ImageFrame sourceFrame in source.Frames) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5380807562..1566ddf442 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -28,10 +28,10 @@ namespace SixLabors.ImageSharp.Tests { using (Image image = provider.GetImage()) { - PngEncoder options = new PngEncoder() - { - PngColorType = pngColorType - }; + var options = new PngEncoder() + { + PngColorType = pngColorType + }; provider.Utility.TestName += "_" + pngColorType; provider.Utility.SaveTestOutputFile(image, "png", options); @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests where TPixel : struct, IPixel { using (Image image = provider.GetImage()) - using (MemoryStream ms = new MemoryStream()) + using (var ms = new MemoryStream()) { image.Save(ms, new PngEncoder()); From 46cf55094c8a030c3590f27dc782c4e6a9c6926f Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 6 Sep 2017 23:03:06 +0200 Subject: [PATCH 14/24] Move extension method back to Image to keep it public. --- .../Advanced/IConfigurableExtensions.cs | 19 ------------------- src/ImageSharp/Advanced/ImageExtensions.cs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 19 deletions(-) delete mode 100644 src/ImageSharp/Advanced/IConfigurableExtensions.cs diff --git a/src/ImageSharp/Advanced/IConfigurableExtensions.cs b/src/ImageSharp/Advanced/IConfigurableExtensions.cs deleted file mode 100644 index e4257ccc2f..0000000000 --- a/src/ImageSharp/Advanced/IConfigurableExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.Advanced -{ - /// - /// Extension methods over - /// - internal static partial class IConfigurableExtensions - { - /// - /// Gets the configuration. - /// - /// The configurable - /// Returns the configuration. - public static Configuration GetConfiguration(this IConfigurable self) - => self?.Configuration ?? Configuration.Default; - } -} \ No newline at end of file diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index ea7bb53497..727c73e837 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -38,6 +38,16 @@ namespace SixLabors.ImageSharp.Advanced where TPixel : struct, IPixel => GetSpan(source, row); + /// + /// Gets the configuration. + /// + /// The Pixel format. + /// The source image + /// Returns the configuration. + public static Configuration GetConfiguration(this Image source) + where TPixel : struct, IPixel + => GetConfiguration(source); + /// /// Gets the span. /// @@ -73,5 +83,13 @@ namespace SixLabors.ImageSharp.Advanced private static Span GetSpan(Buffer2D source, int row) where TPixel : struct, IPixel => source.Span.Slice(row * source.Width, source.Width); + + /// + /// Gets the configuration. + /// + /// The source image + /// Returns the bounds of the image + private static Configuration GetConfiguration(IConfigurable source) + => source?.Configuration ?? Configuration.Default; } } From 53e1741ab556bea07f7e408387a5f38057f6756f Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Wed, 6 Sep 2017 23:14:09 +0200 Subject: [PATCH 15/24] Minor refactor and added Guard for null image. --- src/ImageSharp/Image/ImageFrameCollection.cs | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index bfd8e5e91d..466e2ec392 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -91,17 +91,6 @@ namespace SixLabors.ImageSharp this.frames.Add(frame); } - private void ValidateFrameSize(ImageFrame frame) - { - if (this.Count != 0) - { - if (this.RootFrame.Width != frame.Width || this.RootFrame.Height != frame.Height) - { - throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); - } - } - } - /// /// Determines whether the contains the . /// @@ -122,7 +111,7 @@ namespace SixLabors.ImageSharp /// Cannot remove last frame public bool Remove(ImageFrame frame) { - if (this.frames.Count == 1 && this.frames.Contains(frame)) + if (this.Count == 1 && this.frames.Contains(frame)) { throw new InvalidOperationException("Cannot remove last frame"); } @@ -135,5 +124,18 @@ namespace SixLabors.ImageSharp /// IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.frames).GetEnumerator(); + + private void ValidateFrameSize(ImageFrame frame) + { + Guard.NotNull(frame, nameof(frame)); + + if (this.Count != 0) + { + if (this.RootFrame.Width != frame.Width || this.RootFrame.Height != frame.Height) + { + throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); + } + } + } } } \ No newline at end of file From b7087736c7a40efc72b5f29eff1f0f639df75f29 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Sep 2017 20:16:33 +1000 Subject: [PATCH 16/24] Fix recursion plus cleanup --- src/ImageSharp/Advanced/ImageExtensions.cs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index 727c73e837..243745c9b2 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -2,20 +2,15 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Advanced { /// /// Extension methods over Image{TPixel} /// - public static partial class ImageExtensions + public static class ImageExtensions { /// /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. @@ -28,7 +23,7 @@ namespace SixLabors.ImageSharp.Advanced => GetSpan(source); /// - /// Gets a representing the row 'y' beginning from the the first pixel on that row. + /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. /// /// The type of the pixel. /// The source. @@ -39,17 +34,17 @@ namespace SixLabors.ImageSharp.Advanced => GetSpan(source, row); /// - /// Gets the configuration. + /// Gets the configuration for the image. /// /// The Pixel format. /// The source image /// Returns the configuration. public static Configuration GetConfiguration(this Image source) where TPixel : struct, IPixel - => GetConfiguration(source); + => GetConfiguration((IConfigurable)source); /// - /// Gets the span. + /// Gets the span to the backing buffer. /// /// The type of the pixel. /// The source. @@ -59,7 +54,7 @@ namespace SixLabors.ImageSharp.Advanced => source.PixelBuffer.Span; /// - /// Gets the span. + /// Gets the span to the backing buffer at the given row. /// /// The type of the pixel. /// The source. @@ -72,7 +67,7 @@ namespace SixLabors.ImageSharp.Advanced => GetSpan(source.PixelBuffer, row); /// - /// Gets the span. + /// Gets the span to the backing buffer at the given row. /// /// The type of the pixel. /// The source. From 13b19b9c21d99a484bbcc0959bee838992fd5ded Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Sep 2017 20:31:26 +1000 Subject: [PATCH 17/24] Adjust for new frame cont in Gif encoder --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index fe1e4d83e2..56eb7b2baa 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -90,11 +90,11 @@ namespace SixLabors.ImageSharp.Formats.Gif var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that pallete size can be set but has a fallback. - int paletteSize = this.paletteSize; - paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256; + int size = this.paletteSize; + size = size > 0 ? size.Clamp(1, 256) : 256; // Get the number of bits. - this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize); + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(size); this.hasFrames = image.Frames.Count > 1; @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.Formats.Gif ditheredQuantizer.Dither = !this.hasFrames; // Quantize the image returning a palette. - QuantizedImage quantized = ditheredQuantizer.Quantize(image.Frames.RootFrame, paletteSize); + QuantizedImage quantized = ditheredQuantizer.Quantize(image.Frames.RootFrame, size); int index = this.GetTransparentIndex(quantized); @@ -119,14 +119,14 @@ namespace SixLabors.ImageSharp.Formats.Gif // Write additional frames. if (this.hasFrames) { - this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count); + this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count - 1); } - foreach (ImageFrame frame in image.Frames) + foreach (ImageFrame frame in image.Frames.Skip(1)) { if (quantized == null) { - quantized = ditheredQuantizer.Quantize(frame, paletteSize); + quantized = ditheredQuantizer.Quantize(frame, size); } this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantized)); From 3eb75e6ef8a32a655d61d0538cee03f182afe1e2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Sep 2017 20:44:12 +1000 Subject: [PATCH 18/24] Undo my silliness --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 56eb7b2baa..d143cd5319 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -119,10 +119,10 @@ namespace SixLabors.ImageSharp.Formats.Gif // Write additional frames. if (this.hasFrames) { - this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count - 1); + this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count); } - foreach (ImageFrame frame in image.Frames.Skip(1)) + foreach (ImageFrame frame in image.Frames) { if (quantized == null) { From 41358ce077a32dda3882acd51e357859caf74ecd Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 9 Sep 2017 11:09:43 +0100 Subject: [PATCH 19/24] FrameCollection responsible for adding initial frame --- src/ImageSharp/Image/ImageFrameCollection.cs | 45 +++- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 6 +- src/ImageSharp/Image/Image{TPixel}.cs | 32 +-- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Image/ImageFramesCollectionTests.cs | 219 ++++++++++++++++++ 5 files changed, 266 insertions(+), 38 deletions(-) create mode 100644 tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index 466e2ec392..b8b46c88b2 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -13,11 +13,25 @@ namespace SixLabors.ImageSharp /// Encapsulates an imaged collection of frames. /// /// The type of the pixel. - public sealed class ImageFrameCollection : IEnumerable> + public sealed class ImageFrameCollection : IEnumerable>, IDisposable where TPixel : struct, IPixel { private readonly IList> frames = new List>(); + internal ImageFrameCollection(int width, int height) + { + this.Add(new ImageFrame(width, height)); + } + + internal ImageFrameCollection(IEnumerable> frames) + { + Guard.NotNullOrEmpty(frames, nameof(frames)); + foreach (ImageFrame f in frames) + { + this.Add(f); + } + } + /// /// Gets the count. /// @@ -42,7 +56,7 @@ namespace SixLabors.ImageSharp set { - this.ValidateFrameSize(value); + this.ValidateFrame(value); this.frames[index] = value; } } @@ -61,7 +75,7 @@ namespace SixLabors.ImageSharp /// The to insert into the . public void Insert(int index, ImageFrame frame) { - this.ValidateFrameSize(frame); + this.ValidateFrame(frame); this.frames.Insert(index, frame); } @@ -72,12 +86,12 @@ namespace SixLabors.ImageSharp /// Cannot remove last frame. public void RemoveAt(int index) { - if (index > 0 || this.frames.Count > 1) + if (index == 0 && this.Count == 1) { - this.frames.RemoveAt(index); + throw new InvalidOperationException("Cannot remove last frame."); } - throw new InvalidOperationException("Cannot remove last frame."); + this.frames.RemoveAt(index); } /// @@ -87,7 +101,7 @@ namespace SixLabors.ImageSharp /// Frame must have the same dimensions as the image - frame public void Add(ImageFrame frame) { - this.ValidateFrameSize(frame); + this.ValidateFrame(frame); this.frames.Add(frame); } @@ -113,7 +127,7 @@ namespace SixLabors.ImageSharp { if (this.Count == 1 && this.frames.Contains(frame)) { - throw new InvalidOperationException("Cannot remove last frame"); + throw new InvalidOperationException("Cannot remove last frame."); } return this.frames.Remove(frame); @@ -125,7 +139,7 @@ namespace SixLabors.ImageSharp /// IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.frames).GetEnumerator(); - private void ValidateFrameSize(ImageFrame frame) + private void ValidateFrame(ImageFrame frame) { Guard.NotNull(frame, nameof(frame)); @@ -133,9 +147,20 @@ namespace SixLabors.ImageSharp { if (this.RootFrame.Width != frame.Width || this.RootFrame.Height != frame.Height) { - throw new ArgumentException("Frame must have the same dimensions as the image", nameof(frame)); + throw new ArgumentException("Frame must have the same dimensions as the image.", nameof(frame)); } } } + + /// + public void Dispose() + { + foreach (ImageFrame f in this.frames) + { + f.Dispose(); + } + + this.frames.Clear(); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index 421750d226..fc6da8b89b 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp /// private Buffer2D pixelBuffer; - private bool isDisposed = false; + private bool isDisosed = false; /// /// Initializes a new instance of the class. @@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp /// public void Dispose() { - if (this.isDisposed) + if (this.isDisosed) { return; } @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp this.pixelBuffer = null; // Note disposing is done. - this.isDisposed = true; + this.isDisosed = true; } /// diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index f228d766d1..36335b71b6 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -58,8 +58,10 @@ namespace SixLabors.ImageSharp /// The height of the image in pixels. /// The images metadata. internal Image(Configuration configuration, int width, int height, ImageMetaData metadata) - : this(configuration, width, height, metadata, null) { + this.configuration = configuration ?? Configuration.Default; + this.MetaData = metadata ?? new ImageMetaData(); + this.Frames = new ImageFrameCollection(width, height); } /// @@ -67,29 +69,14 @@ namespace SixLabors.ImageSharp /// with the height and the width of the image. /// /// The configuration providing initialization code which allows extending the library. - /// The width of the image in pixels. - /// The height of the image in pixels. /// The images metadata. /// The frames that will be owned by this image instance. - internal Image(Configuration configuration, int width, int height, ImageMetaData metadata, IEnumerable> frames) + internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable> frames) { this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.Frames = new ImageFrameCollection(); - - if (frames != null) - { - foreach (ImageFrame f in frames) - { - this.Frames.Add(f); - } - } - - if (this.Frames.Count == 0) - { - this.Frames.Add(new ImageFrame(width, height)); - } + this.Frames = new ImageFrameCollection(frames); } /// @@ -157,7 +144,7 @@ namespace SixLabors.ImageSharp { IEnumerable> frames = this.Frames.Select(x => x.Clone()).ToArray(); - return new Image(this.configuration, this.Width, this.Height, this.MetaData.Clone(), frames); + return new Image(this.configuration, this.MetaData.Clone(), frames); } /// @@ -175,7 +162,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> frames = this.Frames.Select(x => x.CloneAs()).ToArray(); - var target = new Image(this.configuration, this.Width, this.Height, this.MetaData, frames); + var target = new Image(this.configuration, this.MetaData, frames); return target; } @@ -185,10 +172,7 @@ namespace SixLabors.ImageSharp /// public void Dispose() { - for (int i = 0; i < this.Frames.Count; i++) - { - this.Frames[i].Dispose(); - } + this.Frames.Dispose(); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 05c70b75e8..a4fdb1a1b4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors // For resize we know we are going to populate every pixel with fresh data and we want a different target size so // let's manually clone an empty set of images at the correct target and then have the base class processs them in turn. IEnumerable> frames = source.Frames.Select(x => new ImageFrame(this.Width, this.Height, x.MetaData.Clone())); // this will create places holders - var image = new Image(config, this.Width, this.Height, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added + var image = new Image(config, source.MetaData.Clone(), frames); // base the place holder images in to prevet a extra frame being added return image; } diff --git a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs new file mode 100644 index 0000000000..acd1eec202 --- /dev/null +++ b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using SixLabors.ImageSharp.Advanced; +using Xunit; + +namespace SixLabors.ImageSharp.Tests +{ + public class ImageFramesCollectionTests + { + [Fact] + public void ImageFramesaLwaysHaveOneFrame() + { + var collection = new ImageFrameCollection(10, 10); + Assert.Equal(1, collection.Count); + } + + [Fact] + public void AddNewFrame_FramesMustHaveSameSize() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentException ex = Assert.Throws(() => + { + collection.Add(new ImageFrame(1, 1)); + }); + + Assert.Equal("Frame must have the same dimensions as the image.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void AddNewFrame_FramesNotBeNull() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentNullException ex = Assert.Throws(() => + { + collection.Add(null); + }); + + Assert.Equal("Value cannot be null.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void InsertNewFrame_FramesMustHaveSameSize() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentException ex = Assert.Throws(() => + { + collection.Insert(1, new ImageFrame(1, 1)); + }); + + Assert.Equal("Frame must have the same dimensions as the image.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void InsertNewFrame_FramesNotBeNull() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentNullException ex = Assert.Throws(() => + { + collection.Insert(1, null); + }); + + Assert.Equal("Value cannot be null.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void SetFrameAtIndex_FramesMustHaveSameSize() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentException ex = Assert.Throws(() => + { + collection[0] = new ImageFrame(1, 1); + }); + + Assert.Equal("Frame must have the same dimensions as the image.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void SetFrameAtIndex_FramesNotBeNull() + { + var collection = new ImageFrameCollection(10, 10); + + ArgumentNullException ex = Assert.Throws(() => + { + collection[0] = null; + }); + + Assert.Equal("Value cannot be null.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void Constructor_FramesMustHaveSameSize() + { + + ArgumentException ex = Assert.Throws(() => + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(1,1), + }); + }); + + Assert.Equal("Frame must have the same dimensions as the image.\r\nParameter name: frame", ex.Message); + } + + [Fact] + public void RemoveAtFrame_ThrowIfRemovingLastFrame() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10) + }); + + InvalidOperationException ex = Assert.Throws(() => + { + collection.RemoveAt(0); + }); + Assert.Equal("Cannot remove last frame.", ex.Message); + } + + [Fact] + public void RemoveAtFrame_CanRemoveFrameZeroIfMultipleFramesExist() + { + + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + collection.RemoveAt(0); + Assert.Equal(1, collection.Count); + } + + [Fact] + public void RemoveFrame_ThrowIfRemovingLastFrame() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10) + }); + + InvalidOperationException ex = Assert.Throws(() => + { + collection.Remove(collection[0]); + }); + Assert.Equal("Cannot remove last frame.", ex.Message); + } + + [Fact] + public void RemoveFrame_CanRemoveFrameZeroIfMultipleFramesExist() + { + + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + collection.Remove(collection[0]); + Assert.Equal(1, collection.Count); + } + + [Fact] + public void RootFrameIsFrameAtIndexZero() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + Assert.Equal(collection.RootFrame, collection[0]); + } + + [Fact] + public void ConstructorPopulatesFrames() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + Assert.Equal(2, collection.Count); + } + + [Fact] + public void DisposeClearsCollection() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + collection.Dispose(); + + Assert.Equal(0, collection.Count); + } + + [Fact] + public void Dispose_DisposesAllInnerFrames() + { + var collection = new ImageFrameCollection(new[] { + new ImageFrame(10,10), + new ImageFrame(10,10), + }); + + IPixelSource[] framesSnapShot = collection.OfType>().ToArray(); + collection.Dispose(); + + Assert.All(framesSnapShot, f => + { + // the pixel source of the frame is null after its been disposed. + Assert.Null(f.PixelBuffer); + }); + } + } +} From 176920a1802a6740d926acaf01280d849c13f022 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 9 Sep 2017 11:11:39 +0100 Subject: [PATCH 20/24] expose span APIs on image --- src/ImageSharp/Advanced/ImageExtensions.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs index 243745c9b2..4369cf67a6 100644 --- a/src/ImageSharp/Advanced/ImageExtensions.cs +++ b/src/ImageSharp/Advanced/ImageExtensions.cs @@ -33,6 +33,27 @@ namespace SixLabors.ImageSharp.Advanced where TPixel : struct, IPixel => GetSpan(source, row); + /// + /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format. + /// + /// The type of the pixel. + /// The source. + /// The + public static Span GetPixelSpan(this Image source) + where TPixel : struct, IPixel + => source.Frames.RootFrame.GetPixelSpan(); + + /// + /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row. + /// + /// The type of the pixel. + /// The source. + /// The row. + /// The + public static Span GetPixelRowSpan(this Image source, int row) + where TPixel : struct, IPixel + => source.Frames.RootFrame.GetPixelRowSpan(row); + /// /// Gets the configuration for the image. /// From 22d51633ad37d16f767cdf81fcf1fac23e4e5974 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 10 Sep 2017 20:27:35 +1000 Subject: [PATCH 21/24] Fix spelling --- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index fc6da8b89b..e950b28a5c 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp /// private Buffer2D pixelBuffer; - private bool isDisosed = false; + private bool isDisposed; /// /// Initializes a new instance of the class. @@ -180,7 +180,7 @@ namespace SixLabors.ImageSharp /// public void Dispose() { - if (this.isDisosed) + if (this.isDisposed) { return; } @@ -189,7 +189,7 @@ namespace SixLabors.ImageSharp this.pixelBuffer = null; // Note disposing is done. - this.isDisosed = true; + this.isDisposed = true; } /// From 2dc3c4f5195ba77f5b43392f4df96aa48b09284e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 10 Sep 2017 20:30:58 +1000 Subject: [PATCH 22/24] Remove unused local variables --- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 2 -- src/ImageSharp/Image/Image{TPixel}.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index e950b28a5c..c4b6562976 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -166,8 +166,6 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - int newWidth = pixelSource.Width; - int newHeight = pixelSource.Height; Buffer2D newPixels = pixelSource.pixelBuffer; pixelSource.pixelBuffer = this.pixelBuffer; diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 36335b71b6..8da19469e5 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -183,8 +183,6 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - int newHeight = pixelSource.Height; - for (int i = 0; i < this.Frames.Count; i++) { this.Frames[i].SwapPixelsBuffers(pixelSource.Frames[i]); From 19b45049f4e7313c718d9f5d88e73c8185439df3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 10 Sep 2017 20:34:41 +1000 Subject: [PATCH 23/24] Reuse comparable swap --- src/ImageSharp/Image/ImageFrame{TPixel}.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index c4b6562976..73e3a80aef 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -166,11 +166,7 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - Buffer2D newPixels = pixelSource.pixelBuffer; - - pixelSource.pixelBuffer = this.pixelBuffer; - - this.pixelBuffer = newPixels; + ComparableExtensions.Swap(ref this.pixelBuffer, ref pixelSource.pixelBuffer); } /// From db80a7ff61056aa49e6842b6bb39ac8b82624ea3 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Tue, 12 Sep 2017 08:08:40 +0100 Subject: [PATCH 24/24] introduce IImageFrameCollectino to hide disposable --- src/ImageSharp/Image/IImageFrameCollection.cs | 84 +++++++++++++++++++ src/ImageSharp/Image/ImageFrameCollection.cs | 2 +- src/ImageSharp/Image/Image{TPixel}.cs | 23 ++--- 3 files changed, 97 insertions(+), 12 deletions(-) create mode 100644 src/ImageSharp/Image/IImageFrameCollection.cs diff --git a/src/ImageSharp/Image/IImageFrameCollection.cs b/src/ImageSharp/Image/IImageFrameCollection.cs new file mode 100644 index 0000000000..ee325bc632 --- /dev/null +++ b/src/ImageSharp/Image/IImageFrameCollection.cs @@ -0,0 +1,84 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections; +using System.Collections.Generic; + +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp +{ + /// + /// Encapsulates an imaged collection of frames. + /// + /// The type of the pixel. + public interface IImageFrameCollection : IEnumerable> + where TPixel : struct, IPixel + { + /// + /// Gets the count. + /// + int Count { get; } + + /// + /// Gets the root frame. + /// + ImageFrame RootFrame { get; } + + /// + /// Gets or sets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// The at the specified index. + ImageFrame this[int index] { get; set; } + + /// + /// Determines the index of a specific in the . + /// + /// The to locate in the . + /// The index of item if found in the list; otherwise, -1. + int IndexOf(ImageFrame frame); + + /// + /// Inserts the to the at the specified . + /// + /// The zero-based index at which item should be inserted.. + /// The to insert into the . + void Insert(int index, ImageFrame frame); + + /// + /// Removes the from the at the specified index. + /// + /// The zero-based index of the item to remove. + /// Cannot remove last frame. + void RemoveAt(int index); + + /// + /// Adds the specified frame. + /// + /// The frame. + /// Frame must have the same dimensions as the image - frame + void Add(ImageFrame frame); + + /// + /// Determines whether the contains the . + /// + /// The frame. + /// + /// true if the the specified frame; otherwise, false. + /// + bool Contains(ImageFrame frame); + + /// + /// Removes the specified frame. + /// + /// The frame. + /// true if item is found in the ; otherwise, + /// Cannot remove last frame + bool Remove(ImageFrame frame); + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index b8b46c88b2..25c0d0c449 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp /// Encapsulates an imaged collection of frames. /// /// The type of the pixel. - public sealed class ImageFrameCollection : IEnumerable>, IDisposable + internal sealed class ImageFrameCollection : IImageFrameCollection, IDisposable where TPixel : struct, IPixel { private readonly IList> frames = new List>(); diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index 8da19469e5..5c35d854a3 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -21,6 +21,7 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { private Configuration configuration; + private ImageFrameCollection frames; /// /// Initializes a new instance of the class @@ -61,7 +62,7 @@ namespace SixLabors.ImageSharp { this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.Frames = new ImageFrameCollection(width, height); + this.frames = new ImageFrameCollection(width, height); } /// @@ -76,7 +77,7 @@ namespace SixLabors.ImageSharp this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.Frames = new ImageFrameCollection(frames); + this.frames = new ImageFrameCollection(frames); } /// @@ -87,12 +88,12 @@ namespace SixLabors.ImageSharp /// /// Gets the width. /// - public int Width => this.Frames.RootFrame.Width; + public int Width => this.frames.RootFrame.Width; /// /// Gets the height. /// - public int Height => this.Frames.RootFrame.Height; + public int Height => this.frames.RootFrame.Height; /// /// Gets the meta data of the image. @@ -102,12 +103,12 @@ namespace SixLabors.ImageSharp /// /// Gets the frames. /// - public ImageFrameCollection Frames { get; private set; } + public IImageFrameCollection Frames => this.frames; /// /// Gets the root frame. /// - private IPixelSource PixelSource => this.Frames?.RootFrame; + private IPixelSource PixelSource => this.frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image)); /// /// Gets or sets the pixel at the specified position. @@ -142,7 +143,7 @@ namespace SixLabors.ImageSharp /// Returns a new image with all the same metadata as the original. public Image Clone() { - IEnumerable> frames = this.Frames.Select(x => x.Clone()).ToArray(); + IEnumerable> frames = this.frames.Select(x => x.Clone()).ToArray(); return new Image(this.configuration, this.MetaData.Clone(), frames); } @@ -161,7 +162,7 @@ namespace SixLabors.ImageSharp public Image CloneAs() where TPixel2 : struct, IPixel { - IEnumerable> frames = this.Frames.Select(x => x.CloneAs()).ToArray(); + IEnumerable> frames = this.frames.Select(x => x.CloneAs()).ToArray(); var target = new Image(this.configuration, this.MetaData, frames); return target; @@ -172,7 +173,7 @@ namespace SixLabors.ImageSharp /// public void Dispose() { - this.Frames.Dispose(); + this.frames.Dispose(); } /// @@ -183,9 +184,9 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - for (int i = 0; i < this.Frames.Count; i++) + for (int i = 0; i < this.frames.Count; i++) { - this.Frames[i].SwapPixelsBuffers(pixelSource.Frames[i]); + this.frames[i].SwapPixelsBuffers(pixelSource.frames[i]); } } }