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