diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 742189ec3a..378fed4a5f 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -9,7 +9,6 @@ using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Bmp; @@ -92,6 +91,11 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// private readonly IQuantizer quantizer; + /// + /// The pixel sampling strategy for quantization. + /// + private readonly IPixelSamplingStrategy pixelSamplingStrategy; + /// /// Initializes a new instance of the class. /// @@ -101,7 +105,8 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals { this.memoryAllocator = memoryAllocator; this.bitsPerPixel = encoder.BitsPerPixel; - this.quantizer = encoder.Quantizer ?? KnownQuantizers.Octree; + this.quantizer = encoder.Quantizer; + this.pixelSamplingStrategy = encoder.GlobalPixelSamplingStrategy; this.infoHeaderType = encoder.SupportTransparency ? BmpInfoHeaderType.WinVersion4 : BmpInfoHeaderType.WinVersion3; } @@ -159,7 +164,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals WriteBitmapFileHeader(stream, infoHeaderSize, colorPaletteSize, iccProfileSize, infoHeader, buffer); this.WriteBitmapInfoHeader(stream, infoHeader, buffer, infoHeaderSize); - this.WriteImage(stream, image.Frames.RootFrame); + this.WriteImage(stream, image); WriteColorProfile(stream, iccProfileData, buffer); stream.Flush(); @@ -311,10 +316,10 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// /// The containing pixel data. /// - private void WriteImage(Stream stream, ImageFrame image) + private void WriteImage(Stream stream, Image image) where TPixel : unmanaged, IPixel { - Buffer2D pixels = image.PixelBuffer; + Buffer2D pixels = image.Frames.RootFrame.PixelBuffer; switch (this.bitsPerPixel) { case BmpBitsPerPixel.Pixel32: @@ -433,8 +438,8 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// /// The type of the pixel. /// The to write to. - /// The containing pixel data. - private void Write8BitPixelData(Stream stream, ImageFrame image) + /// The containing pixel data. + private void Write8BitPixelData(Stream stream, Image image) where TPixel : unmanaged, IPixel { bool isL8 = typeof(TPixel) == typeof(L8); @@ -456,14 +461,15 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// /// The type of the pixel. /// The to write to. - /// The containing pixel data. + /// The containing pixel data. /// A byte span of size 1024 for the color palette. - private void Write8BitColor(Stream stream, ImageFrame image, Span colorPalette) + private void Write8BitColor(Stream stream, Image image, Span colorPalette) where TPixel : unmanaged, IPixel { - // TODO: Should we use the pixel sampling strategy here? using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration); - using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); + + frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); ReadOnlySpan quantizedColorPalette = quantized.Palette.Span; this.WriteColorPalette(stream, quantizedColorPalette, colorPalette); @@ -487,7 +493,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// The to write to. /// The containing pixel data. /// A byte span of size 1024 for the color palette. - private void Write8BitPixelData(Stream stream, ImageFrame image, Span colorPalette) + private void Write8BitPixelData(Stream stream, Image image, Span colorPalette) where TPixel : unmanaged, IPixel { // Create a color palette with 256 different gray values. @@ -504,7 +510,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals } stream.Write(colorPalette); - Buffer2D imageBuffer = image.PixelBuffer; + Buffer2D imageBuffer = image.GetRootFramePixelBuffer(); for (int y = image.Height - 1; y >= 0; y--) { ReadOnlySpan inputPixelRow = imageBuffer.DangerousGetRowSpan(y); @@ -524,14 +530,17 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// The type of the pixel. /// The to write to. /// The containing pixel data. - private void Write4BitPixelData(Stream stream, ImageFrame image) + private void Write4BitPixelData(Stream stream, Image image) where TPixel : unmanaged, IPixel { using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions() { MaxColors = 16 }); - using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); + + frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); + + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize4Bit, AllocationOptions.Clean); Span colorPalette = colorPaletteBuffer.GetSpan(); @@ -568,14 +577,17 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// The type of the pixel. /// The to write to. /// The containing pixel data. - private void Write2BitPixelData(Stream stream, ImageFrame image) + private void Write2BitPixelData(Stream stream, Image image) where TPixel : unmanaged, IPixel { using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions() { MaxColors = 4 }); - using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); + + frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); + + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize2Bit, AllocationOptions.Clean); Span colorPalette = colorPaletteBuffer.GetSpan(); @@ -621,14 +633,17 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals /// The type of the pixel. /// The to write to. /// The containing pixel data. - private void Write1BitPixelData(Stream stream, ImageFrame image) + private void Write1BitPixelData(Stream stream, Image image) where TPixel : unmanaged, IPixel { using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(this.configuration, new QuantizerOptions() { MaxColors = 2 }); - using IndexedImageFrame quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(image, image.Bounds()); + + frameQuantizer.BuildPalette(this.pixelSamplingStrategy, image); + + using IndexedImageFrame quantized = frameQuantizer.QuantizeFrame(image.Frames.RootFrame, image.Bounds()); using IMemoryOwner colorPaletteBuffer = this.memoryAllocator.Allocate(ColorPaletteSize1Bit, AllocationOptions.Clean); Span colorPalette = colorPaletteBuffer.GetSpan(); diff --git a/src/ImageSharp/ImageExtensions.Internal.cs b/src/ImageSharp/ImageExtensions.Internal.cs index 76c9b85224..6ec95a564a 100644 --- a/src/ImageSharp/ImageExtensions.Internal.cs +++ b/src/ImageSharp/ImageExtensions.Internal.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Memory; @@ -12,9 +12,9 @@ namespace SixLabors.ImageSharp; public static partial class ImageExtensions { /// - /// Locks the image providing access to the pixels. + /// Provides access to the image pixels. /// - /// It is imperative that the accessor is correctly disposed off after use. + /// It is imperative that the accessor is correctly disposed of after use. /// /// /// The type of the pixel. @@ -24,7 +24,5 @@ public static partial class ImageExtensions /// internal static Buffer2D GetRootFramePixelBuffer(this Image image) where TPixel : unmanaged, IPixel - { - return image.Frames.RootFrame.PixelBuffer; - } + => image.Frames.RootFrame.PixelBuffer; } diff --git a/src/ImageSharp/ImageFrameCollection{TPixel}.cs b/src/ImageSharp/ImageFrameCollection{TPixel}.cs index d366ff7a76..faa83b59e2 100644 --- a/src/ImageSharp/ImageFrameCollection{TPixel}.cs +++ b/src/ImageSharp/ImageFrameCollection{TPixel}.cs @@ -374,10 +374,15 @@ public sealed class ImageFrameCollection : ImageFrameCollection, IEnumer } /// - public IEnumerator> GetEnumerator() => this.frames.GetEnumerator(); + public IEnumerator> GetEnumerator() + { + this.EnsureNotDisposed(); + + return this.frames.GetEnumerator(); + } /// - IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.frames).GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); private void ValidateFrame(ImageFrame frame) { diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 28c4f686b0..5e435ee9bb 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -14,9 +14,7 @@ public abstract partial class ImageFrameCollectionTests { [Fact] public void Constructor_ShouldCreateOneFrame() - { - Assert.Equal(1, this.Collection.Count); - } + => Assert.Equal(1, this.Collection.Count); [Fact] public void AddNewFrame_FramesMustHaveSameSize() @@ -24,7 +22,7 @@ public abstract partial class ImageFrameCollectionTests ArgumentException ex = Assert.Throws( () => { - using var frame = new ImageFrame(Configuration.Default, 1, 1); + using ImageFrame frame = new(Configuration.Default, 1, 1); using ImageFrame addedFrame = this.Collection.AddFrame(frame); }); @@ -75,7 +73,7 @@ public abstract partial class ImageFrameCollectionTests ArgumentException ex = Assert.Throws( () => { - using var frame = new ImageFrame(Configuration.Default, 1, 1); + using ImageFrame frame = new(Configuration.Default, 1, 1); using ImageFrame insertedFrame = this.Collection.InsertFrame(1, frame); }); @@ -100,8 +98,8 @@ public abstract partial class ImageFrameCollectionTests ArgumentException ex = Assert.Throws( () => { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 1, 1); + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 1, 1); new ImageFrameCollection( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -113,8 +111,8 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void RemoveAtFrame_ThrowIfRemovingLastFrame() { - using var imageFrame = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame }); @@ -126,9 +124,9 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void RemoveAtFrame_CanRemoveFrameZeroIfMultipleFramesExist() { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -139,9 +137,9 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void RootFrameIsFrameAtIndexZero() { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -151,9 +149,9 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void ConstructorPopulatesFrames() { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -163,9 +161,9 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void DisposeClearsCollection() { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -177,9 +175,9 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void Dispose_DisposesAllInnerFrames() { - using var imageFrame1 = new ImageFrame(Configuration.Default, 10, 10); - using var imageFrame2 = new ImageFrame(Configuration.Default, 10, 10); - var collection = new ImageFrameCollection( + using ImageFrame imageFrame1 = new(Configuration.Default, 10, 10); + using ImageFrame imageFrame2 = new(Configuration.Default, 10, 10); + ImageFrameCollection collection = new( this.Image, new[] { imageFrame1, imageFrame2 }); @@ -188,11 +186,8 @@ public abstract partial class ImageFrameCollectionTests Assert.All( framesSnapShot, - f => - { - // The pixel source of the frame is null after its been disposed. - Assert.Null(f.PixelBuffer); - }); + f => // The pixel source of the frame is null after its been disposed. + Assert.Null(f.PixelBuffer)); } [Theory] @@ -200,18 +195,14 @@ public abstract partial class ImageFrameCollectionTests public void CloneFrame(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image img = provider.GetImage()) - { - using var imageFrame = new ImageFrame(Configuration.Default, 10, 10); - using ImageFrame addedFrame = img.Frames.AddFrame(imageFrame); // add a frame anyway - using (Image cloned = img.Frames.CloneFrame(0)) - { - Assert.Equal(2, img.Frames.Count); - Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); - - cloned.ComparePixelBufferTo(imgMem); - } - } + using Image img = provider.GetImage(); + using ImageFrame imageFrame = new(Configuration.Default, 10, 10); + using ImageFrame addedFrame = img.Frames.AddFrame(imageFrame); // add a frame anyway + using Image cloned = img.Frames.CloneFrame(0); + Assert.Equal(2, img.Frames.Count); + Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); + + cloned.ComparePixelBufferTo(imgMem); } [Theory] @@ -219,19 +210,15 @@ public abstract partial class ImageFrameCollectionTests public void ExtractFrame(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image img = provider.GetImage()) - { - Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMemory)); - TPixel[] sourcePixelData = imgMemory.ToArray(); - - using var imageFrame = new ImageFrame(Configuration.Default, 10, 10); - using ImageFrame addedFrame = img.Frames.AddFrame(imageFrame); - using (Image cloned = img.Frames.ExportFrame(0)) - { - Assert.Equal(1, img.Frames.Count); - cloned.ComparePixelBufferTo(sourcePixelData.AsSpan()); - } - } + using Image img = provider.GetImage(); + Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMemory)); + TPixel[] sourcePixelData = imgMemory.ToArray(); + + using ImageFrame imageFrame = new(Configuration.Default, 10, 10); + using ImageFrame addedFrame = img.Frames.AddFrame(imageFrame); + using Image cloned = img.Frames.ExportFrame(0); + Assert.Equal(1, img.Frames.Count); + cloned.ComparePixelBufferTo(sourcePixelData.AsSpan()); } [Fact] @@ -266,7 +253,7 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void AddFrame_clones_sourceFrame() { - using var otherFrame = new ImageFrame(Configuration.Default, 10, 10); + using ImageFrame otherFrame = new(Configuration.Default, 10, 10); using ImageFrame addedFrame = this.Image.Frames.AddFrame(otherFrame); Assert.True(otherFrame.DangerousTryGetSinglePixelMemory(out Memory otherFrameMem)); @@ -277,7 +264,7 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void InsertFrame_clones_sourceFrame() { - using var otherFrame = new ImageFrame(Configuration.Default, 10, 10); + using ImageFrame otherFrame = new(Configuration.Default, 10, 10); using ImageFrame addedFrame = this.Image.Frames.InsertFrame(0, otherFrame); Assert.True(otherFrame.DangerousTryGetSinglePixelMemory(out Memory otherFrameMem)); @@ -332,7 +319,7 @@ public abstract partial class ImageFrameCollectionTests this.Image.Frames.CreateFrame(); } - using var frame = new ImageFrame(Configuration.Default, 10, 10); + using ImageFrame frame = new(Configuration.Default, 10, 10); Assert.False(this.Image.Frames.Contains(frame)); } @@ -343,14 +330,13 @@ public abstract partial class ImageFrameCollectionTests configuration.MemoryAllocator = new TestMemoryAllocator { BufferCapacityInBytes = 1000 }; configuration.PreferContiguousImageBuffers = true; - using var image = new Image(configuration, 100, 100); + using Image image = new(configuration, 100, 100); image.Frames.CreateFrame(); image.Frames.InsertFrame(0, image.Frames[0]); image.Frames.CreateFrame(Color.Red); Assert.Equal(4, image.Frames.Count); - IEnumerable> frames = image.Frames; - foreach (ImageFrame frame in frames) + foreach (ImageFrame frame in image.Frames) { Assert.True(frame.DangerousTryGetSinglePixelMemory(out Memory _)); } @@ -359,8 +345,8 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void DisposeCall_NoThrowIfCalledMultiple() { - var image = new Image(Configuration.Default, 10, 10); - var frameCollection = image.Frames as ImageFrameCollection; + Image image = new(Configuration.Default, 10, 10); + ImageFrameCollection frameCollection = image.Frames; image.Dispose(); // this should invalidate underlying collection as well frameCollection.Dispose(); @@ -369,33 +355,33 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void PublicProperties_ThrowIfDisposed() { - var image = new Image(Configuration.Default, 10, 10); - var frameCollection = image.Frames as ImageFrameCollection; + Image image = new(Configuration.Default, 10, 10); + ImageFrameCollection frameCollection = image.Frames; image.Dispose(); // this should invalidate underlying collection as well - Assert.Throws(() => { var prop = frameCollection.RootFrame; }); + Assert.Throws(() => { ImageFrame prop = frameCollection.RootFrame; }); } [Fact] public void PublicMethods_ThrowIfDisposed() { - var image = new Image(Configuration.Default, 10, 10); - var frameCollection = image.Frames as ImageFrameCollection; + Image image = new(Configuration.Default, 10, 10); + ImageFrameCollection frameCollection = image.Frames; image.Dispose(); // this should invalidate underlying collection as well - Assert.Throws(() => { var res = frameCollection.AddFrame(default); }); - Assert.Throws(() => { var res = frameCollection.CloneFrame(default); }); - Assert.Throws(() => { var res = frameCollection.Contains(default); }); - Assert.Throws(() => { var res = frameCollection.CreateFrame(); }); - Assert.Throws(() => { var res = frameCollection.CreateFrame(default); }); - Assert.Throws(() => { var res = frameCollection.ExportFrame(default); }); - Assert.Throws(() => { var res = frameCollection.GetEnumerator(); }); - Assert.Throws(() => { var prop = frameCollection.IndexOf(default); }); - Assert.Throws(() => { var prop = frameCollection.InsertFrame(default, default); }); - Assert.Throws(() => { frameCollection.RemoveFrame(default); }); - Assert.Throws(() => { frameCollection.MoveFrame(default, default); }); + Assert.Throws(() => { ImageFrame res = frameCollection.AddFrame(default(ImageFrame)); }); + Assert.Throws(() => { Image res = frameCollection.CloneFrame(default); }); + Assert.Throws(() => { bool res = frameCollection.Contains(default); }); + Assert.Throws(() => { ImageFrame res = frameCollection.CreateFrame(); }); + Assert.Throws(() => { ImageFrame res = frameCollection.CreateFrame(default); }); + Assert.Throws(() => { Image res = frameCollection.ExportFrame(default); }); + Assert.Throws(() => { IEnumerator> res = frameCollection.GetEnumerator(); }); + Assert.Throws(() => { int prop = frameCollection.IndexOf(default); }); + Assert.Throws(() => { ImageFrame prop = frameCollection.InsertFrame(default, default); }); + Assert.Throws(() => frameCollection.RemoveFrame(default)); + Assert.Throws(() => frameCollection.MoveFrame(default, default)); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index 6e394d5925..60290a7eda 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -19,7 +19,7 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void AddFrame_OfDifferentPixelType() { - using (var sourceImage = new Image( + using (Image sourceImage = new( this.Image.GetConfiguration(), this.Image.Width, this.Image.Height, @@ -32,7 +32,7 @@ public abstract partial class ImageFrameCollectionTests Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); - var actualFrame = (ImageFrame)this.Collection[1]; + ImageFrame actualFrame = (ImageFrame)this.Collection[1]; actualFrame.ComparePixelBufferTo(expectedAllBlue); } @@ -40,7 +40,7 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void InsertFrame_OfDifferentPixelType() { - using (var sourceImage = new Image( + using (Image sourceImage = new( this.Image.GetConfiguration(), this.Image.Width, this.Image.Height, @@ -53,25 +53,20 @@ public abstract partial class ImageFrameCollectionTests Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); - var actualFrame = (ImageFrame)this.Collection[0]; + ImageFrame actualFrame = (ImageFrame)this.Collection[0]; actualFrame.ComparePixelBufferTo(expectedAllBlue); } [Fact] public void Constructor_ShouldCreateOneFrame() - { - Assert.Equal(1, this.Collection.Count); - } + => Assert.Equal(1, this.Collection.Count); [Fact] public void AddNewFrame_FramesMustHaveSameSize() { ArgumentException ex = Assert.Throws( - () => - { - this.Collection.AddFrame(new ImageFrame(Configuration.Default, 1, 1)); - }); + () => this.Collection.AddFrame(new ImageFrame(Configuration.Default, 1, 1))); Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message); } @@ -80,10 +75,7 @@ public abstract partial class ImageFrameCollectionTests public void AddNewFrame_Frame_FramesNotBeNull() { ArgumentNullException ex = Assert.Throws( - () => - { - this.Collection.AddFrame(null); - }); + () => this.Collection.AddFrame(null)); Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message); } @@ -92,10 +84,7 @@ public abstract partial class ImageFrameCollectionTests public void InsertNewFrame_FramesMustHaveSameSize() { ArgumentException ex = Assert.Throws( - () => - { - this.Collection.InsertFrame(1, new ImageFrame(Configuration.Default, 1, 1)); - }); + () => this.Collection.InsertFrame(1, new ImageFrame(Configuration.Default, 1, 1))); Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message); } @@ -104,10 +93,7 @@ public abstract partial class ImageFrameCollectionTests public void InsertNewFrame_FramesNotBeNull() { ArgumentNullException ex = Assert.Throws( - () => - { - this.Collection.InsertFrame(1, null); - }); + () => this.Collection.InsertFrame(1, null)); Assert.StartsWith("Parameter \"source\" must be not null.", ex.Message); } @@ -116,10 +102,7 @@ public abstract partial class ImageFrameCollectionTests public void RemoveAtFrame_ThrowIfRemovingLastFrame() { InvalidOperationException ex = Assert.Throws( - () => - { - this.Collection.RemoveFrame(0); - }); + () => this.Collection.RemoveFrame(0)); Assert.Equal("Cannot remove last frame.", ex.Message); } @@ -134,30 +117,24 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void RootFrameIsFrameAtIndexZero() - { - Assert.Equal(this.Collection.RootFrame, this.Collection[0]); - } + => Assert.Equal(this.Collection.RootFrame, this.Collection[0]); [Theory] [WithTestPatternImages(10, 10, PixelTypes.Rgba32 | PixelTypes.Bgr24)] public void CloneFrame(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image img = provider.GetImage()) - { - ImageFrameCollection nonGenericFrameCollection = img.Frames; + using Image img = provider.GetImage(); + ImageFrameCollection nonGenericFrameCollection = img.Frames; - nonGenericFrameCollection.AddFrame(new ImageFrame(Configuration.Default, 10, 10)); // add a frame anyway - using (Image cloned = nonGenericFrameCollection.CloneFrame(0)) - { - Assert.Equal(2, img.Frames.Count); + nonGenericFrameCollection.AddFrame(new ImageFrame(Configuration.Default, 10, 10)); // add a frame anyway + using Image cloned = nonGenericFrameCollection.CloneFrame(0); + Assert.Equal(2, img.Frames.Count); - var expectedClone = (Image)cloned; + Image expectedClone = (Image)cloned; - Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); - expectedClone.ComparePixelBufferTo(imgMem); - } - } + Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); + expectedClone.ComparePixelBufferTo(imgMem); } [Theory] @@ -165,22 +142,18 @@ public abstract partial class ImageFrameCollectionTests public void ExtractFrame(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image img = provider.GetImage()) - { - Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); - TPixel[] sourcePixelData = imgMem.ToArray(); + using Image img = provider.GetImage(); + Assert.True(img.DangerousTryGetSinglePixelMemory(out Memory imgMem)); + TPixel[] sourcePixelData = imgMem.ToArray(); - ImageFrameCollection nonGenericFrameCollection = img.Frames; + ImageFrameCollection nonGenericFrameCollection = img.Frames; - nonGenericFrameCollection.AddFrame(new ImageFrame(Configuration.Default, 10, 10)); - using (Image cloned = nonGenericFrameCollection.ExportFrame(0)) - { - Assert.Equal(1, img.Frames.Count); + nonGenericFrameCollection.AddFrame(new ImageFrame(Configuration.Default, 10, 10)); + using Image cloned = nonGenericFrameCollection.ExportFrame(0); + Assert.Equal(1, img.Frames.Count); - var expectedClone = (Image)cloned; - expectedClone.ComparePixelBufferTo(sourcePixelData.AsSpan()); - } - } + Image expectedClone = (Image)cloned; + expectedClone.ComparePixelBufferTo(sourcePixelData.AsSpan()); } [Fact] @@ -190,7 +163,7 @@ public abstract partial class ImageFrameCollectionTests Assert.Equal(2, this.Image.Frames.Count); - var frame = (ImageFrame)this.Image.Frames[1]; + ImageFrame frame = (ImageFrame)this.Image.Frames[1]; frame.ComparePixelBufferTo(default(Rgba32)); } @@ -202,7 +175,7 @@ public abstract partial class ImageFrameCollectionTests Assert.Equal(2, this.Image.Frames.Count); - var frame = (ImageFrame)this.Image.Frames[1]; + ImageFrame frame = (ImageFrame)this.Image.Frames[1]; frame.ComparePixelBufferTo(Color.HotPink); } @@ -210,132 +183,127 @@ public abstract partial class ImageFrameCollectionTests [Fact] public void MoveFrame_LeavesFrameInCorrectLocation() { - for (var i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { this.Image.Frames.CreateFrame(); } - var frame = this.Image.Frames[4]; + ImageFrame frame = this.Image.Frames[4]; this.Image.Frames.MoveFrame(4, 7); - var newIndex = this.Image.Frames.IndexOf(frame); + int newIndex = this.Image.Frames.IndexOf(frame); Assert.Equal(7, newIndex); } [Fact] public void IndexOf_ReturnsCorrectIndex() { - for (var i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { this.Image.Frames.CreateFrame(); } - var frame = this.Image.Frames[4]; - var index = this.Image.Frames.IndexOf(frame); + ImageFrame frame = this.Image.Frames[4]; + int index = this.Image.Frames.IndexOf(frame); Assert.Equal(4, index); } [Fact] public void Contains_TrueIfMember() { - for (var i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { this.Image.Frames.CreateFrame(); } - var frame = this.Image.Frames[4]; + ImageFrame frame = this.Image.Frames[4]; Assert.True(this.Image.Frames.Contains(frame)); } [Fact] public void Contains_FalseIfNonMember() { - for (var i = 0; i < 9; i++) + for (int i = 0; i < 9; i++) { this.Image.Frames.CreateFrame(); } - var frame = new ImageFrame(Configuration.Default, 10, 10); + ImageFrame frame = new(Configuration.Default, 10, 10); Assert.False(this.Image.Frames.Contains(frame)); } [Fact] public void PublicProperties_ThrowIfDisposed() { - var image = new Image(Configuration.Default, 10, 10); - var frameCollection = image.Frames; + Image image = new(Configuration.Default, 10, 10); + ImageFrameCollection frameCollection = image.Frames; image.Dispose(); // this should invalidate underlying collection as well - Assert.Throws(() => { var prop = frameCollection.RootFrame; }); + Assert.Throws(() => { ImageFrame prop = frameCollection.RootFrame; }); } [Fact] public void PublicMethods_ThrowIfDisposed() { - var image = new Image(Configuration.Default, 10, 10); - var frameCollection = image.Frames; - var rgba32Array = new Rgba32[0]; + Image image = new(Configuration.Default, 10, 10); + ImageFrameCollection frameCollection = image.Frames; + Rgba32[] rgba32Array = Array.Empty(); image.Dispose(); // this should invalidate underlying collection as well - Assert.Throws(() => { var res = frameCollection.AddFrame((ImageFrame)null); }); - Assert.Throws(() => { var res = frameCollection.AddFrame(rgba32Array); }); - Assert.Throws(() => { var res = frameCollection.AddFrame((ImageFrame)null); }); - Assert.Throws(() => { var res = frameCollection.AddFrame(rgba32Array.AsSpan()); }); - Assert.Throws(() => { var res = frameCollection.CloneFrame(default); }); - Assert.Throws(() => { var res = frameCollection.Contains(default); }); - Assert.Throws(() => { var res = frameCollection.CreateFrame(); }); - Assert.Throws(() => { var res = frameCollection.CreateFrame(default); }); - Assert.Throws(() => { var res = frameCollection.ExportFrame(default); }); - Assert.Throws(() => { var res = frameCollection.GetEnumerator(); }); - Assert.Throws(() => { var prop = frameCollection.IndexOf(default); }); - Assert.Throws(() => { var prop = frameCollection.InsertFrame(default, default); }); - Assert.Throws(() => { frameCollection.RemoveFrame(default); }); - Assert.Throws(() => { frameCollection.MoveFrame(default, default); }); + Assert.Throws(() => { ImageFrame res = frameCollection.AddFrame((ImageFrame)null); }); + Assert.Throws(() => { ImageFrame res = frameCollection.AddFrame(rgba32Array); }); + Assert.Throws(() => { ImageFrame res = frameCollection.AddFrame((ImageFrame)null); }); + Assert.Throws(() => { ImageFrame res = frameCollection.AddFrame(rgba32Array.AsSpan()); }); + Assert.Throws(() => { Image res = frameCollection.CloneFrame(default); }); + Assert.Throws(() => { bool res = frameCollection.Contains(default); }); + Assert.Throws(() => { ImageFrame res = frameCollection.CreateFrame(); }); + Assert.Throws(() => { ImageFrame res = frameCollection.CreateFrame(default); }); + Assert.Throws(() => { Image res = frameCollection.ExportFrame(default); }); + Assert.Throws(() => { IEnumerator> res = frameCollection.GetEnumerator(); }); + Assert.Throws(() => { int prop = frameCollection.IndexOf(default); }); + Assert.Throws(() => { ImageFrame prop = frameCollection.InsertFrame(default, default); }); + Assert.Throws(() => frameCollection.RemoveFrame(default)); + Assert.Throws(() => frameCollection.MoveFrame(default, default)); } /// /// Integration test for end-to end API validation. /// /// The pixel type of the image. + /// The test image provider [Theory] [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] public void ConstructGif_FromDifferentPixelTypes(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image source = provider.GetImage()) - using (var dest = new Image(source.GetConfiguration(), source.Width, source.Height)) + using Image source = provider.GetImage(); + using Image dest = new(source.GetConfiguration(), source.Width, source.Height); + // Giphy.gif has 5 frames + ImportFrameAs(source.Frames, dest.Frames, 0); + ImportFrameAs(source.Frames, dest.Frames, 1); + ImportFrameAs(source.Frames, dest.Frames, 2); + ImportFrameAs(source.Frames, dest.Frames, 3); + ImportFrameAs(source.Frames, dest.Frames, 4); + + // Drop the original empty root frame: + dest.Frames.RemoveFrame(0); + + dest.DebugSave(provider, appendSourceFileOrDescription: false, extension: "gif"); + dest.CompareToOriginal(provider); + + for (int i = 0; i < 5; i++) { - // Giphy.gif has 5 frames - ImportFrameAs(source.Frames, dest.Frames, 0); - ImportFrameAs(source.Frames, dest.Frames, 1); - ImportFrameAs(source.Frames, dest.Frames, 2); - ImportFrameAs(source.Frames, dest.Frames, 3); - ImportFrameAs(source.Frames, dest.Frames, 4); - - // Drop the original empty root frame: - dest.Frames.RemoveFrame(0); - - dest.DebugSave(provider, appendSourceFileOrDescription: false, extension: "gif"); - dest.CompareToOriginal(provider); - - for (int i = 0; i < 5; i++) - { - CompareGifMetadata(source.Frames[i], dest.Frames[i]); - } + CompareGifMetadata(source.Frames[i], dest.Frames[i]); } } private static void ImportFrameAs(ImageFrameCollection source, ImageFrameCollection destination, int index) where TPixel : unmanaged, IPixel { - using (Image temp = source.CloneFrame(index)) - { - using (Image temp2 = temp.CloneAs()) - { - destination.AddFrame(temp2.Frames.RootFrame); - } - } + using Image temp = source.CloneFrame(index); + using Image temp2 = temp.CloneAs(); + destination.AddFrame(temp2.Frames.RootFrame); } private static void CompareGifMetadata(ImageFrame a, ImageFrame b)