diff --git a/src/ImageSharp.Drawing/Brushes/IBrush.cs b/src/ImageSharp.Drawing/Brushes/IBrush.cs index 9534c7a88..8cb731782 100644 --- a/src/ImageSharp.Drawing/Brushes/IBrush.cs +++ b/src/ImageSharp.Drawing/Brushes/IBrush.cs @@ -22,7 +22,7 @@ namespace ImageSharp.Drawing /// /// Creates the applicator for this brush. /// - /// The pixel source. + /// The source image. /// The region the brush will be applied to. /// The graphic options /// @@ -32,6 +32,6 @@ namespace ImageSharp.Drawing /// 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(PixelAccessor pixelSource, RectangleF region, GraphicsOptions options); + BrushApplicator CreateApplicator(ImageBase 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 6f851e5c3..59dbd3926 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs @@ -6,7 +6,6 @@ namespace ImageSharp.Drawing.Brushes { using System; - using System.Numerics; using ImageSharp.Memory; using ImageSharp.PixelFormats; @@ -22,21 +21,21 @@ namespace ImageSharp.Drawing.Brushes /// /// The image to paint. /// - private readonly IImageBase image; + private readonly ImageBase image; /// /// Initializes a new instance of the class. /// /// The image. - public ImageBrush(IImageBase image) + public ImageBrush(ImageBase image) { this.image = image; } /// - public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) { - return new ImageBrushApplicator(sourcePixels, this.image, region, options); + return new ImageBrushApplicator(source, this.image, region, options); } /// @@ -45,9 +44,9 @@ namespace ImageSharp.Drawing.Brushes private class ImageBrushApplicator : BrushApplicator { /// - /// The source pixel accessor. + /// The source image. /// - private readonly PixelAccessor source; + private readonly ImageBase source; /// /// The y-length. @@ -72,20 +71,14 @@ namespace ImageSharp.Drawing.Brushes /// /// Initializes a new instance of the class. /// - /// - /// The image. - /// - /// - /// The region. - /// + /// The target image. + /// The image. + /// The region. /// The options - /// - /// The sourcePixels. - /// - public ImageBrushApplicator(PixelAccessor sourcePixels, IImageBase image, RectangleF region, GraphicsOptions options) - : base(sourcePixels, options) + public ImageBrushApplicator(ImageBase target, ImageBase image, RectangleF region, GraphicsOptions options) + : base(target, options) { - this.source = image.Lock(); + this.source = image; this.xLength = image.Width; this.yLength = image.Height; this.offsetY = (int)MathF.Max(MathF.Floor(region.Top), 0); @@ -119,9 +112,9 @@ namespace ImageSharp.Drawing.Brushes /// internal override void Apply(Span scanline, int x, int y) { - // create a span for colors - using (Buffer amountBuffer = new Buffer(scanline.Length)) - using (Buffer overlay = new Buffer(scanline.Length)) + // Create a span for colors + using (var amountBuffer = new Buffer(scanline.Length)) + using (var overlay = new Buffer(scanline.Length)) { int sourceY = (y - this.offsetY) % this.yLength; int offsetX = x - this.offsetX; diff --git a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs index 90990e54a..5dd57bda6 100644 --- a/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/PatternBrush{TPixel}.cs @@ -62,8 +62,8 @@ namespace ImageSharp.Drawing.Brushes /// The pattern. internal PatternBrush(TPixel foreColor, TPixel backColor, Fast2DArray pattern) { - Vector4 foreColorVector = foreColor.ToVector4(); - Vector4 backColorVector = backColor.ToVector4(); + var foreColorVector = foreColor.ToVector4(); + var backColorVector = backColor.ToVector4(); this.pattern = new Fast2DArray(pattern.Width, pattern.Height); this.patternVector = new Fast2DArray(pattern.Width, pattern.Height); for (int i = 0; i < pattern.Data.Length; i++) @@ -92,9 +92,9 @@ namespace ImageSharp.Drawing.Brushes } /// - public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) { - return new PatternBrushApplicator(sourcePixels, this.pattern, this.patternVector, options); + return new PatternBrushApplicator(source, this.pattern, this.patternVector, options); } /// @@ -111,12 +111,12 @@ namespace ImageSharp.Drawing.Brushes /// /// Initializes a new instance of the class. /// - /// The sourcePixels. + /// The source image. /// The pattern. /// The patternVector. /// The options - public PatternBrushApplicator(PixelAccessor sourcePixels, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options) - : base(sourcePixels, options) + public PatternBrushApplicator(ImageBase source, Fast2DArray pattern, Fast2DArray patternVector, GraphicsOptions options) + : base(source, options) { this.pattern = pattern; this.patternVector = patternVector; @@ -152,8 +152,8 @@ namespace ImageSharp.Drawing.Brushes internal override void Apply(Span scanline, int x, int y) { int patternY = y % this.pattern.Height; - using (Buffer amountBuffer = new Buffer(scanline.Length)) - using (Buffer overlay = new Buffer(scanline.Length)) + using (var amountBuffer = new Buffer(scanline.Length)) + using (var overlay = new Buffer(scanline.Length)) { for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs index 29629324a..29c625d7f 100644 --- a/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs @@ -6,7 +6,6 @@ namespace ImageSharp.Drawing.Processors { using System; - using System.Numerics; using ImageSharp.Memory; using ImageSharp.PixelFormats; @@ -24,7 +23,7 @@ namespace ImageSharp.Drawing.Processors /// /// The target. /// The options. - internal BrushApplicator(PixelAccessor target, GraphicsOptions options) + internal BrushApplicator(ImageBase target, GraphicsOptions options) { this.Target = target; @@ -41,7 +40,7 @@ namespace ImageSharp.Drawing.Processors /// /// Gets the destinaion /// - protected PixelAccessor Target { get; } + protected ImageBase Target { get; } /// /// Gets the blend percentage @@ -68,8 +67,8 @@ namespace ImageSharp.Drawing.Processors /// scanlineBuffer will be > scanlineWidth but provide and offset in case we want to share a larger buffer across runs. internal virtual void Apply(Span scanline, int x, int y) { - using (Buffer amountBuffer = new Buffer(scanline.Length)) - using (Buffer overlay = new Buffer(scanline.Length)) + using (var amountBuffer = new Buffer(scanline.Length)) + using (var overlay = new Buffer(scanline.Length)) { for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs index 64b91e384..96d824b2f 100644 --- a/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/RecolorBrush{TPixel}.cs @@ -57,9 +57,9 @@ namespace ImageSharp.Drawing.Brushes public TPixel TargeTPixel { get; } /// - public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) { - return new RecolorBrushApplicator(sourcePixels, this.SourceColor, this.TargeTPixel, this.Threshold, options); + return new RecolorBrushApplicator(source, this.SourceColor, this.TargeTPixel, this.Threshold, options); } /// @@ -87,22 +87,22 @@ namespace ImageSharp.Drawing.Brushes /// /// Initializes a new instance of the class. /// - /// The source pixels. + /// The source image. /// Color of the source. /// Color of the target. /// The threshold . /// The options - public RecolorBrushApplicator(PixelAccessor sourcePixels, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) - : base(sourcePixels, options) + public RecolorBrushApplicator(ImageBase source, TPixel sourceColor, TPixel targetColor, float threshold, GraphicsOptions options) + : base(source, options) { this.sourceColor = sourceColor.ToVector4(); this.targetColor = targetColor.ToVector4(); this.targetColorPixel = targetColor; - // Lets hack a min max extreams for a color space by letteing the IPackedPixel clamp our values to something in the correct spaces :) - TPixel maxColor = default(TPixel); + // Lets hack a min max extreams for a color space by letting the IPackedPixel clamp our values to something in the correct spaces :) + var maxColor = default(TPixel); maxColor.PackFromVector4(new Vector4(float.MaxValue)); - TPixel minColor = default(TPixel); + var minColor = default(TPixel); minColor.PackFromVector4(new Vector4(float.MinValue)); this.threshold = Vector4.DistanceSquared(maxColor.ToVector4(), minColor.ToVector4()) * threshold; } @@ -121,7 +121,7 @@ namespace ImageSharp.Drawing.Brushes { // Offset the requested pixel by the value in the rectangle (the shapes position) TPixel result = this.Target[x, y]; - Vector4 background = result.ToVector4(); + var background = result.ToVector4(); float distance = Vector4.DistanceSquared(background, this.sourceColor); if (distance <= this.threshold) { @@ -144,8 +144,8 @@ namespace ImageSharp.Drawing.Brushes /// internal override void Apply(Span scanline, int x, int y) { - using (Buffer amountBuffer = new Buffer(scanline.Length)) - using (Buffer overlay = new Buffer(scanline.Length)) + using (var amountBuffer = new Buffer(scanline.Length)) + using (var overlay = new Buffer(scanline.Length)) { for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs index 28f7b0e45..453b4d29e 100644 --- a/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/SolidBrush{TPixel}.cs @@ -42,9 +42,9 @@ namespace ImageSharp.Drawing.Brushes public TPixel Color => this.color; /// - public BrushApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region, GraphicsOptions options) + public BrushApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) { - return new SolidBrushApplicator(sourcePixels, this.color, options); + return new SolidBrushApplicator(source, this.color, options); } /// @@ -55,13 +55,13 @@ namespace ImageSharp.Drawing.Brushes /// /// Initializes a new instance of the class. /// + /// The source image. /// The color. /// The options - /// The sourcePixels. - public SolidBrushApplicator(PixelAccessor sourcePixels, TPixel color, GraphicsOptions options) - : base(sourcePixels, options) + public SolidBrushApplicator(ImageBase source, TPixel color, GraphicsOptions options) + : base(source, options) { - this.Colors = new Buffer(sourcePixels.Width); + this.Colors = new Buffer(source.Width); for (int i = 0; i < this.Colors.Length; i++) { this.Colors[i] = color; @@ -94,7 +94,7 @@ namespace ImageSharp.Drawing.Brushes { Span destinationRow = this.Target.GetRowSpan(x, y).Slice(0, scanline.Length); - using (Buffer amountBuffer = new Buffer(scanline.Length)) + using (var amountBuffer = new Buffer(scanline.Length)) { for (int i = 0; i < scanline.Length; i++) { diff --git a/src/ImageSharp.Drawing/Pens/IPen.cs b/src/ImageSharp.Drawing/Pens/IPen.cs index d488dbfb0..81d273091 100644 --- a/src/ImageSharp.Drawing/Pens/IPen.cs +++ b/src/ImageSharp.Drawing/Pens/IPen.cs @@ -18,7 +18,7 @@ namespace ImageSharp.Drawing.Pens /// /// Creates the applicator for applying this pen to an Image /// - /// The pixel source. + /// The source image. /// The region the pen will be applied to. /// The currently active graphic options. /// @@ -27,6 +27,6 @@ namespace ImageSharp.Drawing.Pens /// /// The when being applied to things like shapes would usually be the bounding box of the shape not necessarily the shape of the whole image. /// - PenApplicator CreateApplicator(PixelAccessor pixelSource, RectangleF region, GraphicsOptions options); + PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options); } } diff --git a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs index 1da50e0d6..53a3c8c99 100644 --- a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs +++ b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs @@ -101,7 +101,7 @@ namespace ImageSharp.Drawing.Pens /// /// Creates the applicator for applying this pen to an Image /// - /// The source pixels. + /// The source image. /// The region the pen will be applied to. /// The Graphics options /// @@ -111,16 +111,16 @@ namespace ImageSharp.Drawing.Pens /// The when being applied to things like shapes would ussually be the /// bounding box of the shape not necorserrally the shape of the whole image /// - public PenApplicator CreateApplicator(PixelAccessor sourcePixels, RectangleF region, GraphicsOptions options) + public PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options) { if (this.pattern == null || this.pattern.Length < 2) { // if there is only one item in the pattern then 100% of it will // be solid so use the quicker applicator - return new SolidPenApplicator(sourcePixels, this.Brush, region, this.Width, options); + return new SolidPenApplicator(source, this.Brush, region, this.Width, options); } - return new PatternPenApplicator(sourcePixels, this.Brush, region, this.Width, this.pattern, options); + return new PatternPenApplicator(source, this.Brush, region, this.Width, this.pattern, options); } private class SolidPenApplicator : PenApplicator @@ -128,7 +128,7 @@ namespace ImageSharp.Drawing.Pens private readonly BrushApplicator brush; private readonly float halfWidth; - public SolidPenApplicator(PixelAccessor sourcePixels, IBrush brush, RectangleF region, float width, GraphicsOptions options) + public SolidPenApplicator(ImageBase sourcePixels, IBrush brush, RectangleF region, float width, GraphicsOptions options) { this.brush = brush.CreateApplicator(sourcePixels, region, options); this.halfWidth = width / 2; @@ -147,7 +147,7 @@ namespace ImageSharp.Drawing.Pens public override ColoredPointInfo GetColor(int x, int y, PointInfo info) { - ColoredPointInfo result = default(ColoredPointInfo); + var result = default(ColoredPointInfo); result.Color = this.brush[x, y]; if (info.DistanceFromPath < this.halfWidth) @@ -171,9 +171,9 @@ namespace ImageSharp.Drawing.Pens private readonly float[] pattern; private readonly float totalLength; - public PatternPenApplicator(PixelAccessor sourcePixels, IBrush brush, RectangleF region, float width, float[] pattern, GraphicsOptions options) + public PatternPenApplicator(ImageBase source, IBrush brush, RectangleF region, float width, float[] pattern, GraphicsOptions options) { - this.brush = brush.CreateApplicator(sourcePixels, region, options); + this.brush = brush.CreateApplicator(source, region, options); this.halfWidth = width / 2; this.totalLength = 0; @@ -200,7 +200,7 @@ namespace ImageSharp.Drawing.Pens public override ColoredPointInfo GetColor(int x, int y, PointInfo info) { - ColoredPointInfo infoResult = default(ColoredPointInfo); + var infoResult = default(ColoredPointInfo); infoResult.DistanceFromElement = float.MaxValue; // is really outside the element float length = info.DistanceAlongPath % this.totalLength; diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs index d1332c435..860c4c4f0 100644 --- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs @@ -56,8 +56,7 @@ namespace ImageSharp.Drawing.Processors /// protected override void OnApply(ImageBase source, Rectangle sourceRectangle) { - using (PixelAccessor sourcePixels = source.Lock()) - using (PenApplicator applicator = this.Pen.CreateApplicator(sourcePixels, this.Path.Bounds, this.Options)) + using (PenApplicator applicator = this.Pen.CreateApplicator(source, this.Path.Bounds, this.Options)) { Rectangle rect = RectangleF.Ceiling(applicator.RequiredRegion); @@ -99,8 +98,8 @@ namespace ImageSharp.Drawing.Processors { int offsetY = y - polyStartY; - using (Buffer amount = new Buffer(width)) - using (Buffer colors = new Buffer(width)) + using (var amount = new Buffer(width)) + using (var colors = new Buffer(width)) { for (int i = 0; i < width; i++) { @@ -112,7 +111,7 @@ namespace ImageSharp.Drawing.Processors colors[i] = color.Color; } - Span destination = sourcePixels.GetRowSpan(offsetY).Slice(minX - startX, width); + Span destination = source.GetRowSpan(offsetY).Slice(minX - startX, width); blender.Blend(destination, destination, colors, amount); } }); diff --git a/src/ImageSharp.Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processors/FillProcessor.cs index fa6f48156..8c7cd4e8c 100644 --- a/src/ImageSharp.Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillProcessor.cs @@ -66,12 +66,11 @@ namespace ImageSharp.Drawing.Processors int width = maxX - minX; - // we could possibly do some optermising by having knowledge about the individual brushes operate + // 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 (PixelAccessor sourcePixels = source.Lock()) - using (Buffer amount = new Buffer(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator(sourcePixels, sourceRectangle, this.options)) + using (var amount = new Buffer(width)) + using (BrushApplicator applicator = this.brush.CreateApplicator(source, sourceRectangle, this.options)) { for (int i = 0; i < width; i++) { diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index a57be3a5a..ae828e112 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -7,6 +7,7 @@ namespace ImageSharp.Drawing.Processors { using System; using System.Buffers; + using System.Runtime.CompilerServices; using Drawing; using ImageSharp.Memory; @@ -89,12 +90,11 @@ namespace ImageSharp.Drawing.Processors } } - using (PixelAccessor sourcePixels = source.Lock()) - using (BrushApplicator applicator = this.Brush.CreateApplicator(sourcePixels, rect, this.Options)) + using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options)) { float[] buffer = arrayPool.Rent(maxIntersections); int scanlineWidth = maxX - minX; - using (Buffer scanline = new Buffer(scanlineWidth)) + using (var scanline = new Buffer(scanlineWidth)) { try { @@ -193,6 +193,7 @@ namespace ImageSharp.Drawing.Processors } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void Swap(float[] data, int left, int right) { float tmp = data[left]; diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs index 7a5fabdb3..0c4192a87 100644 --- a/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs +++ b/src/ImageSharp/Dithering/ErrorDiffusion/ErrorDiffuser.cs @@ -71,7 +71,7 @@ namespace ImageSharp.Dithering /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dither(PixelAccessor pixels, TPixel source, TPixel transformed, int x, int y, int width, int height) + public void Dither(ImageBase pixels, TPixel source, TPixel transformed, int x, int y, int width, int height) where TPixel : struct, IPixel { this.Dither(pixels, source, transformed, x, y, width, height, true); @@ -79,13 +79,13 @@ namespace ImageSharp.Dithering /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Dither(PixelAccessor pixels, TPixel source, TPixel transformed, int x, int y, int width, int height, bool replacePixel) + public void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int width, int height, bool replacePixel) where TPixel : struct, IPixel { if (replacePixel) { // Assign the transformed pixel to the array. - pixels[x, y] = transformed; + image[x, y] = transformed; } // Calculate the error @@ -111,14 +111,14 @@ namespace ImageSharp.Dithering continue; } - Vector4 coefficientVector = new Vector4(coefficient); - Vector4 offsetColor = pixels[matrixX, matrixY].ToVector4(); + var coefficientVector = new Vector4(coefficient); + var offsetColor = image[matrixX, matrixY].ToVector4(); Vector4 result = ((error * coefficientVector) / this.divisorVector) + offsetColor; result.W = offsetColor.W; - TPixel packed = default(TPixel); + var packed = default(TPixel); packed.PackFromVector4(result); - pixels[matrixX, matrixY] = packed; + image[matrixX, matrixY] = packed; } } } diff --git a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs index f49e7e62d..bc785e897 100644 --- a/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs +++ b/src/ImageSharp/Dithering/ErrorDiffusion/IErrorDiffuser.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Dithering /// /// Transforms the image applying the dither matrix. This method alters the input pixels array /// - /// The pixel accessor + /// The image /// The source pixel /// The transformed pixel /// The column index. @@ -23,13 +23,13 @@ namespace ImageSharp.Dithering /// The image width. /// The image height. /// The pixel format. - void Dither(PixelAccessor pixels, TPixel source, TPixel transformed, int x, int y, int width, int height) + void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int width, int height) where TPixel : struct, IPixel; /// /// Transforms the image applying the dither matrix. This method alters the input pixels array /// - /// The pixel accessor + /// The image /// The source pixel /// The transformed pixel /// The column index. @@ -41,7 +41,7 @@ namespace 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(PixelAccessor pixels, TPixel source, TPixel transformed, int x, int y, int width, int height, bool replacePixel) + void Dither(ImageBase image, TPixel source, TPixel transformed, int x, int y, int width, int height, bool replacePixel) where TPixel : struct, IPixel; } } diff --git a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs index 3f7cf4988..c69cddefe 100644 --- a/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs +++ b/src/ImageSharp/Dithering/Ordered/IOrderedDither.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Dithering /// /// Transforms the image applying the dither matrix. This method alters the input pixels array /// - /// The pixel accessor + /// The image /// The source pixel /// The color to apply to the pixels above the threshold. /// The color to apply to the pixels below the threshold. @@ -26,7 +26,7 @@ namespace ImageSharp.Dithering /// The image width. /// The image height. /// The pixel format. - void Dither(PixelAccessor pixels, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y, int width, int height) + void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y, int width, int height) where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs b/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs index 48d6c3f6a..a180888f7 100644 --- a/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs +++ b/src/ImageSharp/Dithering/Ordered/OrderedDither4x4.cs @@ -28,14 +28,14 @@ namespace ImageSharp.Dithering.Ordered } /// - public void Dither(PixelAccessor pixels, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y, int width, int height) + public void Dither(ImageBase image, TPixel source, TPixel upper, TPixel lower, byte[] bytes, int index, int x, int y, int width, int height) where TPixel : struct, IPixel { // TODO: This doesn't really cut it for me. - // I'd rather be using float but we need to add some sort of movalization vector methods to all IPixel implementations + // I'd rather be using float but we need to add some sort of normalization vector methods to all IPixel implementations // before we can do that as the vectors all cover different ranges. source.ToXyzwBytes(bytes, 0); - pixels[x, y] = this.matrix[y % 3, x % 3] >= bytes[index] ? lower : upper; + image[x, y] = this.matrix[y % 3, x % 3] >= bytes[index] ? lower : upper; } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/IImageBase{TPixel}.cs b/src/ImageSharp/Image/IImageBase{TPixel}.cs index 08d25709b..f0ab5b033 100644 --- a/src/ImageSharp/Image/IImageBase{TPixel}.cs +++ b/src/ImageSharp/Image/IImageBase{TPixel}.cs @@ -21,14 +21,5 @@ namespace ImageSharp /// of the array for calculations. Use Width * Height. /// TPixel[] Pixels { get; } - - /// - /// Locks the image providing access to the pixels. - /// - /// It is imperative that the accessor is correctly disposed off after use. - /// - /// - /// The - PixelAccessor Lock(); } } \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageBase{TPixel}.cs b/src/ImageSharp/Image/ImageBase{TPixel}.cs index 4fd9d26cb..f7b294cf0 100644 --- a/src/ImageSharp/Image/ImageBase{TPixel}.cs +++ b/src/ImageSharp/Image/ImageBase{TPixel}.cs @@ -7,6 +7,7 @@ namespace ImageSharp { using System; using System.Diagnostics; + using System.Runtime.CompilerServices; using ImageSharp.Memory; using ImageSharp.PixelFormats; @@ -36,6 +37,11 @@ namespace ImageSharp /// private TPixel[] pixelBuffer; + /// + /// The span representing the pixel buffer + /// + private Span span; + /// /// A value indicating whether this instance of the given entity has been disposed. /// @@ -129,6 +135,67 @@ namespace ImageSharp /// 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)] + public ref TPixel GetPixelReference(int x, int y) + { + this.CheckCoordinates(x, y); + return ref this.pixelBuffer[(y * this.Width) + x]; + } + + /// + /// Gets a representing the row 'y' beginning from the the first pixel on that row. + /// + /// The y-coordinate of the pixel row. Must be greater than or equal to zero and less than the height of the image. + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span GetRowSpan(int y) + { + this.CheckCoordinates(y); + return this.span.Slice(y * this.Width, this.Width); + } + + /// + /// Gets a to the row 'y' beginning from the pixel at 'x'. + /// + /// The x coordinate (position in the row) + /// The y (row) coordinate + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span GetRowSpan(int x, int y) + { + this.CheckCoordinates(x, y); + return this.span.Slice((y * this.Width) + x, this.Width - x); + } + /// /// Applies the processor. /// @@ -152,8 +219,14 @@ namespace ImageSharp GC.SuppressFinalize(this); } - /// - public PixelAccessor Lock() + /// + /// 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); } @@ -174,6 +247,7 @@ namespace ImageSharp this.Width = newWidth; this.Height = newHeight; this.pixelBuffer = newPixels; + this.span = new Span(this.pixelBuffer); } /// @@ -225,6 +299,7 @@ namespace ImageSharp private void RentPixels() { this.pixelBuffer = PixelDataPool.Rent(this.Width * this.Height); + this.span = new Span(this.pixelBuffer); } /// @@ -234,6 +309,7 @@ namespace ImageSharp { PixelDataPool.Return(this.pixelBuffer); this.pixelBuffer = null; + this.span = null; } /// @@ -243,5 +319,43 @@ namespace ImageSharp { 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/PixelAccessor{TPixel}.cs b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs index a54c03b63..240e65c82 100644 --- a/src/ImageSharp/Image/PixelAccessor{TPixel}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TPixel}.cs @@ -17,7 +17,7 @@ namespace ImageSharp /// Provides per-pixel access to generic pixels. /// /// The pixel format. - public sealed class PixelAccessor : IDisposable, IBuffer2D + internal sealed class PixelAccessor : IDisposable, IBuffer2D where TPixel : struct, IPixel { /// @@ -128,12 +128,14 @@ namespace ImageSharp /// The at the specified position. public TPixel this[int x, int y] { + [MethodImpl(MethodImplOptions.AggressiveInlining)] get { this.CheckCoordinates(x, y); return this.PixelArray[(y * this.Width) + x]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.CheckCoordinates(x, y); diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 51e558281..046bfd81f 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -29,7 +29,7 @@ namespace ImageSharp.Memory } /// - /// Gets a to the row 'y' beginning from the pixel at 'x'. + /// Gets a to the row 'y' beginning from the pixel at the first pixel on that row. /// /// The buffer /// The y (row) coordinate diff --git a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs index af2d9f760..cb6f2fce4 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/ErrorDiffusionDitherProcessor.cs @@ -85,18 +85,15 @@ namespace ImageSharp.Processing.Processors startY = 0; } - using (PixelAccessor sourcePixels = source.Lock()) + for (int y = minY; y < maxY; y++) { - for (int y = minY; y < maxY; y++) + int offsetY = y - startY; + for (int x = minX; x < maxX; x++) { - int offsetY = y - startY; - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - TPixel sourceColor = sourcePixels[offsetX, offsetY]; - TPixel transformedColor = sourceColor.ToVector4().X >= this.Threshold ? this.UpperColor : this.LowerColor; - this.Diffuser.Dither(sourcePixels, sourceColor, transformedColor, offsetX, offsetY, maxX, maxY); - } + int offsetX = x - startX; + TPixel sourceColor = source[offsetX, offsetY]; + TPixel transformedColor = sourceColor.ToVector4().X >= this.Threshold ? this.UpperColor : this.LowerColor; + this.Diffuser.Dither(source, sourceColor, transformedColor, offsetX, offsetY, maxX, maxY); } } } diff --git a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs index c4d71d9af..1bdb4d53b 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/OrderedDitherProcessor.cs @@ -93,21 +93,16 @@ namespace ImageSharp.Processing.Processors startY = 0; } - using (PixelAccessor sourcePixels = source.Lock()) + byte[] bytes = new byte[4]; + for (int y = minY; y < maxY; y++) { - for (int y = minY; y < maxY; y++) - { - int offsetY = y - startY; - byte[] bytes = ArrayPool.Shared.Rent(4); - - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - TPixel sourceColor = sourcePixels[offsetX, offsetY]; - this.Dither.Dither(sourcePixels, sourceColor, this.UpperColor, this.LowerColor, bytes, this.Index, offsetX, offsetY, maxX, maxY); - } + int offsetY = y - startY; - ArrayPool.Shared.Return(bytes); + for (int x = minX; x < maxX; x++) + { + int offsetX = x - startX; + TPixel sourceColor = source[offsetX, offsetY]; + this.Dither.Dither(source, sourceColor, this.UpperColor, this.LowerColor, bytes, this.Index, offsetX, offsetY, maxX, maxY); } } } diff --git a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs index 40bce74c3..f41272900 100644 --- a/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs @@ -66,7 +66,7 @@ namespace ImageSharp.Quantizers } /// - protected override void SecondPass(PixelAccessor source, byte[] output, int width, int height) + protected override void SecondPass(ImageBase source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color. @@ -490,7 +490,7 @@ namespace ImageSharp.Quantizers byte b = (this.blue / this.pixelCount).ToByte(); // And set the color of the palette entry - TPixel pixel = default(TPixel); + var pixel = default(TPixel); pixel.PackFromBytes(r, g, b, 255); palette[index] = pixel; diff --git a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs index 7e07da6c3..52d3f320d 100644 --- a/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs @@ -51,7 +51,7 @@ namespace ImageSharp.Quantizers for (int i = 0; i < constants.Length; i++) { constants[i].ToXyzwBytes(this.pixelBuffer, 0); - TPixel packed = default(TPixel); + var packed = default(TPixel); packed.PackFromBytes(this.pixelBuffer[0], this.pixelBuffer[1], this.pixelBuffer[2], this.pixelBuffer[3]); safe[i] = packed; } @@ -72,7 +72,7 @@ namespace ImageSharp.Quantizers } /// - protected override void SecondPass(PixelAccessor source, byte[] output, int width, int height) + protected override void SecondPass(ImageBase source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color. diff --git a/src/ImageSharp/Quantizers/Quantizer{TPixel}.cs b/src/ImageSharp/Quantizers/Quantizer{TPixel}.cs index 48f33f98b..e99402996 100644 --- a/src/ImageSharp/Quantizers/Quantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/Quantizer{TPixel}.cs @@ -54,35 +54,30 @@ namespace ImageSharp.Quantizers int height = image.Height; int width = image.Width; byte[] quantizedPixels = new byte[width * height]; - TPixel[] colorPalette; - using (PixelAccessor pixels = image.Lock()) + // Call the FirstPass function if not a single pass algorithm. + // For something like an Octree quantizer, this will run through + // all image pixels, build a data structure, and create a palette. + if (!this.singlePass) { - // Call the FirstPass function if not a single pass algorithm. - // For something like an Octree quantizer, this will run through - // all image pixels, build a data structure, and create a palette. - if (!this.singlePass) - { - this.FirstPass(pixels, width, height); - } + this.FirstPass(image, width, height); + } - // Collect the palette. Required before the second pass runs. - colorPalette = this.GetPalette(); + // Collect the palette. Required before the second pass runs. + TPixel[] colorPalette = this.GetPalette(); - if (this.Dither) - { - // We clone the image as we don't want to alter the original. - using (Image clone = new Image(image)) - using (PixelAccessor clonedPixels = clone.Lock()) - { - this.SecondPass(clonedPixels, quantizedPixels, width, height); - } - } - else + if (this.Dither) + { + // We clone the image as we don't want to alter the original. + using (var clone = new Image(image)) { - this.SecondPass(pixels, quantizedPixels, width, height); + this.SecondPass(clone, quantizedPixels, width, height); } } + else + { + this.SecondPass(image, quantizedPixels, width, height); + } return new QuantizedImage(width, height, colorPalette, quantizedPixels); } @@ -93,7 +88,7 @@ namespace ImageSharp.Quantizers /// The source data /// The width in pixels of the image. /// The height in pixels of the image. - protected virtual void FirstPass(PixelAccessor source, int width, int height) + protected virtual void FirstPass(ImageBase source, int width, int height) { // Loop through each row for (int y = 0; y < height; y++) @@ -114,7 +109,7 @@ namespace ImageSharp.Quantizers /// The output pixel array /// The width in pixels of the image /// The height in pixels of the image - protected abstract void SecondPass(PixelAccessor source, byte[] output, int width, int height); + protected abstract void SecondPass(ImageBase source, byte[] output, int width, int height); /// /// Override this to process the pixel in the first pass of the algorithm @@ -155,7 +150,7 @@ namespace ImageSharp.Quantizers // Not found - loop through the palette and find the nearest match. byte colorIndex = 0; float leastDistance = int.MaxValue; - Vector4 vector = pixel.ToVector4(); + var vector = pixel.ToVector4(); for (int index = 0; index < colorPalette.Length; index++) { diff --git a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs index fb63c9dcd..8d98a29d8 100644 --- a/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs @@ -183,7 +183,7 @@ namespace ImageSharp.Quantizers float b = Volume(this.colorCube[k], this.vmb) / weight; float a = Volume(this.colorCube[k], this.vma) / weight; - TPixel color = default(TPixel); + var color = default(TPixel); color.PackFromVector4(new Vector4(r, g, b, a) / 255F); this.palette[k] = color; } @@ -221,7 +221,7 @@ namespace ImageSharp.Quantizers } /// - protected override void FirstPass(PixelAccessor source, int width, int height) + protected override void FirstPass(ImageBase source, int width, int height) { // Build up the 3-D color histogram // Loop through each row @@ -240,7 +240,7 @@ namespace ImageSharp.Quantizers } /// - protected override void SecondPass(PixelAccessor source, byte[] output, int width, int height) + protected override void SecondPass(ImageBase source, byte[] output, int width, int height) { // Load up the values for the first pixel. We can use these to speed up the second // pass of the algorithm by avoiding transforming rows of identical color.