diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs
index 8b163d7f67..bb907281b0 100644
--- a/src/ImageSharp.Drawing/Brushes/IBrush.cs
+++ b/src/ImageSharp.Drawing/Brushes/IBrush.cs
@@ -32,6 +32,6 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// The when being applied to things like shapes would usually be the
/// bounding box of the shape not necessarily the bounds of the whole image
///
- BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options);
+ BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
index 850775ce05..4cd3585ec7 100644
--- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs
@@ -21,19 +21,19 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
///
/// The image to paint.
///
- private readonly ImageBase image;
+ private readonly ImageFrame image;
///
/// Initializes a new instance of the class.
///
/// The image.
- public ImageBrush(ImageBase image)
+ public ImageBrush(ImageFrame image)
{
this.image = image;
}
///
- public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
+ public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options)
{
return new ImageBrushApplicator(source, this.image, region, options);
}
@@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
///
/// The source image.
///
- private readonly ImageBase source;
+ private readonly ImageFrame source;
///
/// The y-length.
@@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// The image.
/// The region.
/// The options
- public ImageBrushApplicator(ImageBase target, ImageBase image, RectangleF region, GraphicsOptions options)
+ public ImageBrushApplicator(ImageFrame target, ImageFrame image, RectangleF region, GraphicsOptions options)
: base(target, options)
{
this.source = image;
diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
index b1dab0ea9c..844df0e0e9 100644
--- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs
@@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
}
///
- public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
+ public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options)
{
return new PatternBrushApplicator(source, this.pattern, this.patternVector, options);
}
@@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// The pattern.
/// The patternVector.
/// The options
- public PatternBrushApplicator(ImageBase source, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options)
+ public PatternBrushApplicator(ImageFrame source, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options)
: base(source, options)
{
this.pattern = pattern;
diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
index 258d69721c..ca6f7630d9 100644
--- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
+++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes.Processors
///
/// The target.
/// The options.
- internal BrushApplicator(ImageBase target, GraphicsOptions options)
+ internal BrushApplicator(ImageFrame target, GraphicsOptions options)
{
this.Target = target;
@@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes.Processors
///
/// Gets the destinaion
///
- protected ImageBase Target { get; }
+ protected ImageFrame Target { get; }
///
/// Gets the blend percentage
diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
index bbd0e4d864..ba2fca4e4b 100644
--- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
public TPixel TargeTPixel { get; }
///
- public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
+ public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options)
{
return new RecolorBrushApplicator(source, this.SourceColor, this.TargeTPixel, this.Threshold, options);
}
@@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// Color of the target.
/// The threshold .
/// The options
- public RecolorBrushApplicator(ImageBase source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options)
+ public RecolorBrushApplicator(ImageFrame source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options)
: base(source, options)
{
this.sourceColor = sourceColor.ToVector4();
diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
index 27bce86bfb..658164339d 100644
--- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs
@@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
public TPixel Color => this.color;
///
- public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
+ public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options)
{
return new SolidBrushApplicator(source, this.color, options);
}
@@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Drawing.Brushes
/// The source image.
/// The color.
/// The options
- public SolidBrushApplicator(ImageBase source, TPixel color, GraphicsOptions options)
+ public SolidBrushApplicator(ImageFrame source, TPixel color, GraphicsOptions options)
: base(source, options)
{
this.Colors = new Buffer(source.Width);
diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
index e1ce6b0133..213ab1b4a7 100644
--- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
@@ -4,6 +4,8 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -58,7 +60,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, Configuration configuration)
{
Image disposableImage = null;
Image targetImage = this.Image;
@@ -94,7 +96,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
Parallel.For(
minY,
maxY,
- source.Configuration.ParallelOptions,
+ configuration.ParallelOptions,
y =>
{
Span background = sourcePixels.GetRowSpan(y).Slice(minX, width);
diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs
index fbd9654262..679ca6a228 100644
--- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs
@@ -4,6 +4,7 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.Drawing.Brushes;
using SixLabors.ImageSharp.Drawing.Brushes.Processors;
@@ -39,7 +40,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
}
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
int startX = sourceRectangle.X;
int endX = sourceRectangle.Right;
@@ -65,9 +66,6 @@ namespace SixLabors.ImageSharp.Drawing.Processors
int width = maxX - minX;
- // We could possibly do some optimization by having knowledge about the individual brushes operate
- // for example If brush is SolidBrush then we could just get the color upfront
- // and skip using the IBrushApplicator?.
using (var amount = new Buffer(width))
using (BrushApplicator applicator = this.brush.CreateApplicator(source, sourceRectangle, this.options))
{
@@ -79,7 +77,7 @@ namespace SixLabors.ImageSharp.Drawing.Processors
Parallel.For(
minY,
maxY,
- source.Configuration.ParallelOptions,
+ configuration.ParallelOptions,
y =>
{
int offsetY = y - startY;
diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
index b9dd9a7b10..d867008d7e 100644
--- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
@@ -58,7 +58,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, Configuration configuration)
{
Region region = this.Region;
Rectangle rect = region.Bounds;
diff --git a/src/ImageSharp/Advanced/IConfigurable.cs b/src/ImageSharp/Advanced/IConfigurable.cs
new file mode 100644
index 0000000000..fd97ae921a
--- /dev/null
+++ b/src/ImageSharp/Advanced/IConfigurable.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Encapsulates the properties for configuration
+ ///
+ internal interface IConfigurable
+ {
+ ///
+ /// Gets the configuration.
+ ///
+ Configuration Configuration { get; }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Advanced/IPixelSource{TPixel}.cs b/src/ImageSharp/Advanced/IPixelSource.cs
similarity index 62%
rename from src/ImageSharp/Advanced/IPixelSource{TPixel}.cs
rename to src/ImageSharp/Advanced/IPixelSource.cs
index 777cb76e2e..c9edf118c6 100644
--- a/src/ImageSharp/Advanced/IPixelSource{TPixel}.cs
+++ b/src/ImageSharp/Advanced/IPixelSource.cs
@@ -2,20 +2,23 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Advanced
{
///
- /// Allows access to the pixels as an area of contiguous memory in the given pixel format.
+ /// Encapsulates the basic properties and methods required to manipulate images.
///
/// 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.
+ /// Gets the pixel buffer.
///
- Span Span { get; }
+ Buffer2D PixelBuffer { get; }
}
-}
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Advanced/ImageExtensions.cs b/src/ImageSharp/Advanced/ImageExtensions.cs
index ca2e522f59..f4043b5ade 100644
--- a/src/ImageSharp/Advanced/ImageExtensions.cs
+++ b/src/ImageSharp/Advanced/ImageExtensions.cs
@@ -2,19 +2,15 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Advanced
{
///
/// Extension methods over Image{TPixel}
///
- internal static partial class ImageExtensions
+ internal static class ImageExtensions
{
///
/// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
@@ -22,29 +18,94 @@ 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 a representing the row 'y' beginning from the the first pixel on that row.
+ /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
///
/// The type of the pixel.
/// The source.
/// The row.
/// The
- public static Span GetPixelRowSpan(this ImageBase source, int row)
+ public static Span GetPixelRowSpan(this ImageFrame source, int row)
where TPixel : struct, IPixel
- => GetSpan(source).Slice(row * source.Width, source.Width);
+ => GetSpan(source, row);
///
- /// Gets the span.
+ /// Gets the representation of the pixels as an area of contiguous memory in the given pixel format.
+ ///
+ /// The type of the pixel.
+ /// The source.
+ /// The
+ public static Span GetPixelSpan(this Image source)
+ where TPixel : struct, IPixel
+ => source.Frames.RootFrame.GetPixelSpan();
+
+ ///
+ /// Gets the representation of the pixels as an area of contiguous memory at row 'y' beginning from the the first pixel on that row.
+ ///
+ /// The type of the pixel.
+ /// The source.
+ /// The row.
+ /// The
+ public static Span GetPixelRowSpan(this Image source, int row)
+ where TPixel : struct, IPixel
+ => source.Frames.RootFrame.GetPixelRowSpan(row);
+
+ ///
+ /// Gets the configuration for the image.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// Returns the configuration.
+ public static Configuration GetConfiguration(this Image source)
+ where TPixel : struct, IPixel
+ => GetConfiguration((IConfigurable)source);
+
+ ///
+ /// Gets the span to the backing buffer.
///
/// The type of the pixel.
/// The source.
/// The span retuned from Pixel source
private static Span GetSpan(IPixelSource source)
where TPixel : struct, IPixel
- => source.Span;
+ => source.PixelBuffer.Span;
+
+ ///
+ /// Gets the span to the backing buffer at the given row.
+ ///
+ /// The type of the pixel.
+ /// The source.
+ /// The row.
+ ///
+ /// The span retuned from Pixel source
+ ///
+ private static Span GetSpan(IPixelSource source, int row)
+ where TPixel : struct, IPixel
+ => GetSpan(source.PixelBuffer, row);
+
+ ///
+ /// Gets the span to the backing buffer at the given row.
+ ///
+ /// The type of the pixel.
+ /// The source.
+ /// The row.
+ ///
+ /// The span retuned from Pixel source
+ ///
+ private static Span GetSpan(Buffer2D source, int row)
+ where TPixel : struct, IPixel
+ => source.Span.Slice(row * source.Width, source.Width);
+
+ ///
+ /// Gets the configuration.
+ ///
+ /// The source image
+ /// Returns the bounds of the image
+ private static Configuration GetConfiguration(IConfigurable source)
+ => source?.Configuration ?? Configuration.Default;
}
}
diff --git a/src/ImageSharp/ApplyProcessors.cs b/src/ImageSharp/ApplyProcessors.cs
index 1788332755..58a952c406 100644
--- a/src/ImageSharp/ApplyProcessors.cs
+++ b/src/ImageSharp/ApplyProcessors.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
@@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
- IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true);
+ IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, true);
operation(operationsRunner);
operationsRunner.Apply();
}
@@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(operations, nameof(operations));
Guard.NotNull(source, nameof(source));
- IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, true);
+ IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, true);
operationsRunner.ApplyProcessors(operations);
operationsRunner.Apply();
}
@@ -59,7 +60,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(operation, nameof(operation));
Guard.NotNull(source, nameof(source));
- IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false);
+ IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, false);
operation(operationsRunner);
return operationsRunner.Apply();
}
@@ -77,7 +78,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(operations, nameof(operations));
Guard.NotNull(source, nameof(source));
- IInternalImageProcessingContext operationsRunner = source.Configuration.ImageOperationsProvider.CreateImageProcessingContext(source, false);
+ IInternalImageProcessingContext operationsRunner = source.GetConfiguration().ImageOperationsProvider.CreateImageProcessingContext(source, false);
operationsRunner.ApplyProcessors(operations);
return operationsRunner.Apply();
}
diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index 8453881cc5..8717fa9876 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/DefaultInternalImageProcessorContext.cs b/src/ImageSharp/DefaultInternalImageProcessorContext.cs
index 8eb1c09fee..575525a773 100644
--- a/src/ImageSharp/DefaultInternalImageProcessorContext.cs
+++ b/src/ImageSharp/DefaultInternalImageProcessorContext.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.Primitives;
@@ -53,8 +54,7 @@ namespace SixLabors.ImageSharp
// This will only work if the first processor applied is the cloning one thus
// realistically for this optermissation to work the resize must the first processor
// applied any only up processors will take the douple data path.
- var cloningImageProcessor = processor as ICloningImageProcessor;
- if (cloningImageProcessor != null)
+ if (processor is ICloningImageProcessor cloningImageProcessor)
{
this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
return this;
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs
index 3fb86f1924..510a097eaf 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuserBase.cs
@@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Dithering.Base
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Dither(ImageBase pixels, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY)
+ public void Dither(ImageFrame pixels, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY)
where TPixel : struct, IPixel
{
this.Dither(pixels, source, transformed, x, y, minX, minY, maxX, maxY, true);
@@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Dithering.Base
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel)
+ public void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel)
where TPixel : struct, IPixel
{
if (replacePixel)
diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
index 850c978fef..c538d643c6 100644
--- a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
+++ b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Dithering
/// The maximum column value.
/// The maximum row value.
/// The pixel format.
- void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY)
+ void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY)
where TPixel : struct, IPixel;
///
@@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Dithering
/// Generally this would be true for standard two-color dithering but when used in conjunction with color quantization this should be false.
///
/// The pixel format.
- void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel)
+ void Dither(ImageFrame image, TPixel source, TPixel transformed, int x, int y, int minX, int minY, int maxX, int maxY, bool replacePixel)
where TPixel : struct, IPixel;
}
}
diff --git a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
index e3c7c5cbaf..e0e11ad9ee 100644
--- a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
+++ b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs
@@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Dithering
/// The column index.
/// The row index.
/// The pixel format.
- void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
+ void Dither(ImageFrame image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
where TPixel : struct, IPixel;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs b/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs
index 6fa406bec8..09c30eb272 100644
--- a/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs
+++ b/src/ImageSharp/Dithering/Ordered/OrderedDitherBase.cs
@@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Dithering.Base
}
///
- public void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
+ public void Dither(ImageFrame image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y)
where TPixel : struct, IPixel
{
// TODO: This doesn't really cut it for me.
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index 12dd0f91a3..d34d170847 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));
@@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
WriteHeader(writer, fileHeader);
this.WriteInfo(writer, infoHeader);
- this.WriteImage(writer, image);
+ this.WriteImage(writer, image.Frames.RootFrame);
writer.Flush();
}
@@ -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, ImageFrame image)
where TPixel : struct, IPixel
{
using (PixelAccessor pixels = image.Lock())
diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
index 558ce69c55..935ce8f4ad 100644
--- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.PixelFormats;
@@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is null.
public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder)
where TPixel : struct, IPixel
- => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Bmp));
+ => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Bmp));
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index cb124d305a..c3c395e852 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 = this.image.Frames.RootFrame;
}
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.Frames.RootFrame : 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/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs
index 2c3bb29299..ccf46a17d6 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs
@@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
public void Encode(Image image, Stream stream)
where TPixel : struct, IPixel
{
- GifEncoderCore encoder = new GifEncoderCore(this);
+ var encoder = new GifEncoderCore(this);
encoder.Encode(image, stream);
}
}
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index 5022678384..d143cd5319 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -90,20 +90,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that pallete size can be set but has a fallback.
- int paletteSize = this.paletteSize;
- paletteSize = paletteSize > 0 ? paletteSize.Clamp(1, 256) : 256;
+ int size = this.paletteSize;
+ size = size > 0 ? size.Clamp(1, 256) : 256;
// Get the number of bits.
- this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(paletteSize);
+ this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(size);
- this.hasFrames = image.Frames.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;
ditheredQuantizer.Dither = !this.hasFrames;
// Quantize the image returning a palette.
- QuantizedImage quantized = ditheredQuantizer.Quantize(image, paletteSize);
+ QuantizedImage quantized = ditheredQuantizer.Quantize(image.Frames.RootFrame, size);
int index = this.GetTransparentIndex(quantized);
@@ -114,28 +114,27 @@ 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++)
+ foreach (ImageFrame frame in image.Frames)
+ {
+ 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, size);
}
+
+ 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 +252,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 +320,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 +346,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/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs
index b5f358f583..939eb456e1 100644
--- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.PixelFormats;
@@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is null.
public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder)
where TPixel : struct, IPixel
- => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Gif));
+ => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Gif));
}
}
diff --git a/src/ImageSharp/Formats/IImageDecoder.cs b/src/ImageSharp/Formats/IImageDecoder.cs
index 86d5f5375b..e392cf7c61 100644
--- a/src/ImageSharp/Formats/IImageDecoder.cs
+++ b/src/ImageSharp/Formats/IImageDecoder.cs
@@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats
public interface IImageDecoder
{
///
- /// Decodes the image from the specified stream to the .
+ /// Decodes the image from the specified stream to the .
///
/// The pixel format.
/// The configuration for the image.
diff --git a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs
index 57b29e8ab4..84867d2766 100644
--- a/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Common/Decoder/JpegImagePostProcessor.cs
@@ -2,6 +2,7 @@ using System;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -16,7 +17,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
{
@@ -97,7 +98,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
///
/// The pixel type
/// The destination image
- public void PostProcess(Image destination)
+ public void PostProcess(ImageFrame destination)
where TPixel : struct, IPixel
{
this.PixelRowCounter = 0;
@@ -118,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
///
/// The pixel type
/// The destination image.
- public void DoPostProcessorStep(Image destination)
+ public void DoPostProcessorStep(ImageFrame destination)
where TPixel : struct, IPixel
{
foreach (JpegComponentPostProcessor cpp in this.ComponentProcessors)
@@ -136,7 +137,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common.Decoder
///
/// The pixel type
/// The destination image
- private void ConvertColorsInto(Image destination)
+ private void ConvertColorsInto(ImageFrame destination)
where TPixel : struct, IPixel
{
int maxY = Math.Min(destination.Height, this.PixelRowCounter + PixelRowsPerStep);
diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
index 33ebe72d01..8369e92366 100644
--- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
@@ -815,7 +815,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
using (var postProcessor = new JpegImagePostProcessor(this))
{
var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
- postProcessor.PostProcess(image);
+ postProcessor.PostProcess(image.Frames.RootFrame);
return image;
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
index c7d7b26da6..9cd7b3a8bd 100644
--- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs
@@ -3,6 +3,7 @@
using System;
using System.IO;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.PixelFormats;
@@ -35,6 +36,6 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is null.
public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder)
where TPixel : struct, IPixel
- => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Jpeg));
+ => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Jpeg));
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
index c5225b5467..6c84597c99 100644
--- a/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
@@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
this.QuantizeAndInverseAllComponents();
var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, metadata);
- this.FillPixelData(image);
+ this.FillPixelData(image.Frames.RootFrame);
this.AssignResolution(image);
return image;
}
@@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
///
/// The pixel format.
/// The image
- private void FillPixelData(Image image)
+ private void FillPixelData(ImageFrame image)
where TPixel : struct, IPixel
{
if (this.NumberOfComponents > 4)
@@ -856,7 +856,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillGrayScaleImage(Image image)
+ private void FillGrayScaleImage(ImageFrame image)
where TPixel : struct, IPixel
{
for (int y = 0; y < image.Height; y++)
@@ -875,7 +875,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillYCbCrImage(Image image)
+ private void FillYCbCrImage(ImageFrame image)
where TPixel : struct, IPixel
{
for (int y = 0; y < image.Height; y++)
@@ -894,7 +894,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillYcckImage(Image image)
+ private void FillYcckImage(ImageFrame image)
where TPixel : struct, IPixel
{
for (int y = 0; y < image.Height; y++)
@@ -915,7 +915,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillCmykImage(Image image)
+ private void FillCmykImage(ImageFrame image)
where TPixel : struct, IPixel
{
for (int y = 0; y < image.Height; y++)
@@ -941,7 +941,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void FillRgbImage(Image image)
+ private void FillRgbImage(ImageFrame image)
where TPixel : struct, IPixel
{
for (int y = 0; y < image.Height; y++)
diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs
index 5d7539915c..10970fc16a 100644
--- a/src/ImageSharp/Formats/Png/ImageExtensions.cs
+++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System.IO;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.PixelFormats;
@@ -34,6 +35,6 @@ namespace SixLabors.ImageSharp
/// Thrown if the stream is null.
public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder)
where TPixel : struct, IPixel
- => source.Save(stream, encoder ?? source.Configuration.FindEncoder(ImageFormats.Png));
+ => source.Save(stream, encoder ?? source.GetConfiguration().FindEncoder(ImageFormats.Png));
}
}
diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs
index 786f3fe901..739fd6051e 100644
--- a/src/ImageSharp/Formats/Png/PngDecoder.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoder.cs
@@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Png
public Encoding TextEncoding { get; set; } = PngConstants.DefaultEncoding;
///
- /// Decodes the image from the specified stream to the .
+ /// Decodes the image from the specified stream to the .
///
/// The pixel format.
/// The configuration for the image.
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 48618c5eee..4fd57c2784 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -236,7 +236,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
deframeStream.AllocateNewBytes(currentChunk.Length);
- this.ReadScanlines(deframeStream.CompressedStream, image);
+ this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame);
stream.Read(this.crcBuffer, 0, 4);
break;
case PngChunkTypes.Palette:
@@ -442,7 +442,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The containing data.
/// The pixel data.
- private void ReadScanlines(Stream dataStream, Image image)
+ private void ReadScanlines(Stream dataStream, ImageFrame image)
where TPixel : struct, IPixel
{
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
@@ -461,7 +461,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The compressed pixel data stream.
/// The image to decode to.
- private void DecodePixelData(Stream compressedStream, Image image)
+ private void DecodePixelData(Stream compressedStream, ImageFrame image)
where TPixel : struct, IPixel
{
while (this.currentRow < this.header.Height)
@@ -519,7 +519,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The compressed pixel data stream.
/// The current image.
- private void DecodeInterlacedPixelData(Stream compressedStream, Image image)
+ private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image)
where TPixel : struct, IPixel
{
while (true)
@@ -609,7 +609,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The de-filtered scanline
/// The image
- private void ProcessDefilteredScanline(byte[] defilteredScanline, Image pixels)
+ private void ProcessDefilteredScanline(byte[] defilteredScanline, ImageFrame pixels)
where TPixel : struct, IPixel
{
var color = default(TPixel);
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index dfc905bfa3..660c371873 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,12 +233,12 @@ namespace SixLabors.ImageSharp.Formats.Png
// Collect the indexed pixel data
if (this.pngColorType == PngColorType.Palette)
{
- this.CollectIndexedBytes(image, stream, header);
+ this.CollectIndexedBytes(image.Frames.RootFrame, stream, header);
}
this.WritePhysicalChunk(stream, image);
this.WriteGammaChunk(stream);
- this.WriteDataChunks(image, stream);
+ this.WriteDataChunks(image.Frames.RootFrame, stream);
this.WriteEndChunk(stream);
stream.Flush();
}
@@ -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)
@@ -649,7 +649,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The image.
/// The stream.
- private void WriteDataChunks(Image pixels, Stream stream)
+ private void WriteDataChunks(ImageFrame pixels, Stream stream)
where TPixel : struct, IPixel
{
this.bytesPerScanline = this.width * this.bytesPerPixel;
diff --git a/src/ImageSharp/Helpers/ImageExtensions.cs b/src/ImageSharp/Helpers/ImageExtensions.cs
new file mode 100644
index 0000000000..dbf2e34a42
--- /dev/null
+++ b/src/ImageSharp/Helpers/ImageExtensions.cs
@@ -0,0 +1,61 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Text;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.Primitives;
+
+namespace SixLabors.ImageSharp.Helpers
+{
+ ///
+ /// Extension methods over Image{TPixel}
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Gets the bounds of the image.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// Returns the bounds of the image
+ public static Rectangle Bounds(this Image source)
+ where TPixel : struct, IPixel
+ => new Rectangle(0, 0, source.Width, source.Height);
+
+ ///
+ /// Gets the bounds of the image.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// Returns the bounds of the image
+ public static Rectangle Bounds(this ImageFrame source)
+ where TPixel : struct, IPixel
+ => new Rectangle(0, 0, source.Width, source.Height);
+
+ ///
+ /// Gets the size of the image.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// Returns the bounds of the image
+ public static Size Size(this Image source)
+ where TPixel : struct, IPixel
+ => new Size(source.Width, source.Height);
+
+ ///
+ /// Gets the size of the image.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// Returns the bounds of the image
+ public static Size Size(this ImageFrame source)
+ where TPixel : struct, IPixel
+ => new Size(source.Width, source.Height);
+ }
+}
diff --git a/src/ImageSharp/Image/ICloningImageProcessor.cs b/src/ImageSharp/ICloningImageProcessor.cs
similarity index 96%
rename from src/ImageSharp/Image/ICloningImageProcessor.cs
rename to src/ImageSharp/ICloningImageProcessor.cs
index 1e7d6e4f0a..aeb3c815ec 100644
--- a/src/ImageSharp/Image/ICloningImageProcessor.cs
+++ b/src/ImageSharp/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/IImageProcessor.cs b/src/ImageSharp/IImageProcessor.cs
similarity index 96%
rename from src/ImageSharp/Image/IImageProcessor.cs
rename to src/ImageSharp/IImageProcessor.cs
index b81f08e150..bd6df8d835 100644
--- a/src/ImageSharp/Image/IImageProcessor.cs
+++ b/src/ImageSharp/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/IImage.cs b/src/ImageSharp/Image/IImage.cs
deleted file mode 100644
index 3223e20f75..0000000000
--- a/src/ImageSharp/Image/IImage.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using SixLabors.ImageSharp.Formats;
-using SixLabors.ImageSharp.MetaData;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// Encapsulates the basic properties and methods required to manipulate images.
- ///
- internal interface IImage : IImageBase
- {
- ///
- /// Gets the meta data of the image.
- ///
- ImageMetaData MetaData { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs
deleted file mode 100644
index 9aea1517d6..0000000000
--- a/src/ImageSharp/Image/IImageBase.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using SixLabors.Primitives;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// Encapsulates the basic properties and methods required to manipulate images.
- ///
- public interface IImageBase
- {
- ///
- /// Gets the width in pixels.
- ///
- int Width { get; }
-
- ///
- /// Gets the height in pixels.
- ///
- int Height { get; }
-
- ///
- /// Gets the configuration providing initialization code which allows extending the library.
- ///
- Configuration Configuration { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs
deleted file mode 100644
index 31a8165887..0000000000
--- a/src/ImageSharp/Image/IImageFrame.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using SixLabors.ImageSharp.MetaData;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// Encapsulates the basic properties and methods required to manipulate images.
- ///
- internal interface IImageFrame : IImageBase
- {
- ///
- /// Gets the meta data of the image.
- ///
- ImageFrameMetaData MetaData { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/IImageFrameCollection.cs b/src/ImageSharp/Image/IImageFrameCollection.cs
new file mode 100644
index 0000000000..ee325bc632
--- /dev/null
+++ b/src/ImageSharp/Image/IImageFrameCollection.cs
@@ -0,0 +1,84 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Encapsulates an imaged collection of frames.
+ ///
+ /// The type of the pixel.
+ public interface IImageFrameCollection : IEnumerable>
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// Gets the count.
+ ///
+ int Count { get; }
+
+ ///
+ /// Gets the root frame.
+ ///
+ ImageFrame RootFrame { get; }
+
+ ///
+ /// Gets or sets the at the specified index.
+ ///
+ ///
+ /// The .
+ ///
+ /// The index.
+ /// The at the specified index.
+ ImageFrame this[int index] { get; set; }
+
+ ///
+ /// Determines the index of a specific in the .
+ ///
+ /// The to locate in the .
+ /// The index of item if found in the list; otherwise, -1.
+ int IndexOf(ImageFrame frame);
+
+ ///
+ /// Inserts the to the at the specified .
+ ///
+ /// The zero-based index at which item should be inserted..
+ /// The to insert into the .
+ void Insert(int index, ImageFrame frame);
+
+ ///
+ /// Removes the from the at the specified index.
+ ///
+ /// The zero-based index of the item to remove.
+ /// Cannot remove last frame.
+ void RemoveAt(int index);
+
+ ///
+ /// Adds the specified frame.
+ ///
+ /// The frame.
+ /// Frame must have the same dimensions as the image - frame
+ void Add(ImageFrame frame);
+
+ ///
+ /// Determines whether the contains the .
+ ///
+ /// The frame.
+ ///
+ /// true if the the specified frame; otherwise, false.
+ ///
+ bool Contains(ImageFrame frame);
+
+ ///
+ /// Removes the specified frame.
+ ///
+ /// The frame.
+ /// true if item is found in the ; otherwise,
+ /// Cannot remove last frame
+ bool Remove(ImageFrame frame);
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/Image.LoadPixelData.cs b/src/ImageSharp/Image/Image.LoadPixelData.cs
index d6ed4fcde2..5f1a1617f2 100644
--- a/src/ImageSharp/Image/Image.LoadPixelData.cs
+++ b/src/ImageSharp/Image/Image.LoadPixelData.cs
@@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
var image = new Image(config, width, height);
- SpanHelper.Copy(data, image.GetPixelSpan(), count);
+ SpanHelper.Copy(data, image.Frames.RootFrame.GetPixelSpan(), count);
return image;
}
diff --git a/src/ImageSharp/Image/ImageBase{TPixel}.cs b/src/ImageSharp/Image/ImageBase{TPixel}.cs
deleted file mode 100644
index e9987e0c76..0000000000
--- a/src/ImageSharp/Image/ImageBase{TPixel}.cs
+++ /dev/null
@@ -1,333 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Advanced;
-using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Processing;
-using SixLabors.Primitives;
-
-namespace SixLabors.ImageSharp
-{
- ///
- /// The base class of all images. Encapsulates the basic properties and methods required to manipulate
- /// images in different pixel formats.
- ///
- /// The pixel format.
- public abstract class ImageBase : IImageBase, IDisposable, IPixelSource
- where TPixel : struct, IPixel
- {
-#pragma warning disable SA1401 // Fields must be private
- ///
- /// The image pixels. Not private as Buffer2D requires an array in its constructor.
- ///
- internal TPixel[] PixelBuffer;
-#pragma warning restore SA1401 // Fields must be private
-
- ///
- /// A value indicating whether this instance of the given entity has been disposed.
- ///
- /// if this instance has been disposed; otherwise, .
- ///
- /// If the entity is disposed, it must not be disposed a second time. The isDisposed field is set the first time the entity
- /// is disposed. If the isDisposed field is true, then the Dispose() method will not dispose again. This help not to prolong the entity's
- /// life in the Garbage Collector.
- ///
- private bool isDisposed;
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- protected ImageBase(Configuration configuration)
- {
- this.Configuration = configuration ?? Configuration.Default;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The configuration providing initialization code which allows extending the library.
- ///
- /// The width of the image in pixels.
- /// The height of the image in pixels.
- ///
- /// Thrown if either or are less than or equal to 0.
- ///
- protected ImageBase(Configuration configuration, int width, int height)
- : this(configuration)
- {
- Guard.MustBeGreaterThan(width, 0, nameof(width));
- Guard.MustBeGreaterThan(height, 0, nameof(height));
-
- this.Width = width;
- this.Height = height;
- this.RentPixels();
- this.ClearPixels();
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- ///
- /// The other to create this instance from.
- ///
- ///
- /// Thrown if the given is null.
- ///
- protected ImageBase(ImageBase other)
- : this(other.Configuration)
- {
- Guard.NotNull(other, nameof(other), "Other image cannot be null.");
-
- this.Width = other.Width;
- this.Height = other.Height;
- this.CopyProperties(other);
-
- // Rent then copy the pixels. Unsafe.CopyBlock gives us a nice speed boost here.
- this.RentPixels();
-
- other.GetPixelSpan().CopyTo(this.GetPixelSpan());
- }
-
- ///
- Span IPixelSource.Span => new Span(this.PixelBuffer, 0, this.Width * this.Height);
-
- ///
- public int Width { get; private set; }
-
- ///
- public int Height { get; private set; }
-
- ///
- /// Gets the configuration providing initialization code which allows extending the library.
- ///
- public Configuration Configuration { get; private set; }
-
- ///
- /// Gets or sets the pixel at the specified position.
- ///
- /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image.
- /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image.
- /// The at the specified position.
- public TPixel this[int x, int y]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- this.CheckCoordinates(x, y);
- return this.PixelBuffer[(y * this.Width) + x];
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- set
- {
- this.CheckCoordinates(x, y);
- this.PixelBuffer[(y * this.Width) + x] = value;
- }
- }
-
- ///
- /// Gets a reference to the pixel at the specified position.
- ///
- /// The x-coordinate of the pixel. Must be greater than or equal to zero and less than the width of the image.
- /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image.
- /// The at the specified position.
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal ref TPixel GetPixelReference(int x, int y)
- {
- this.CheckCoordinates(x, y);
- return ref this.PixelBuffer[(y * this.Width) + x];
- }
-
- ///
- /// Clones the image
- ///
- /// A new items which is a clone of the original.
- public ImageBase Clone()
- {
- return this.CloneImageBase();
- }
-
- ///
- public void Dispose()
- {
- this.Dispose(true);
-
- // This object will be cleaned up by the Dispose method.
- // Therefore, you should call GC.SuppressFinalize to
- // take this object off the finalization queue
- // and prevent finalization code for this object
- // from executing a second time.
- GC.SuppressFinalize(this);
- }
-
- ///
- /// Locks the image providing access to the pixels.
- ///
- /// It is imperative that the accessor is correctly disposed off after use.
- ///
- ///
- /// The
- internal PixelAccessor Lock()
- {
- return new PixelAccessor(this);
- }
-
- ///
- /// Copies the pixels to another of the same size.
- ///
- /// The target pixel buffer accessor.
- internal void CopyTo(PixelAccessor target)
- {
- SpanHelper.Copy(this.GetPixelSpan(), target.PixelBuffer.Span);
- }
-
- ///
- /// Switches the buffers used by the image and the PixelAccessor meaning that the Image will "own" the buffer from the PixelAccessor and the PixelAccessor will now own the Images buffer.
- ///
- /// The pixel source.
- internal void SwapPixelsBuffers(PixelAccessor pixelSource)
- {
- Guard.NotNull(pixelSource, nameof(pixelSource));
-
- int newWidth = pixelSource.Width;
- int newHeight = pixelSource.Height;
-
- // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
- TPixel[] newPixels = pixelSource.ReturnCurrentColorsAndReplaceThemInternally(this.Width, this.Height, this.PixelBuffer);
- this.Width = newWidth;
- this.Height = newHeight;
- this.PixelBuffer = newPixels;
- }
-
- ///
- /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer.
- ///
- /// The pixel source.
- internal void SwapPixelsData(ImageBase pixelSource)
- {
- Guard.NotNull(pixelSource, nameof(pixelSource));
-
- int newWidth = pixelSource.Width;
- int newHeight = pixelSource.Height;
- TPixel[] newPixels = pixelSource.PixelBuffer;
-
- pixelSource.PixelBuffer = this.PixelBuffer;
- pixelSource.Width = this.Width;
- pixelSource.Height = this.Height;
-
- this.Width = newWidth;
- this.Height = newHeight;
- this.PixelBuffer = newPixels;
- }
-
- ///
- /// Clones the image
- ///
- /// A new items which is a clone of the original.
- protected abstract ImageBase CloneImageBase();
-
- ///
- /// Copies the properties from the other .
- ///
- ///
- /// The other to copy the properties from.
- ///
- protected void CopyProperties(IImageBase other)
- {
- DebugGuard.NotNull(other, nameof(other));
-
- this.Configuration = other.Configuration;
- }
-
- ///
- /// Disposes the object and frees resources for the Garbage Collector.
- ///
- /// If true, the object gets disposed.
- protected virtual void Dispose(bool disposing)
- {
- if (this.isDisposed)
- {
- return;
- }
-
- if (disposing)
- {
- this.ReturnPixels();
- }
-
- // Note disposing is done.
- this.isDisposed = true;
- }
-
- ///
- /// Rents the pixel array from the pool.
- ///
- private void RentPixels()
- {
- this.PixelBuffer = PixelDataPool.Rent(this.Width * this.Height);
- }
-
- ///
- /// Returns the rented pixel array back to the pool.
- ///
- private void ReturnPixels()
- {
- PixelDataPool.Return(this.PixelBuffer);
- this.PixelBuffer = null;
- }
-
- ///
- /// Clears the pixel array.
- ///
- private void ClearPixels()
- {
- Array.Clear(this.PixelBuffer, 0, this.Width * this.Height);
- }
-
- ///
- /// Checks the coordinates to ensure they are within bounds.
- ///
- /// The y-coordinate of the pixel. Must be greater than zero and less than the height of the image.
- ///
- /// Thrown if the coordinates are not within the bounds of the image.
- ///
- [Conditional("DEBUG")]
- private void CheckCoordinates(int y)
- {
- if (y < 0 || y >= this.Height)
- {
- throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds.");
- }
- }
-
- ///
- /// Checks the coordinates to ensure they are within bounds.
- ///
- /// The x-coordinate of the pixel. Must be greater than zero and less than the width of the image.
- /// The y-coordinate of the pixel. Must be greater than zero and less than the height of the image.
- ///
- /// Thrown if the coordinates are not within the bounds of the image.
- ///
- [Conditional("DEBUG")]
- private void CheckCoordinates(int x, int y)
- {
- if (x < 0 || x >= this.Width)
- {
- throw new ArgumentOutOfRangeException(nameof(x), x, $"{x} is outwith the image bounds.");
- }
-
- if (y < 0 || y >= this.Height)
- {
- throw new ArgumentOutOfRangeException(nameof(y), y, $"{y} is outwith the image bounds.");
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/ImageExtensions.cs b/src/ImageSharp/Image/ImageExtensions.cs
index afd4343815..c5b3d6f31a 100644
--- a/src/ImageSharp/Image/ImageExtensions.cs
+++ b/src/ImageSharp/Image/ImageExtensions.cs
@@ -18,26 +18,6 @@ namespace SixLabors.ImageSharp
///
public static partial class ImageExtensions
{
- ///
- /// Gets the bounds of the image.
- ///
- /// The Pixel format.
- /// The source image
- /// Returns the bounds of the image
- public static Rectangle Bounds(this ImageBase source)
- where TPixel : struct, IPixel
- => new Rectangle(0, 0, source.Width, source.Height);
-
- ///
- /// Gets the size of the image.
- ///
- /// The Pixel format.
- /// The source image
- /// Returns the bounds of the image
- public static Size Size(this ImageBase source)
- where TPixel : struct, IPixel
- => new Size(source.Width, source.Height);
-
#if !NETSTANDARD1_1
///
/// Saves the image to the given stream using the currently loaded image format.
@@ -52,12 +32,12 @@ namespace SixLabors.ImageSharp
Guard.NotNullOrEmpty(filePath, nameof(filePath));
string ext = Path.GetExtension(filePath).Trim('.');
- IImageFormat format = source.Configuration.FindFormatByFileExtension(ext);
+ IImageFormat format = source.GetConfiguration().FindFormatByFileExtension(ext);
if (format == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
- foreach (IImageFormat fmt in source.Configuration.ImageFormats)
+ foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats)
{
stringBuilder.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}");
}
@@ -65,13 +45,13 @@ namespace SixLabors.ImageSharp
throw new NotSupportedException(stringBuilder.ToString());
}
- IImageEncoder encoder = source.Configuration.FindEncoder(format);
+ IImageEncoder encoder = source.GetConfiguration().FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
- foreach (KeyValuePair enc in source.Configuration.ImageEncoders)
+ foreach (KeyValuePair enc in source.GetConfiguration().ImageEncoders)
{
stringBuilder.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
}
@@ -94,7 +74,7 @@ namespace SixLabors.ImageSharp
where TPixel : struct, IPixel
{
Guard.NotNull(encoder, nameof(encoder));
- using (Stream fs = source.Configuration.FileSystem.Create(filePath))
+ using (Stream fs = source.GetConfiguration().FileSystem.Create(filePath))
{
source.Save(fs, encoder);
}
@@ -113,14 +93,14 @@ namespace SixLabors.ImageSharp
where TPixel : struct, IPixel
{
Guard.NotNull(format, nameof(format));
- IImageEncoder encoder = source.Configuration.FindEncoder(format);
+ IImageEncoder encoder = source.GetConfiguration().FindEncoder(format);
if (encoder == null)
{
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine("Can't find encoder for provided mime type. Available encoded:");
- foreach (KeyValuePair val in source.Configuration.ImageEncoders)
+ foreach (KeyValuePair val in source.GetConfiguration().ImageEncoders)
{
stringBuilder.AppendLine($" - {val.Key.Name} : {val.Value.GetType().Name}");
}
@@ -131,6 +111,17 @@ namespace SixLabors.ImageSharp
source.Save(stream, encoder);
}
+ ///
+ /// Saves the raw image to the given bytes.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// A copy of the pixel data as bytes from this frame.
+ /// Thrown if the stream is null.
+ public static byte[] SavePixelData(this ImageFrame source)
+ where TPixel : struct, IPixel
+ => source.GetPixelSpan().AsBytes().ToArray();
+
///
/// Saves the raw image to the given bytes.
///
@@ -138,7 +129,18 @@ namespace SixLabors.ImageSharp
/// The source image
/// The buffer to save the raw pixel data to.
/// Thrown if the stream is null.
- internal static void SavePixelData(this Image source, byte[] buffer)
+ public static void SavePixelData(this ImageFrame source, byte[] buffer)
+ where TPixel : struct, IPixel
+ => SavePixelData(source, new Span(buffer));
+
+ ///
+ /// Saves the raw image to the given bytes.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// The buffer to save the raw pixel data to.
+ /// Thrown if the stream is null.
+ private static void SavePixelData(this ImageFrame source, Span buffer)
where TPixel : struct, IPixel
{
Span byteBuffer = source.GetPixelSpan().AsBytes();
@@ -147,6 +149,39 @@ namespace SixLabors.ImageSharp
byteBuffer.CopyTo(buffer);
}
+ ///
+ /// Saves the raw image to the given bytes.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// A copy of the pixel data from the first frame as bytes.
+ /// Thrown if the stream is null.
+ public static byte[] SavePixelData(this Image source)
+ where TPixel : struct, IPixel
+ => source.Frames.RootFrame.SavePixelData();
+
+ ///
+ /// Saves the raw image to the given bytes.
+ ///
+ /// The Pixel format.
+ /// The source image
+ /// The buffer to save the raw pixel data to.
+ /// Thrown if the stream is null.
+ public static void SavePixelData(this Image source, byte[] buffer)
+ where TPixel : struct, IPixel
+ => source.Frames.RootFrame.SavePixelData(buffer);
+
+ ///
+ /// 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.
+ private static void SavePixelData(this Image source, Span buffer)
+ where TPixel : struct, IPixel
+ => source.Frames.RootFrame.SavePixelData(buffer);
+
///
/// Returns a Base64 encoded string from the given image.
///
diff --git a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs
new file mode 100644
index 0000000000..aecd9bba9e
--- /dev/null
+++ b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.IO;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Adds static methods allowing the creation of new image from raw pixel data.
+ ///
+ public static partial class ImageFrame
+ {
+ ///
+ /// Create a new instance of the class from the given byte array in format.
+ ///
+ /// The byte array containing image data.
+ /// The width of the final image.
+ /// The height of the final image.
+ /// The pixel format.
+ /// A new .
+ public static ImageFrame LoadPixelData(Span data, int width, int height)
+ where TPixel : struct, IPixel
+ => LoadPixelData(data.NonPortableCast(), width, height);
+
+ ///
+ /// Create a new instance of the class from the raw data.
+ ///
+ /// The Span containing the image Pixel data.
+ /// The width of the final image.
+ /// The height of the final image.
+ /// The pixel format.
+ /// A new .
+ public static ImageFrame LoadPixelData(Span data, int width, int height)
+ where TPixel : struct, IPixel
+ {
+ int count = width * height;
+ Guard.MustBeGreaterThanOrEqualTo(data.Length, count, nameof(data));
+
+ var image = new ImageFrame(width, height);
+ SpanHelper.Copy(data, image.GetPixelSpan(), count);
+
+ return image;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs
new file mode 100644
index 0000000000..25c0d0c449
--- /dev/null
+++ b/src/ImageSharp/Image/ImageFrameCollection.cs
@@ -0,0 +1,166 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+using SixLabors.ImageSharp.PixelFormats;
+
+namespace SixLabors.ImageSharp
+{
+ ///
+ /// Encapsulates an imaged collection of frames.
+ ///
+ /// The type of the pixel.
+ internal sealed class ImageFrameCollection : IImageFrameCollection, IDisposable
+ where TPixel : struct, IPixel
+ {
+ private readonly IList> frames = new List>();
+
+ internal ImageFrameCollection(int width, int height)
+ {
+ this.Add(new ImageFrame(width, height));
+ }
+
+ internal ImageFrameCollection(IEnumerable> frames)
+ {
+ Guard.NotNullOrEmpty(frames, nameof(frames));
+ foreach (ImageFrame f in frames)
+ {
+ this.Add(f);
+ }
+ }
+
+ ///
+ /// Gets the count.
+ ///
+ public int Count => this.frames.Count;
+
+ ///
+ /// Gets the root frame.
+ ///
+ public ImageFrame RootFrame => this.frames.Count > 0 ? this.frames[0] : null;
+
+ ///
+ /// Gets or sets the at the specified index.
+ ///
+ ///
+ /// The .
+ ///
+ /// The index.
+ /// The at the specified index.
+ public ImageFrame this[int index]
+ {
+ get => this.frames[index];
+
+ set
+ {
+ this.ValidateFrame(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.ValidateFrame(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.Count == 1)
+ {
+ throw new InvalidOperationException("Cannot remove last frame.");
+ }
+
+ this.frames.RemoveAt(index);
+ }
+
+ ///
+ /// Adds the specified frame.
+ ///
+ /// The frame.
+ /// Frame must have the same dimensions as the image - frame
+ public void Add(ImageFrame frame)
+ {
+ this.ValidateFrame(frame);
+ this.frames.Add(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.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();
+
+ private void ValidateFrame(ImageFrame frame)
+ {
+ Guard.NotNull(frame, nameof(frame));
+
+ if (this.Count != 0)
+ {
+ if (this.RootFrame.Width != frame.Width || this.RootFrame.Height != frame.Height)
+ {
+ throw new ArgumentException("Frame must have the same dimensions as the image.", nameof(frame));
+ }
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ foreach (ImageFrame f in this.frames)
+ {
+ f.Dispose();
+ }
+
+ this.frames.Clear();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs
index bd5e272618..73e3a80aef 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,174 @@ namespace SixLabors.ImageSharp
/// Represents a single frame in a animation.
///
/// The pixel format.
- public sealed class ImageFrame : ImageBase, IImageFrame
+ public sealed class ImageFrame : IPixelSource, IDisposable
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;
+
+ ///
+ /// 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.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.MetaData = new ImageFrameMetaData();
+ this.pixelBuffer = new Buffer2D(source.pixelBuffer.Width, source.pixelBuffer.Height);
+ source.pixelBuffer.Span.CopyTo(this.pixelBuffer.Span);
+ this.MetaData = source.MetaData.Clone();
}
+ ///
+ Buffer2D IPixelSource.PixelBuffer => this.pixelBuffer;
+
+ ///
+ /// Gets the width.
+ ///
+ public int Width => this.pixelBuffer.Width;
+
+ ///
+ /// Gets the height.
+ ///
+ public int Height => this.pixelBuffer.Height;
+
+ ///
+ /// Gets the meta data of the frame.
+ ///
+ public ImageFrameMetaData MetaData { get; private set; }
+
///
- /// Initializes a new instance of the class.
+ /// Gets or sets the pixel at the specified position.
///
- /// The image to create the frame from.
- internal ImageFrame(ImageBase image)
- : base(image)
+ /// 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.
- private ImageFrame(ImageFrame 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.CopyProperties(image);
+ return ref this.pixelBuffer[x, y];
}
///
- /// Gets the meta data of the frame.
+ /// Locks the image providing access to the pixels.
+ ///
+ /// It is imperative that the accessor is correctly disposed off after use.
+ ///
///
- public ImageFrameMetaData MetaData { get; private set; }
+ /// 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));
+
+ // Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
+ Buffer2D newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer);
+ 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));
+
+ ComparableExtensions.Swap(ref this.pixelBuffer, ref pixelSource.pixelBuffer);
+ }
+
+ ///
+ /// 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 +207,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,12 +215,12 @@ namespace SixLabors.ImageSharp
Parallel.For(
0,
target.Height,
- this.Configuration.ParallelOptions,
+ Configuration.Default.ParallelOptions,
y =>
{
for (int x = 0; x < target.Width; x++)
{
- TPixel2 color = default(TPixel2);
+ var color = default(TPixel2);
color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4()));
targetPixels[x, y] = color;
}
@@ -131,28 +234,9 @@ namespace SixLabors.ImageSharp
/// Clones the current instance.
///
/// The
- public new ImageFrame Clone()
+ public ImageFrame Clone()
{
return new ImageFrame(this);
}
-
- ///
- protected override ImageBase CloneImageBase()
- {
- return this.Clone();
- }
-
- ///
- /// Copies the properties from the other .
- ///
- ///
- /// The other to copy the properties from.
- ///
- private void CopyProperties(IImageFrame other)
- {
- base.CopyProperties(other);
-
- this.MetaData = new ImageFrameMetaData(other.MetaData);
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs
index 900045dbad..5c35d854a3 100644
--- a/src/ImageSharp/Image/Image{TPixel}.cs
+++ b/src/ImageSharp/Image/Image{TPixel}.cs
@@ -3,16 +3,13 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
-using System.Numerics;
-using System.Text;
-using System.Threading.Tasks;
+using System.Linq;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
-using SixLabors.ImageSharp.Processing;
-using SixLabors.Primitives;
namespace SixLabors.ImageSharp
{
@@ -20,9 +17,12 @@ 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 : IDisposable, IConfigurable
where TPixel : struct, IPixel
{
+ private Configuration configuration;
+ private ImageFrameCollection frames;
+
///
/// Initializes a new instance of the class
/// with the height and the width of the image.
@@ -59,41 +59,41 @@ 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 = configuration ?? Configuration.Default;
this.MetaData = metadata ?? new ImageMetaData();
+ this.frames = new ImageFrameCollection(width, height);
}
///
- /// Initializes a new instance of the class
- /// by making a copy from another image.
+ /// Initializes a new instance of the class
+ /// with the height and the width of the image.
///
- /// The other image, where the clone should be made from.
- /// is null.
- private Image(Image other)
- : base(other)
+ /// The configuration providing initialization code which allows extending the library.
+ /// The images metadata.
+ /// The frames that will be owned by this image instance.
+ internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable> frames)
{
- foreach (ImageFrame frame in other.Frames)
- {
- if (frame != null)
- {
- this.Frames.Add(frame.Clone());
- }
- }
+ this.configuration = configuration ?? Configuration.Default;
+ this.MetaData = metadata ?? new ImageMetaData();
- this.CopyProperties(other);
+ this.frames = new ImageFrameCollection(frames);
}
///
- /// Initializes a new instance of the class
- /// by making a copy from another image.
+ /// Gets the pixel buffer.
///
- /// The other image, where the clone should be made from.
- /// is null.
- private Image(ImageBase other)
- : base(other)
- {
- }
+ Configuration IConfigurable.Configuration => this.configuration;
+
+ ///
+ /// Gets the width.
+ ///
+ public int Width => this.frames.RootFrame.Width;
+
+ ///
+ /// Gets the height.
+ ///
+ public int Height => this.frames.RootFrame.Height;
///
/// Gets the meta data of the image.
@@ -101,10 +101,27 @@ namespace SixLabors.ImageSharp
public ImageMetaData MetaData { get; private set; } = new ImageMetaData();
///
- /// Gets the other frames associated with this image.
+ /// Gets the frames.
+ ///
+ public IImageFrameCollection Frames => this.frames;
+
+ ///
+ /// Gets the root frame.
///
- /// The list of frame images.
- public IList> Frames { get; } = new List>();
+ private IPixelSource PixelSource => this.frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image));
+
+ ///
+ /// 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]
+ {
+ get => this.PixelSource.PixelBuffer[x, y];
+
+ set => this.PixelSource.PixelBuffer[x, y] = value;
+ }
///
/// Saves the image to the given stream using the given image encoder.
@@ -124,9 +141,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.MetaData.Clone(), frames);
}
///
@@ -143,79 +162,32 @@ 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.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();
+ this.frames.Dispose();
}
///
- /// Copies the properties from the other .
+ /// 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 to copy the properties from.
- ///
- private void CopyProperties(IImage other)
+ /// The pixel source.
+ internal void SwapPixelsBuffers(Image pixelSource)
{
- this.MetaData = new ImageMetaData(other.MetaData);
+ Guard.NotNull(pixelSource, nameof(pixelSource));
+
+ for (int i = 0; i < this.frames.Count; i++)
+ {
+ this.frames[i].SwapPixelsBuffers(pixelSource.frames[i]);
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/PixelAccessorExtensions.cs b/src/ImageSharp/Image/PixelAccessorExtensions.cs
new file mode 100644
index 0000000000..9146ef48da
--- /dev/null
+++ b/src/ImageSharp/Image/PixelAccessorExtensions.cs
@@ -0,0 +1,54 @@
+// 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.Advanced;
+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 IPixelSource frame)
+ where TPixel : struct, IPixel
+ {
+ return new PixelAccessor(frame);
+ }
+
+ ///
+ /// Locks the image providing access to the pixels.
+ ///
+ /// It is imperative that the accessor is correctly disposed off after use.
+ ///
+ ///
+ /// The type of the pixel.
+ /// The image.
+ ///
+ /// The
+ ///
+ internal static PixelAccessor Lock(this Image image)
+ where TPixel : struct, IPixel
+ {
+ return image.Frames.RootFrame.Lock();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
index 90908529f5..3abe28aca0 100644
--- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
+++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs
@@ -4,7 +4,7 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
-using System.Threading.Tasks;
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Unsafe = System.Runtime.CompilerServices.Unsafe;
@@ -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,13 @@ namespace SixLabors.ImageSharp
/// Initializes a new instance of the class.
///
/// The image to provide pixel access for.
- public PixelAccessor(ImageBase image)
+ public PixelAccessor(IPixelSource image)
{
Guard.NotNull(image, nameof(image));
- Guard.MustBeGreaterThan(image.Width, 0, "image width");
- Guard.MustBeGreaterThan(image.Height, 0, "image height");
+ Guard.MustBeGreaterThan(image.PixelBuffer.Width, 0, "image width");
+ Guard.MustBeGreaterThan(image.PixelBuffer.Height, 0, "image height");
- this.SetPixelBufferUnsafe(image.Width, image.Height, image.PixelBuffer);
- this.ParallelOptions = image.Configuration.ParallelOptions;
+ this.SetPixelBufferUnsafe(image.PixelBuffer, false);
}
///
@@ -56,7 +56,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,15 +66,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.ParallelOptions = Configuration.Default.ParallelOptions;
+ this.SetPixelBufferUnsafe(pixels, ownedBuffer);
}
///
@@ -100,21 +99,12 @@ namespace SixLabors.ImageSharp
///
public int RowStride { get; private set; }
- ///
- /// Gets the width of the image.
- ///
+ ///
public int Width { get; private set; }
- ///
- /// Gets the height of the image.
- ///
+ ///
public int Height { get; private set; }
- ///
- /// Gets the global parallel options for processing tasks in parallel.
- ///
- public ParallelOptions ParallelOptions { get; }
-
///
Span IBuffer2D.Span => this.PixelBuffer;
@@ -143,12 +133,10 @@ namespace SixLabors.ImageSharp
}
}
- ///
- /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
- ///
+ ///
public void Dispose()
{
- if (this.isDisposed)
+ if (this.isDisposed || !this.ownedBuffer)
{
return;
}
@@ -236,15 +224,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);
+ Buffer2D oldPixels = this.PixelBuffer;
+ this.SetPixelBufferUnsafe(pixels, this.ownedBuffer);
return oldPixels;
}
@@ -412,23 +398,18 @@ 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)
+ /// if set to true then this instance ownes the buffer and thus should dispose of it afterwards.
+ private void SetPixelBufferUnsafe(Buffer2D pixels, bool ownedBuffer)
{
this.PixelBuffer = pixels;
+ this.ownedBuffer = ownedBuffer;
- this.Width = width;
- this.Height = height;
+ this.Width = pixels.Width;
+ this.Height = pixels.Height;
this.PixelSize = Unsafe.SizeOf();
this.RowStride = this.Width * this.PixelSize;
}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
index c4aa98d319..d736b91ee6 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
@@ -48,13 +48,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
public TPixel LowerColor { get; set; }
///
- protected override void BeforeApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void BeforeApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
- new GrayscaleBt709Processor().Apply(source, sourceRectangle);
+ new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration);
}
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
float threshold = this.Threshold;
TPixel upper = this.UpperColor;
@@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For(
minY,
maxY,
- source.Configuration.ParallelOptions,
+ configuration.ParallelOptions,
y =>
{
Span row = source.GetPixelRowSpan(y - startY);
diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
index ba79d2a80e..8907770e15 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs
@@ -4,6 +4,7 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Dithering;
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -54,13 +55,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, Configuration configuration)
{
- new GrayscaleBt709Processor().Apply(source, sourceRectangle);
+ new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration);
}
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
index 2f76ecda57..203a64cf16 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs
@@ -5,6 +5,7 @@ using System;
using System.Buffers;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Dithering;
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -62,13 +63,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, Configuration configuration)
{
- new GrayscaleBt709Processor().Apply(source, sourceRectangle);
+ new GrayscaleBt709Processor().Apply(source, sourceRectangle, configuration);
}
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
int startY = interest.Y;
diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
index a1fa3c9cba..fdee21ed6a 100644
--- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs
@@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
-
+using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -27,21 +27,17 @@ 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.");
}
+ Configuration configuration = source.GetConfiguration();
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];
ImageFrame clonedFrame = clone.Frames[i];
- this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle);
-
- this.OnApply(sourceFrame, clonedFrame, sourceRectangle);
- this.AfterApply(sourceFrame, clonedFrame, sourceRectangle);
+ this.BeforeApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
+ this.OnApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
+ this.AfterApply(sourceFrame, clonedFrame, sourceRectangle, configuration);
}
this.AfterImageApply(source, clone, sourceRectangle);
@@ -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);
}
}
@@ -107,33 +99,30 @@ namespace SixLabors.ImageSharp.Processing
///
/// The source image. Cannot be null.
/// The cloned/destination image. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- protected virtual void BeforeApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle)
+ /// The structure that specifies the portion of the image object to draw.
+ /// The configuration.
+ protected virtual void BeforeApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
{
}
///
- /// Applies the process to the specified portion of the specified at the specified location
+ /// Applies the process to the specified portion of the specified at the specified location
/// and with the specified size.
///
/// The source image. Cannot be null.
/// The cloned/destination image. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- protected abstract void OnApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle);
+ /// The structure that specifies the portion of the image object to draw.
+ /// The configuration.
+ protected abstract void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration);
///
/// This method is called after the process is applied to prepare the processor.
///
/// The source image. Cannot be null.
/// The cloned/destination image. Cannot be null.
- ///
- /// The structure that specifies the portion of the image object to draw.
- ///
- protected virtual void AfterApply(ImageBase source, ImageBase destination, Rectangle sourceRectangle)
+ /// The structure that specifies the portion of the image object to draw.
+ /// The configuration.
+ protected virtual void AfterApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
{
}
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
index c4da8dee7d..4a64bfaa0d 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/ColorMatrixProcessor.cs
@@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public virtual bool Compand { get; set; } = true;
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
int startY = sourceRectangle.Y;
int endY = sourceRectangle.Bottom;
@@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For(
minY,
maxY,
- source.Configuration.ParallelOptions,
+ configuration.ParallelOptions,
y =>
{
Span row = source.GetPixelRowSpan(y - startY);
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
index dcb5955c00..1ec76bf554 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/LomographProcessor.cs
@@ -39,9 +39,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
};
///
- protected override void AfterApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
- new VignetteProcessor(VeryDarkGreen, this.options).Apply(source, sourceRectangle);
+ new VignetteProcessor(VeryDarkGreen, this.options).Apply(source, sourceRectangle, configuration);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
index 928a641a00..f910562e64 100644
--- a/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/ColorMatrix/PolaroidProcessor.cs
@@ -46,10 +46,10 @@ namespace SixLabors.ImageSharp.Processing.Processors
};
///
- protected override void AfterApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void AfterApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
- new VignetteProcessor(VeryDarkOrange, this.options).Apply(source, sourceRectangle);
- new GlowProcessor(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle);
+ new VignetteProcessor(VeryDarkOrange, this.options).Apply(source, sourceRectangle, configuration);
+ new GlowProcessor(LightOrange, source.Width / 4F, this.options).Apply(source, sourceRectangle, configuration);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
index 3c95d29974..8056141a09 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
@@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray KernelY { get; }
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
- new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle);
+ new Convolution2PassProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration);
}
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
index d109cb10e8..b85432ac54 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
public Fast2DArray KernelY { get; }
///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
+ protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
int kernelYHeight = this.KernelY.Height;
int kernelYWidth = this.KernelY.Width;
@@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
Parallel.For(
startY,
endY,
- source.Configuration.ParallelOptions,
+ configuration.ParallelOptions,
y =>
{
Span sourceRow = source.GetPixelRowSpan(y);
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
index 08ea5a6412..362fa5c508 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
@@ -4,6 +4,8 @@
using System;
using System.Numerics;
using System.Threading.Tasks;
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@@ -39,11 +41,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, Configuration configuration)
{
int width = source.Width;
int height = source.Height;
- ParallelOptions parallelOptions = source.Configuration.ParallelOptions;
+ ParallelOptions parallelOptions = configuration.ParallelOptions;
using (var firstPassPixels = new PixelAccessor