diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs index 8b163d7f6..bb907281b 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 850775ce0..4cd3585ec 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 b1dab0ea9..844df0e0e 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 258d69721..ca6f7630d 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 bbd0e4d86..ba2fca4e4 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 27bce86bf..658164339 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 e1ce6b013..2a8e2cf4c 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 fbd965426..57c4e3d9b 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 3e0dedb3b..1022f6308 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 777cb76e2..000000000 --- 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 7377e6ca0..1bd7c0cc4 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 8cf220b30..2fda9341a 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 3fb86f192..510a097ea 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 850c978fe..c538d643c 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 e3c7c5cba..e0e11ad9e 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 6fa406bec..09c30eb27 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 12dd0f91a..6ac124362 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 cb124d305..8666dca7a 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 502267838..7b12b95b1 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 86d5f5375..e392cf7c6 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 57b29e8ab..52fc1c228 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 786f3fe90..739fd6051 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 dfc905bfa..6ca27d533 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 1e7d6e4f0..aeb3c815e 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 3223e20f7..000000000 --- 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 9aea1517d..000000000 --- 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 31a816588..244a60a89 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 b81f08e15..bd6df8d83 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 e9987e0c7..000000000 --- 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 6844bdc81..9c7b0962e 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 000000000..186f94762 --- /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 bd5e27261..cc5c8b1ac 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 900045dba..94d6ddb6a 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 000000000..3c90a55c9 --- /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 90908529f..0204c9e77 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 c4aa98d31..4a2ca3807 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 ba79d2a80..d2a68094e 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 2f76ecda5..c4499a372 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 a1fa3c9cb..1279792dc 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 c4da8dee7..b48da3a14 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 dcb5955c0..5c702af21 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 928a641a0..78e25c147 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 3c95d2997..75d134137 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 d109cb10e..37174c49d 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 08ea5a641..d6efce35b 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 fa1f18ea9..f2bc82f3b 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 af7a5e276..3198ae0a2 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 aa3c60535..86f33c345 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 b8e5106b7..d43ee6d64 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 583d38bf7..2a1da2938 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 e22904ae1..263abbdcf 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 e1bd8c526..7fc70bd79 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 5cdf63210..fbc5a15d7 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 da3b78c3f..9e4813f2b 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 2c96ddb11..8143d662e 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 d4ec49fd1..545363e27 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 35443fdd5..3fe179cd8 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 ab5588556..88b4a2bab 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 a7513d1cb..64522b67e 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 1a4d52d3e..ed1ec1c29 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 47ca3b135..eeb9ae8e8 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 bad6cbf41..7d3da8c89 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 76271529d..a84a7b189 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 1d0ab6d1f..4228bb34b 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 89e22a7e6..7ca7008a3 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 1cb92cca9..17ce08318 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 54724ee78..4a15254ab 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 8d5eeded1..708d7a273 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 57b9a81f9..a56afd450 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 5b8952dc8..be865be0a 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 85bf1b693..5d4578e8c 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 90f50ec3d..152b451e2 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 dc23eb4fb..826741d94 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 1e992c894..82f6146a3 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 77771c792..49adce23b 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 545004bc2..ca11a042f 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 ad166f606..26d37615b 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 48c4df5e4..7f58ff1bf 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 5955ec989..77c421468 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 1530905c7..64eb9e8b5 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 3fe7fe007..521d30fd9 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 4fabd6076..effebdecf 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 8a992b17d..aa61c7f5a 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 ab0ab287d..9688262d0 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 1b3ebf016..f4faa9456 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);