From 5a1569f499a314a5a8b321f519b0d50d0026a874 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Sun, 29 Apr 2018 17:33:39 +0200 Subject: [PATCH 01/12] Added fast path for SolidBrush in FillProcessor. --- .../Drawing/Brushes/SolidBrush{TPixel}.cs | 21 ++++-- .../Drawing/Processors/FillProcessor.cs | 66 ++++++++++++------- 2 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs index 826f5f60a7..f2054ee0d7 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/SolidBrush{TPixel}.cs @@ -90,16 +90,23 @@ internal override void Apply(Span scanline, int x, int y) MemoryManager memoryManager = this.Target.MemoryManager; - using (IBuffer amountBuffer = memoryManager.Allocate(scanline.Length)) + if (this.Options.BlendPercentage == 1f) { - Span amountSpan = amountBuffer.Span; - - for (int i = 0; i < scanline.Length; i++) + this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, scanline); + } + else + { + using (IBuffer amountBuffer = memoryManager.Allocate(scanline.Length)) { - amountSpan[i] = scanline[i] * this.Options.BlendPercentage; - } + Span amountSpan = amountBuffer.Span; + + for (int i = 0; i < scanline.Length; i++) + { + amountSpan[i] = scanline[i] * this.Options.BlendPercentage; + } - this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan); + this.Blender.Blend(memoryManager, destinationRow, destinationRow, this.Colors.Span, amountSpan); + } } } } diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs index e4ef44564e..0ef7db419e 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs @@ -3,6 +3,7 @@ using System; using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Drawing.Brushes; @@ -49,38 +50,57 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } - - if (minY > 0) - { - startY = 0; - } - int width = maxX - minX; - using (IBuffer amount = source.MemoryManager.Allocate(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator( - source, - sourceRectangle, - this.options)) - { - amount.Span.Fill(this.options.BlendPercentage); + var solidBrush = this.brush as SolidBrush; + // If there's no reason for blending, then avoid it. + if (solidBrush != null && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().Z == 1f) + { Parallel.For( minY, maxY, configuration.ParallelOptions, y => - { - int offsetY = y - startY; - int offsetX = minX - startX; + { + int offsetY = y - startY; + int offsetX = minX - startX; + source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); + }); + } + else + { + // Reset offset if necessary. + if (minX > 0) + { + startX = 0; + } + + if (minY > 0) + { + startY = 0; + } + + using (IBuffer amount = source.MemoryManager.Allocate(width)) + using (BrushApplicator applicator = this.brush.CreateApplicator( + source, + sourceRectangle, + this.options)) + { + amount.Span.Fill(this.options.BlendPercentage); + + Parallel.For( + minY, + maxY, + configuration.ParallelOptions, + y => + { + int offsetY = y - startY; + int offsetX = minX - startX; - applicator.Apply(amount.Span, offsetX, offsetY); - }); + applicator.Apply(amount.Span, offsetX, offsetY); + }); + } } } } From 08b033c684c4d693310826dd1388c6da24ca12cf Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Sun, 29 Apr 2018 17:45:02 +0200 Subject: [PATCH 02/12] Oops, should be W instead of Z ofcourse. --- .../Processing/Drawing/Processors/FillProcessor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs index 0ef7db419e..c3addaf29f 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs @@ -55,7 +55,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source var solidBrush = this.brush as SolidBrush; // If there's no reason for blending, then avoid it. - if (solidBrush != null && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().Z == 1f) + if (solidBrush != null && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) { Parallel.For( minY, From 58384de0c7b884bd6f30fa495aba8a95217569d6 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Sun, 29 Apr 2018 20:19:35 +0200 Subject: [PATCH 03/12] Add Image and ImageFrame constructors that take a clear color as parameter. This is good for performance because this avoids first needing to clear the buffer with zeroes. --- src/ImageSharp/ImageFrameCollection.cs | 20 ++++++++++-- src/ImageSharp/Image{TPixel}.cs | 40 +++++++++++++++++++++++ src/ImageSharp/Memory/BufferExtensions.cs | 12 +++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index a9225eec49..1c00d9e633 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -23,7 +23,14 @@ internal ImageFrameCollection(Image parent, int width, int height) this.parent = parent; // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration().MemoryManager, width, height)); + if (parent.ClearColor.HasValue) + { + this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, parent.ClearColor.Value)); + } + else + { + this.frames.Add(new ImageFrame(parent.GetConfiguration().MemoryManager, width, height)); + } } internal ImageFrameCollection(Image parent, IEnumerable> frames) @@ -143,7 +150,16 @@ public Image CloneFrame(int index) /// public ImageFrame CreateFrame() { - var frame = new ImageFrame(this.parent.GetConfiguration().MemoryManager, this.RootFrame.Width, this.RootFrame.Height); + ImageFrame frame; + if (this.parent.ClearColor.HasValue) + { + frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.parent.ClearColor.Value); + } + else + { + frame = new ImageFrame(this.parent.GetConfiguration().MemoryManager, this.RootFrame.Width, this.RootFrame.Height); + } + this.frames.Add(frame); return frame; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 78a091e414..2aa5038440 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -22,6 +22,7 @@ public sealed class Image : IImage, IConfigurable { private readonly Configuration configuration; private readonly ImageFrameCollection frames; + private readonly TPixel? clearColor; /// /// Initializes a new instance of the class @@ -37,6 +38,21 @@ public Image(Configuration configuration, int width, int height) { } + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The color to initialize the pixels with. + public Image(Configuration configuration, int width, int height, TPixel clearColor) + : this(configuration, width, height, clearColor, new ImageMetaData()) + { + } + /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -66,6 +82,25 @@ internal Image(Configuration configuration, int width, int height, ImageMetaData this.frames = new ImageFrameCollection(this, width, height); } + /// + /// Initializes a new instance of the class + /// with the height and the width of the image. + /// + /// + /// The configuration providing initialization code which allows extending the library. + /// + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The clear color. + /// The images metadata. + internal Image(Configuration configuration, int width, int height, TPixel clearColor, ImageMetaData metadata) { + this.configuration = configuration ?? Configuration.Default; + this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); + this.MetaData = metadata ?? new ImageMetaData(); + this.clearColor = clearColor; + this.frames = new ImageFrameCollection(this, width, height); + } + /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -104,6 +139,11 @@ internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable< /// public IImageFrameCollection Frames => this.frames; + /// + /// Gets the clear color to initialize the image frame pixels with. + /// + internal TPixel? ClearColor => this.clearColor; + /// /// Gets the root frame. /// diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/BufferExtensions.cs index dd3114c21c..1347f28821 100644 --- a/src/ImageSharp/Memory/BufferExtensions.cs +++ b/src/ImageSharp/Memory/BufferExtensions.cs @@ -52,6 +52,18 @@ public static void Clear(this IBuffer buffer) buffer.Span.Clear(); } + /// + /// Fills the contents of this buffer. + /// + /// The buffer + /// The value to fill the buffer with. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Fill(this IBuffer buffer, T value) + where T : struct + { + buffer.Span.Fill(value); + } + public static ref T DangerousGetPinnableReference(this IBuffer buffer) where T : struct => ref MemoryMarshal.GetReference(buffer.Span); From 8995a738aa2e98acf8e52457a35af0ba3ac5bc55 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Sun, 29 Apr 2018 21:36:03 +0200 Subject: [PATCH 04/12] Processed Scott's review comment. --- .../Drawing/Processors/FillProcessor.cs | 6 ++++- .../PixelFormats/PixelBlenderMode.cs | 24 +++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs index c3addaf29f..3417b8faaa 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs @@ -55,7 +55,11 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source var solidBrush = this.brush as SolidBrush; // If there's no reason for blending, then avoid it. - if (solidBrush != null && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) + if (solidBrush != null && + ( + (this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || + (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || + (this.options.BlenderMode == PixelBlenderMode.Src))) { Parallel.For( minY, diff --git a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs index 4b8f56d766..7a8ab6592a 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenderMode.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenderMode.cs @@ -54,62 +54,62 @@ public enum PixelBlenderMode HardLight, /// - /// returns the source colors + /// returns the source colors. /// Src, /// - /// returns the source over the destination + /// returns the source over the destination. /// Atop, /// - /// returns the detination over the source + /// returns the destination over the source. /// Over, /// - /// the source where the desitnation and source overlap + /// The source where the destination and source overlap. /// In, /// - /// the destination where the desitnation and source overlap + /// The destination where the destination and source overlap. /// Out, /// - /// the destination where the source does not overlap it + /// The destination where the source does not overlap it. /// Dest, /// - /// the source where they dont overlap othersie dest in overlapping parts + /// The source where they don't overlap othersie dest in overlapping parts. /// DestAtop, /// - /// the destnation over the source + /// The destination over the source. /// DestOver, /// - /// the destination where the desitnation and source overlap + /// The destination where the destination and source overlap. /// DestIn, /// - /// the source where the desitnation and source overlap + /// The source where the destination and source overlap. /// DestOut, /// - /// the clear. + /// The clear. /// Clear, /// - /// clear where they overlap + /// Clear where they overlap. /// Xor } From 02fc4ef43b7834f4d0e7de927de0ec41a5725afe Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Sun, 29 Apr 2018 23:19:28 +0200 Subject: [PATCH 05/12] I think I forgot to commit this one. --- src/ImageSharp/ImageFrame{TPixel}.cs | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index cf7a1ae4fc..cb15fe3db2 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; @@ -52,6 +53,39 @@ internal ImageFrame(MemoryManager memoryManager, int width, int height, ImageFra this.MetaData = metaData; } + /// + /// Initializes a new instance of the class. + /// + /// The to use for buffer allocation and parallel options to clear the buffer with. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The color to clear the image with. + internal ImageFrame(Configuration configuration, int width, int height, TPixel clearColor) + : this(configuration, width, height, clearColor, new ImageFrameMetaData()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The to use for buffer allocation and parallel options to clear the buffer with. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The color to clear the image with. + /// The meta data. + internal ImageFrame(Configuration configuration, int width, int height, TPixel clearColor, ImageFrameMetaData metaData) + { + Guard.NotNull(configuration, nameof(configuration)); + Guard.MustBeGreaterThan(width, 0, nameof(width)); + Guard.MustBeGreaterThan(height, 0, nameof(height)); + Guard.NotNull(metaData, nameof(metaData)); + + this.MemoryManager = configuration.MemoryManager; + this.PixelBuffer = this.MemoryManager.Allocate2D(width, height, false); + this.Clear(configuration.ParallelOptions, clearColor); + this.MetaData = metaData; + } + /// /// Initializes a new instance of the class. /// @@ -267,6 +301,23 @@ internal ImageFrame CloneAs() return target; } + /// + /// Clears the bitmap. + /// + /// The parallel options. + /// The value to initialize the bitmap with. + public void Clear(ParallelOptions parallelOptions, TPixel value) { + Parallel.For( + 0, + this.Height, + parallelOptions, + (int y) => + { + Span targetRow = this.GetPixelRowSpan(y); + targetRow.Fill(value); + }); + } + /// /// Clones the current instance. /// From 2943df12d751fcfb67d7b5239da1041079cee871 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Mon, 30 Apr 2018 10:27:21 +0200 Subject: [PATCH 06/12] Processed review comment, made ClearColor not nullable. --- src/ImageSharp/ImageFrameCollection.cs | 20 ++------------------ src/ImageSharp/Image{TPixel}.cs | 4 ++-- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 1c00d9e633..f2e35812b5 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -23,14 +23,7 @@ internal ImageFrameCollection(Image parent, int width, int height) this.parent = parent; // Frames are already cloned within the caller - if (parent.ClearColor.HasValue) - { - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, parent.ClearColor.Value)); - } - else - { - this.frames.Add(new ImageFrame(parent.GetConfiguration().MemoryManager, width, height)); - } + this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, parent.ClearColor)); } internal ImageFrameCollection(Image parent, IEnumerable> frames) @@ -150,16 +143,7 @@ public Image CloneFrame(int index) /// public ImageFrame CreateFrame() { - ImageFrame frame; - if (this.parent.ClearColor.HasValue) - { - frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.parent.ClearColor.Value); - } - else - { - frame = new ImageFrame(this.parent.GetConfiguration().MemoryManager, this.RootFrame.Width, this.RootFrame.Height); - } - + ImageFrame frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.parent.ClearColor); this.frames.Add(frame); return frame; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 2aa5038440..599116414a 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -22,7 +22,7 @@ public sealed class Image : IImage, IConfigurable { private readonly Configuration configuration; private readonly ImageFrameCollection frames; - private readonly TPixel? clearColor; + private readonly TPixel clearColor; /// /// Initializes a new instance of the class @@ -142,7 +142,7 @@ internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable< /// /// Gets the clear color to initialize the image frame pixels with. /// - internal TPixel? ClearColor => this.clearColor; + internal TPixel ClearColor => this.clearColor; /// /// Gets the root frame. From aa4a05719fbd011cd4a28f73eb248012b0db20e0 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Mon, 30 Apr 2018 18:22:19 +0200 Subject: [PATCH 07/12] Processed review comments, moved Image.ClearColor to ImageFrame.BackgroundColor. --- src/ImageSharp/ImageFrameCollection.cs | 6 ++-- src/ImageSharp/ImageFrame{TPixel}.cs | 30 ++++++++++--------- src/ImageSharp/Image{TPixel}.cs | 21 +++++-------- src/ImageSharp/Memory/BufferExtensions.cs | 12 -------- .../Image/ImageFramesCollectionTests.cs | 2 +- 5 files changed, 27 insertions(+), 44 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index f2e35812b5..1d4735fd8e 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -16,14 +16,14 @@ internal sealed class ImageFrameCollection : IImageFrameCollection> frames = new List>(); private readonly Image parent; - internal ImageFrameCollection(Image parent, int width, int height) + internal ImageFrameCollection(Image parent, int width, int height, TPixel backgroundColor) { Guard.NotNull(parent, nameof(parent)); this.parent = parent; // Frames are already cloned within the caller - this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, parent.ClearColor)); + this.frames.Add(new ImageFrame(parent.GetConfiguration(), width, height, backgroundColor)); } internal ImageFrameCollection(Image parent, IEnumerable> frames) @@ -143,7 +143,7 @@ public Image CloneFrame(int index) /// public ImageFrame CreateFrame() { - ImageFrame frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.parent.ClearColor); + var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.RootFrame.BackgroundColor); this.frames.Add(frame); return frame; } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index cb15fe3db2..1c26bb5582 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -19,8 +19,7 @@ namespace SixLabors.ImageSharp /// /// The pixel format. public sealed class ImageFrame : IPixelSource, IDisposable - where TPixel : struct, IPixel - { + where TPixel : struct, IPixel { private bool isDisposed; /// @@ -30,8 +29,7 @@ public sealed class ImageFrame : IPixelSource, IDisposable /// The width of the image in pixels. /// The height of the image in pixels. internal ImageFrame(MemoryManager memoryManager, int width, int height) - : this(memoryManager, width, height, new ImageFrameMetaData()) - { + : this(memoryManager, width, height, new ImageFrameMetaData()) { } /// @@ -59,10 +57,9 @@ internal ImageFrame(MemoryManager memoryManager, int width, int height, ImageFra /// The to use for buffer allocation and parallel options to clear the buffer with. /// The width of the image in pixels. /// The height of the image in pixels. - /// The color to clear the image with. - internal ImageFrame(Configuration configuration, int width, int height, TPixel clearColor) - : this(configuration, width, height, clearColor, new ImageFrameMetaData()) - { + /// The color to clear the image with. + internal ImageFrame(Configuration configuration, int width, int height, TPixel backgroundColor) + : this(configuration, width, height, backgroundColor, new ImageFrameMetaData()) { } /// @@ -71,9 +68,9 @@ internal ImageFrame(Configuration configuration, int width, int height, TPixel c /// The to use for buffer allocation and parallel options to clear the buffer with. /// The width of the image in pixels. /// The height of the image in pixels. - /// The color to clear the image with. + /// The color to clear the image with. /// The meta data. - internal ImageFrame(Configuration configuration, int width, int height, TPixel clearColor, ImageFrameMetaData metaData) + internal ImageFrame(Configuration configuration, int width, int height, TPixel backgroundColor, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); @@ -82,7 +79,8 @@ internal ImageFrame(Configuration configuration, int width, int height, TPixel c this.MemoryManager = configuration.MemoryManager; this.PixelBuffer = this.MemoryManager.Allocate2D(width, height, false); - this.Clear(configuration.ParallelOptions, clearColor); + this.BackgroundColor = backgroundColor; + this.Clear(configuration.ParallelOptions, backgroundColor); this.MetaData = metaData; } @@ -93,8 +91,7 @@ internal ImageFrame(Configuration configuration, int width, int height, TPixel c /// The of the frame. /// The meta data. internal ImageFrame(MemoryManager memoryManager, Size size, ImageFrameMetaData metaData) - : this(memoryManager, size.Width, size.Height, metaData) - { + : this(memoryManager, size.Width, size.Height, metaData) { } /// @@ -133,6 +130,11 @@ internal ImageFrame(MemoryManager memoryManager, ImageFrame source) /// public int Height => this.PixelBuffer.Height; + /// + /// Gets the background color. + /// + public TPixel BackgroundColor { get; } + /// /// Gets the meta data of the frame. /// @@ -306,7 +308,7 @@ internal ImageFrame CloneAs() /// /// The parallel options. /// The value to initialize the bitmap with. - public void Clear(ParallelOptions parallelOptions, TPixel value) { + internal void Clear(ParallelOptions parallelOptions, TPixel value) { Parallel.For( 0, this.Height, diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 599116414a..2d98696028 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -22,7 +22,6 @@ public sealed class Image : IImage, IConfigurable { private readonly Configuration configuration; private readonly ImageFrameCollection frames; - private readonly TPixel clearColor; /// /// Initializes a new instance of the class @@ -47,9 +46,9 @@ public Image(Configuration configuration, int width, int height) /// /// The width of the image in pixels. /// The height of the image in pixels. - /// The color to initialize the pixels with. - public Image(Configuration configuration, int width, int height, TPixel clearColor) - : this(configuration, width, height, clearColor, new ImageMetaData()) + /// The color to initialize the pixels with. + public Image(Configuration configuration, int width, int height, TPixel backgroundColor) + : this(configuration, width, height, backgroundColor, new ImageMetaData()) { } @@ -79,7 +78,7 @@ internal Image(Configuration configuration, int width, int height, ImageMetaData this.configuration = configuration ?? Configuration.Default; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, width, height); + this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); } /// @@ -91,14 +90,13 @@ internal Image(Configuration configuration, int width, int height, ImageMetaData /// /// The width of the image in pixels. /// The height of the image in pixels. - /// The clear color. + /// The color to initialize the pixels with. /// The images metadata. - internal Image(Configuration configuration, int width, int height, TPixel clearColor, ImageMetaData metadata) { + internal Image(Configuration configuration, int width, int height, TPixel backgroundColor, ImageMetaData metadata) { this.configuration = configuration ?? Configuration.Default; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.clearColor = clearColor; - this.frames = new ImageFrameCollection(this, width, height); + this.frames = new ImageFrameCollection(this, width, height, backgroundColor); } /// @@ -139,11 +137,6 @@ internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable< /// public IImageFrameCollection Frames => this.frames; - /// - /// Gets the clear color to initialize the image frame pixels with. - /// - internal TPixel ClearColor => this.clearColor; - /// /// Gets the root frame. /// diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/BufferExtensions.cs index 1347f28821..dd3114c21c 100644 --- a/src/ImageSharp/Memory/BufferExtensions.cs +++ b/src/ImageSharp/Memory/BufferExtensions.cs @@ -52,18 +52,6 @@ public static void Clear(this IBuffer buffer) buffer.Span.Clear(); } - /// - /// Fills the contents of this buffer. - /// - /// The buffer - /// The value to fill the buffer with. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Fill(this IBuffer buffer, T value) - where T : struct - { - buffer.Span.Fill(value); - } - public static ref T DangerousGetPinnableReference(this IBuffer buffer) where T : struct => ref MemoryMarshal.GetReference(buffer.Span); diff --git a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs index 4c760e6810..cb185d9773 100644 --- a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs @@ -19,7 +19,7 @@ public ImageFramesCollectionTests() System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en-US"); this.image = new Image(10, 10); - this.collection = new ImageFrameCollection(this.image, 10, 10); + this.collection = new ImageFrameCollection(this.image, 10, 10, default); } [Fact] From 7c70a5efcfd4b6be1c0a4a1f4d588a8a869128a4 Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Tue, 1 May 2018 10:36:20 +0200 Subject: [PATCH 08/12] Processed review comments, removed ImageFrame.BackgroundColor property. --- src/ImageSharp/ImageFrameCollection.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 1d4735fd8e..eb118979c8 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -143,7 +143,7 @@ public Image CloneFrame(int index) /// public ImageFrame CreateFrame() { - var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, this.RootFrame.BackgroundColor); + var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, default); this.frames.Add(frame); return frame; } diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 1c26bb5582..c3955c1321 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -79,7 +79,6 @@ internal ImageFrame(Configuration configuration, int width, int height, TPixel b this.MemoryManager = configuration.MemoryManager; this.PixelBuffer = this.MemoryManager.Allocate2D(width, height, false); - this.BackgroundColor = backgroundColor; this.Clear(configuration.ParallelOptions, backgroundColor); this.MetaData = metaData; } @@ -130,11 +129,6 @@ internal ImageFrame(MemoryManager memoryManager, ImageFrame source) /// public int Height => this.PixelBuffer.Height; - /// - /// Gets the background color. - /// - public TPixel BackgroundColor { get; } - /// /// Gets the meta data of the frame. /// From 0d81089159548ff584bf0519fa7c7ba880f5030c Mon Sep 17 00:00:00 2001 From: woutware <35376607+woutware@users.noreply.github.com> Date: Tue, 1 May 2018 15:14:34 +0200 Subject: [PATCH 09/12] Processed review comments, removed IImageFrameCollection interface, and added backgroundColor parameter to ImageFrameCollection.CreateFrame() method with default. --- src/ImageSharp/IImageFrameCollection.cs | 115 ---------------------- src/ImageSharp/ImageFrameCollection.cs | 123 ++++++++++++++++++------ src/ImageSharp/Image{TPixel}.cs | 2 +- 3 files changed, 94 insertions(+), 146 deletions(-) delete mode 100644 src/ImageSharp/IImageFrameCollection.cs diff --git a/src/ImageSharp/IImageFrameCollection.cs b/src/ImageSharp/IImageFrameCollection.cs deleted file mode 100644 index 59c64a6af6..0000000000 --- a/src/ImageSharp/IImageFrameCollection.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; - -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp -{ - /// - /// Encapsulates a collection of instances that make up an . - /// - /// The type of the pixel. - public interface IImageFrameCollection : IEnumerable> - where TPixel : struct, IPixel - { - /// - /// Gets the number of frames. - /// - int Count { get; } - - /// - /// Gets the root frame. - /// - ImageFrame RootFrame { get; } - - /// - /// Gets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// The at the specified index. - ImageFrame this[int index] { get; } - - /// - /// Creates an with only the frame at the specified index - /// with the same metadata as the original image. - /// - /// The zero-based index of the frame to clone. - /// The new with the specified frame. - Image CloneFrame(int index); - - /// - /// Removes the frame at the specified index and creates a new image with only the removed frame - /// with the same metadata as the original image. - /// - /// The zero-based index of the frame to export. - /// Cannot remove last frame. - /// The new with the specified frame. - Image ExportFrame(int index); - - /// - /// Removes the frame at the specified index and frees all freeable resources associated with it. - /// - /// The zero-based index of the frame to remove. - /// Cannot remove last frame. - void RemoveFrame(int index); - - /// - /// Creates a new and appends it to the end of the collection. - /// - /// The new . - ImageFrame CreateFrame(); - - /// - /// Clones the frame and appends the clone to the end of the collection. - /// - /// The raw pixel data to generate the from. - /// The cloned . - ImageFrame AddFrame(ImageFrame source); - - /// - /// Creates a new frame from the pixel data with the same dimensions as the other frames and inserts the - /// new frame at the end of the collection. - /// - /// The raw pixel data to generate the from. - /// The new . - ImageFrame AddFrame(TPixel[] source); - - /// - /// Clones and inserts the into the at the specified . - /// - /// The zero-based index to insert the frame at. - /// The to clone and insert into the . - /// Frame must have the same dimensions as the image. - /// The cloned . - ImageFrame InsertFrame(int index, ImageFrame source); - - /// - /// Moves an from to . - /// - /// The zero-based index of the frame to move. - /// The index to move the frame to. - void MoveFrame(int sourceIndex, int destinationIndex); - - /// - /// 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); - - /// - /// Determines whether the contains the . - /// - /// The frame. - /// - /// true if the contains the specified frame; otherwise, false. - /// - bool Contains(ImageFrame frame); - } -} \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index eb118979c8..97a8df875d 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -9,8 +9,11 @@ namespace SixLabors.ImageSharp { - /// - internal sealed class ImageFrameCollection : IImageFrameCollection + /// + /// Encapsulates a collection of instances that make up an . + /// + /// The type of the pixel. + public sealed class ImageFrameCollection : IEnumerable> where TPixel : struct, IPixel { private readonly IList> frames = new List>(); @@ -41,51 +44,85 @@ internal ImageFrameCollection(Image parent, IEnumerable + /// + /// Gets the number of frames. + /// public int Count => this.frames.Count; - /// + /// + /// Gets the root frame. + /// public ImageFrame RootFrame => this.frames.Count > 0 ? this.frames[0] : null; - /// + /// + /// Gets the at the specified index. + /// + /// + /// The . + /// + /// The index. + /// The at the specified index. public ImageFrame this[int index] => this.frames[index]; - /// + /// + /// 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); - /// - public ImageFrame InsertFrame(int index, ImageFrame frame) + /// + /// Clones and inserts the into the at the specified . + /// + /// The zero-based index to insert the frame at. + /// The to clone and insert into the . + /// Frame must have the same dimensions as the image. + /// The cloned . + public ImageFrame InsertFrame(int index, ImageFrame source) { - this.ValidateFrame(frame); - ImageFrame clonedFrame = frame.Clone(); + this.ValidateFrame(source); + ImageFrame clonedFrame = source.Clone(); this.frames.Insert(index, clonedFrame); return clonedFrame; } - /// - public ImageFrame AddFrame(ImageFrame frame) + /// + /// Clones the frame and appends the clone to the end of the collection. + /// + /// The raw pixel data to generate the from. + /// The cloned . + public ImageFrame AddFrame(ImageFrame source) { - this.ValidateFrame(frame); - ImageFrame clonedFrame = frame.Clone(); + this.ValidateFrame(source); + ImageFrame clonedFrame = source.Clone(); this.frames.Add(clonedFrame); return clonedFrame; } - /// - public ImageFrame AddFrame(TPixel[] data) + /// + /// Creates a new frame from the pixel data with the same dimensions as the other frames and inserts the + /// new frame at the end of the collection. + /// + /// The raw pixel data to generate the from. + /// The new . + public ImageFrame AddFrame(TPixel[] source) { - Guard.NotNull(data, nameof(data)); + Guard.NotNull(source, nameof(source)); var frame = ImageFrame.LoadPixelData( this.parent.GetMemoryManager(), - new Span(data), + new Span(source), this.RootFrame.Width, this.RootFrame.Height); this.frames.Add(frame); return frame; } - /// + /// + /// Removes the frame at the specified index and frees all freeable resources associated with it. + /// + /// The zero-based index of the frame to remove. + /// Cannot remove last frame. public void RemoveFrame(int index) { if (index == 0 && this.Count == 1) @@ -98,26 +135,42 @@ public void RemoveFrame(int index) frame.Dispose(); } - /// + /// + /// Determines whether the contains the . + /// + /// The frame. + /// + /// true if the contains the specified frame; otherwise, false. + /// public bool Contains(ImageFrame frame) { return this.frames.Contains(frame); } - /// - public void MoveFrame(int sourceIndex, int destIndex) + /// + /// Moves an from to . + /// + /// The zero-based index of the frame to move. + /// The index to move the frame to. + public void MoveFrame(int sourceIndex, int destinationIndex) { - if (sourceIndex == destIndex) + if (sourceIndex == destinationIndex) { return; } ImageFrame frameAtIndex = this.frames[sourceIndex]; this.frames.RemoveAt(sourceIndex); - this.frames.Insert(destIndex, frameAtIndex); + this.frames.Insert(destinationIndex, frameAtIndex); } - /// + /// + /// Removes the frame at the specified index and creates a new image with only the removed frame + /// with the same metadata as the original image. + /// + /// The zero-based index of the frame to export. + /// Cannot remove last frame. + /// The new with the specified frame. public Image ExportFrame(int index) { ImageFrame frame = this[index]; @@ -132,7 +185,12 @@ public Image ExportFrame(int index) return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); } - /// + /// + /// Creates an with only the frame at the specified index + /// with the same metadata as the original image. + /// + /// The zero-based index of the frame to clone. + /// The new with the specified frame. public Image CloneFrame(int index) { ImageFrame frame = this[index]; @@ -140,10 +198,15 @@ public Image CloneFrame(int index) return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); } - /// - public ImageFrame CreateFrame() - { - var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, default); + /// + /// Creates a new and appends it to the end of the collection. + /// + /// The background color to initialize the pixels with. + /// + /// The new . + /// + public ImageFrame CreateFrame(TPixel backgroundColor = default) { + var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, backgroundColor); this.frames.Add(frame); return frame; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 2d98696028..596dc9bcd0 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -135,7 +135,7 @@ internal Image(Configuration configuration, ImageMetaData metadata, IEnumerable< /// /// Gets the frames. /// - public IImageFrameCollection Frames => this.frames; + public ImageFrameCollection Frames => this.frames; /// /// Gets the root frame. From 24f6ff98f8e7014169c71dc0f650a9a07393254a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 1 May 2018 18:00:43 +0200 Subject: [PATCH 10/12] minor code cleanup in FillProcessor.cs --- .../Drawing/Processors/FillProcessor.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs index 44329e3597..645ff03537 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs @@ -52,14 +52,8 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source int width = maxX - minX; - var solidBrush = this.brush as SolidBrush; - // If there's no reason for blending, then avoid it. - if (solidBrush != null && - ( - (this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || - (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || - (this.options.BlenderMode == PixelBlenderMode.Src))) + if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) { Parallel.For( minY, @@ -67,8 +61,6 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source configuration.ParallelOptions, y => { - int offsetY = y - startY; - int offsetX = minX - startX; source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); }); } @@ -107,5 +99,17 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { + solidBrush = this.brush as SolidBrush; + + return solidBrush != null + && ((this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f + && solidBrush.Color.ToVector4().W == 1f) + || (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f + && solidBrush.Color.ToVector4().W == 1f) + || (this.options.BlenderMode == PixelBlenderMode.Src)); + } } } \ No newline at end of file From a9816fd937341598ad4bdd7e793ab289caf30253 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 1 May 2018 18:33:44 +0200 Subject: [PATCH 11/12] use overloading in ImageFrameCollection + more tests for API-s affected by the PR --- src/ImageSharp/ImageFrameCollection.cs | 20 ++++++- .../Image/ImageFramesCollectionTests.cs | 13 +++- tests/ImageSharp.Tests/Image/ImageTests.cs | 60 +++++++++++++++++-- .../TestUtilities/TestImageExtensions.cs | 15 ++++- 4 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 97a8df875d..0318a7068d 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -198,6 +198,17 @@ public Image CloneFrame(int index) return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); } + /// + /// Creates a new and appends it to the end of the collection. + /// + /// + /// The new . + /// + public ImageFrame CreateFrame() + { + return this.CreateFrame(default); + } + /// /// Creates a new and appends it to the end of the collection. /// @@ -205,8 +216,13 @@ public Image CloneFrame(int index) /// /// The new . /// - public ImageFrame CreateFrame(TPixel backgroundColor = default) { - var frame = new ImageFrame(this.parent.GetConfiguration(), this.RootFrame.Width, this.RootFrame.Height, backgroundColor); + public ImageFrame CreateFrame(TPixel backgroundColor) + { + var frame = new ImageFrame( + this.parent.GetConfiguration(), + this.RootFrame.Width, + this.RootFrame.Height, + backgroundColor); this.frames.Add(frame); return frame; } diff --git a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs index cb185d9773..c2ebf83ba7 100644 --- a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs @@ -225,10 +225,21 @@ public void ExtractFrame(TestImageProvider provider) } [Fact] - public void CreateFrame() + public void CreateFrame_Default() { this.image.Frames.CreateFrame(); + + Assert.Equal(2, this.image.Frames.Count); + this.image.Frames[1].ComparePixelBufferTo(default(Rgba32)); + } + + [Fact] + public void CreateFrame_CustomFillColor() + { + this.image.Frames.CreateFrame(Rgba32.HotPink); + Assert.Equal(2, this.image.Frames.Count); + this.image.Frames[1].ComparePixelBufferTo(Rgba32.HotPink); } [Fact] diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index da813f4280..8234df24ef 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -13,10 +13,60 @@ namespace SixLabors.ImageSharp.Tests /// /// Tests the class. /// - public class ImageTests : FileTestBase + public class ImageTests { + public class Constructor + { + [Fact] + public void Width_Height() + { + using (var image = new Image(11, 23)) + { + Assert.Equal(11, image.Width); + Assert.Equal(23, image.Height); + Assert.Equal(11*23, image.GetPixelSpan().Length); + image.ComparePixelBufferTo(default(Rgba32)); + + Assert.Equal(Configuration.Default, image.GetConfiguration()); + } + } + + [Fact] + public void Configuration_Width_Height() + { + Configuration configuration = Configuration.Default.ShallowCopy(); + + using (var image = new Image(configuration, 11, 23)) + { + Assert.Equal(11, image.Width); + Assert.Equal(23, image.Height); + Assert.Equal(11 * 23, image.GetPixelSpan().Length); + image.ComparePixelBufferTo(default(Rgba32)); + + Assert.Equal(configuration, image.GetConfiguration()); + } + } + + [Fact] + public void Configuration_Width_Height_BackroundColor() + { + Configuration configuration = Configuration.Default.ShallowCopy(); + Rgba32 color = Rgba32.Aquamarine; + + using (var image = new Image(configuration, 11, 23, color)) + { + Assert.Equal(11, image.Width); + Assert.Equal(23, image.Height); + Assert.Equal(11 * 23, image.GetPixelSpan().Length); + image.ComparePixelBufferTo(color); + + Assert.Equal(configuration, image.GetConfiguration()); + } + } + } + [Fact] - public void ConstructorByteArray() + public void Load_ByteArray() { Assert.Throws(() => { @@ -32,7 +82,7 @@ public void ConstructorByteArray() } [Fact] - public void ConstructorFileSystem() + public void Load_FileSystemPath() { TestFile file = TestFile.Create(TestImages.Bmp.Car); using (Image image = Image.Load(file.FullPath)) @@ -43,7 +93,7 @@ public void ConstructorFileSystem() } [Fact] - public void ConstructorFileSystem_FileNotFound() + public void Load_FileSystemPath_FileNotFound() { System.IO.FileNotFoundException ex = Assert.Throws( () => @@ -53,7 +103,7 @@ public void ConstructorFileSystem_FileNotFound() } [Fact] - public void ConstructorFileSystem_NullPath() + public void Load_FileSystemPath_NullPath() { ArgumentNullException ex = Assert.Throws( () => diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index f37df48dce..8955eeb63c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -361,14 +361,25 @@ public static Image ComparePixelBufferTo( public static Image ComparePixelBufferTo(this Image image, TPixel expectedPixel) where TPixel : struct, IPixel { - Span actualPixels = image.GetPixelSpan(); + foreach (ImageFrame imageFrame in image.Frames) + { + imageFrame.ComparePixelBufferTo(expectedPixel); + } + + return image; + } + + public static ImageFrame ComparePixelBufferTo(this ImageFrame imageFrame, TPixel expectedPixel) + where TPixel : struct, IPixel + { + Span actualPixels = imageFrame.GetPixelSpan(); for (int i = 0; i < actualPixels.Length; i++) { Assert.True(expectedPixel.Equals(actualPixels[i]), $"Pixels are different on position {i}!"); } - return image; + return imageFrame; } public static ImageFrame ComparePixelBufferTo( From 72cb50c0c7e805d6e0c1d310578b4038c3ab203d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 2 May 2018 13:52:40 +1000 Subject: [PATCH 12/12] Delete merge conflict backup file. --- .../Drawing/Processors/FillProcessor.cs.orig | 121 ------------------ 1 file changed, 121 deletions(-) delete mode 100644 src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs.orig diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs.orig b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs.orig deleted file mode 100644 index 7da01b24f8..0000000000 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs.orig +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Drawing.Brushes; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Drawing.Processors -{ - /// - /// Using the brush as a source of pixels colors blends the brush color with source. - /// - /// The pixel format. - internal class FillProcessor : ImageProcessor - where TPixel : struct, IPixel - { - /// - /// The brush. - /// - private readonly IBrush brush; - private readonly GraphicsOptions options; - - /// - /// Initializes a new instance of the class. - /// - /// The brush to source pixel colors from. - /// The options - public FillProcessor(IBrush brush, GraphicsOptions options) - { - this.brush = brush; - this.options = options; - } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - - // Align start/end positions. - int minX = Math.Max(0, startX); - int maxX = Math.Min(source.Width, endX); - int minY = Math.Max(0, startY); - int maxY = Math.Min(source.Height, endY); - - int width = maxX - minX; - -<<<<<<< HEAD - var solidBrush = this.brush as SolidBrush; -======= - using (IBuffer amount = source.MemoryManager.Allocate(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator( - source, - sourceRectangle, - this.options)) - { - amount.Span.Fill(1f); ->>>>>>> master - - // If there's no reason for blending, then avoid it. - if (solidBrush != null && - ( - (this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || - (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f && solidBrush.Color.ToVector4().W == 1f) || - (this.options.BlenderMode == PixelBlenderMode.Src))) - { - Parallel.For( - minY, - maxY, - configuration.ParallelOptions, - y => - { - int offsetY = y - startY; - int offsetX = minX - startX; - source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); - }); - } - else - { - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } - - if (minY > 0) - { - startY = 0; - } - - using (IBuffer amount = source.MemoryManager.Allocate(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator( - source, - sourceRectangle, - this.options)) - { - amount.Span.Fill(this.options.BlendPercentage); - - Parallel.For( - minY, - maxY, - configuration.ParallelOptions, - y => - { - int offsetY = y - startY; - int offsetX = minX - startX; - - applicator.Apply(amount.Span, offsetX, offsetY); - }); - } - } - } - } -} \ No newline at end of file