diff --git a/ImageSharp.v3.ncrunchsolution b/ImageSharp.v3.ncrunchsolution new file mode 100644 index 000000000..10420ac91 --- /dev/null +++ b/ImageSharp.v3.ncrunchsolution @@ -0,0 +1,6 @@ + + + True + True + + \ 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 4cd3585ec..2d29e23fe 100644 --- a/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Brushes/ImageBrush{TPixel}.cs @@ -32,6 +32,15 @@ namespace SixLabors.ImageSharp.Drawing.Brushes this.image = image; } + /// + /// Initializes a new instance of the class. + /// + /// The image. + public ImageBrush(Image image) + : this(image.Frames.RootFrame) + { + } + /// public BrushApplicator CreateApplicator(ImageFrame source, RectangleF region, GraphicsOptions options) { diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs index 511e66c64..0acb846c5 100644 --- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs +++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs @@ -12,6 +12,16 @@ namespace SixLabors.ImageSharp.Advanced /// public static class AdvancedImageExtensions { + /// + /// Gets the configuration for the image. + /// + /// The Pixel format. + /// The source image + /// Returns the configuration. + public static Configuration GetConfiguration(this Image source) + where TPixel : struct, IPixel + => GetConfiguration((IConfigurable)source); + /// /// Returns a reference to the 0th element of the Pixel buffer, /// allowing direct manipulation of pixel data through unsafe operations. @@ -78,16 +88,6 @@ namespace SixLabors.ImageSharp.Advanced where TPixel : struct, IPixel => source.Frames.RootFrame.GetPixelRowSpan(row); - /// - /// Gets the configuration for the image. - /// - /// The Pixel format. - /// The source image - /// Returns the configuration. - internal static Configuration GetConfiguration(this Image source) - where TPixel : struct, IPixel - => GetConfiguration((IConfigurable)source); - /// /// Gets the span to the backing buffer. /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index c3c395e85..e4c7d93a0 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -388,15 +388,13 @@ namespace SixLabors.ImageSharp.Formats.Gif previousFrame = this.previousFrame; } - currentFrame = this.previousFrame.Clone(); + currentFrame = this.image.Frames.AddFrame(this.previousFrame); // this clones the frame and adds it the collection this.SetFrameMetaData(currentFrame.MetaData); image = currentFrame; this.RestoreToBackground(image); - - this.image.Frames.Add(currentFrame); } int i = 0; diff --git a/src/ImageSharp/Image/IImageFrameCollection.cs b/src/ImageSharp/Image/IImageFrameCollection.cs index ee325bc63..81b512e22 100644 --- a/src/ImageSharp/Image/IImageFrameCollection.cs +++ b/src/ImageSharp/Image/IImageFrameCollection.cs @@ -27,42 +27,82 @@ namespace SixLabors.ImageSharp ImageFrame RootFrame { get; } /// - /// Gets or sets the at the specified index. + /// Gets the at the specified index. /// /// /// The . /// /// The index. /// The at the specified index. - ImageFrame this[int index] { get; set; } + ImageFrame this[int index] { get; } /// - /// Determines the index of a specific in the . + /// Clones the the frame at and generates a new images with all the same metadata from the orgional but with only the single frame on it. /// - /// The to locate in the . - /// The index of item if found in the list; otherwise, -1. - int IndexOf(ImageFrame frame); + /// The zero-based index at which item should be removed. + /// Cannot remove last frame. + /// The new with only the one frame on it. + Image CloneFrame(int index); /// - /// Inserts the to the at the specified . + /// Removed the frame at and generates a new images with all the same metadata from the orgional but with only the single frame on it. /// - /// The zero-based index at which item should be inserted.. - /// The to insert into the . - void Insert(int index, ImageFrame frame); + /// The zero-based index at which item should be removed. + /// Cannot remove last frame. + /// The new with only the one frame on it. + Image ExportFrame(int index); /// - /// Removes the from the at the specified index. + /// Remove the frame at and frees all freeable resources associated with it. /// - /// The zero-based index of the item to remove. + /// The zero-based index at which item should be removed. /// Cannot remove last frame. - void RemoveAt(int index); + void RemoveFrame(int index); /// - /// Adds the specified frame. + /// Creates a new and appends it appends it to the end of the collection. /// - /// The frame. + /// The new . + ImageFrame CreateFrame(); + + /// + /// Clones the frame and appends the clone to the end of the collection. + /// + /// The raw pixel data to generate from. + /// The cloned . + ImageFrame AddFrame(ImageFrame source); + + /// + /// Creates a new frame from the pixel data at the same dimensions at the current image and inserts the new frame + /// into the at the end of the collection. + /// + /// The raw pixel data to generate from. + /// The new . + ImageFrame AddFrame(TPixel[] source); + + /// + /// Clones and inserts the into the at the specified . + /// + /// The zero-based index at which item should be inserted. + /// The to clone and insert into the . /// Frame must have the same dimensions as the image - frame - void Add(ImageFrame frame); + /// The cloned . + ImageFrame InsertFrame(int index, ImageFrame source); + + /// + /// Moves a from the at the specified index to the other index. + /// + /// The zero-based index of the item to move. + /// The zero-based index of the new index that should be inserted at. + /// Cannot remove last frame. + 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 . @@ -72,13 +112,5 @@ namespace SixLabors.ImageSharp /// true if the the specified frame; otherwise, false. /// bool Contains(ImageFrame frame); - - /// - /// Removes the specified frame. - /// - /// The frame. - /// true if item is found in the ; otherwise, - /// Cannot remove last frame - bool Remove(ImageFrame frame); } } \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs index aecd9bba9..e2230c436 100644 --- a/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs +++ b/src/ImageSharp/Image/ImageFrame.LoadPixelData.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp /// /// Adds static methods allowing the creation of new image from raw pixel data. /// - public static partial class ImageFrame + internal static partial class ImageFrame { /// /// Create a new instance of the class from the given byte array in format. diff --git a/src/ImageSharp/Image/ImageFrameCollection.cs b/src/ImageSharp/Image/ImageFrameCollection.cs index 25c0d0c44..b29fdc511 100644 --- a/src/ImageSharp/Image/ImageFrameCollection.cs +++ b/src/ImageSharp/Image/ImageFrameCollection.cs @@ -4,7 +4,7 @@ using System; using System.Collections; using System.Collections.Generic; - +using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp @@ -13,124 +13,134 @@ namespace SixLabors.ImageSharp /// Encapsulates an imaged collection of frames. /// /// The type of the pixel. - internal sealed class ImageFrameCollection : IImageFrameCollection, IDisposable + internal sealed class ImageFrameCollection : IImageFrameCollection where TPixel : struct, IPixel { private readonly IList> frames = new List>(); + private readonly Image parent; - internal ImageFrameCollection(int width, int height) + internal ImageFrameCollection(Image parent, int width, int height) { - this.Add(new ImageFrame(width, height)); + Guard.NotNull(parent, nameof(parent)); + + this.parent = parent; + this.AddFrame(new ImageFrame(width, height)); } - internal ImageFrameCollection(IEnumerable> frames) + internal ImageFrameCollection(Image parent, IEnumerable> frames) { + Guard.NotNull(parent, nameof(parent)); Guard.NotNullOrEmpty(frames, nameof(frames)); + + this.parent = parent; foreach (ImageFrame f in frames) { - this.Add(f); + this.AddFrame(f); } } - /// - /// Gets the count. - /// + /// public int Count => this.frames.Count; - /// - /// Gets the root frame. - /// + /// public ImageFrame RootFrame => this.frames.Count > 0 ? this.frames[0] : null; - /// - /// Gets or sets the at the specified index. - /// - /// - /// The . - /// - /// The index. - /// The at the specified index. + /// public ImageFrame this[int index] { get => this.frames[index]; - - set - { - this.ValidateFrame(value); - this.frames[index] = value; - } } - /// - /// Determines the index of a specific in the . - /// - /// The to locate in the . - /// The index of item if found in the list; otherwise, -1. + /// public int IndexOf(ImageFrame frame) => this.frames.IndexOf(frame); - /// - /// Inserts the to the at the specified . - /// - /// The zero-based index at which item should be inserted.. - /// The to insert into the . - public void Insert(int index, ImageFrame frame) + /// + public ImageFrame InsertFrame(int index, ImageFrame frame) { this.ValidateFrame(frame); - this.frames.Insert(index, frame); + ImageFrame clonedFrame = frame.Clone(); + this.frames.Insert(index, clonedFrame); + return clonedFrame; } - /// - /// Removes the from the at the specified index. - /// - /// The zero-based index of the item to remove. - /// Cannot remove last frame. - public void RemoveAt(int index) + /// + public ImageFrame AddFrame(ImageFrame frame) + { + this.ValidateFrame(frame); + ImageFrame clonedFrame = frame.Clone(); + this.frames.Add(clonedFrame); + return clonedFrame; + } + + /// + public ImageFrame AddFrame(TPixel[] data) + { + var frame = ImageFrame.LoadPixelData(new Span(data), this.RootFrame.Width, this.RootFrame.Height); + this.frames.Add(frame); + return frame; + } + + /// + public void RemoveFrame(int index) { if (index == 0 && this.Count == 1) { throw new InvalidOperationException("Cannot remove last frame."); } + ImageFrame frame = this.frames[index]; this.frames.RemoveAt(index); + frame.Dispose(); } - /// - /// Adds the specified frame. - /// - /// The frame. - /// Frame must have the same dimensions as the image - frame - public void Add(ImageFrame frame) + /// + public bool Contains(ImageFrame frame) { - this.ValidateFrame(frame); - this.frames.Add(frame); + return this.frames.Contains(frame); } - /// - /// Determines whether the contains the . - /// - /// The frame. - /// - /// true if the the specified frame; otherwise, false. - /// - public bool Contains(ImageFrame frame) + /// + public void MoveFrame(int sourceIndex, int destIndex) { - return this.frames.Contains(frame); + if (sourceIndex == destIndex) + { + return; + } + + ImageFrame frameAtIndex = this.frames[sourceIndex]; + this.frames.RemoveAt(sourceIndex); + this.frames.Insert(destIndex, frameAtIndex); } - /// - /// Removes the specified frame. - /// - /// The frame. - /// true if item is found in the ; otherwise, - /// Cannot remove last frame - public bool Remove(ImageFrame frame) + /// + public Image ExportFrame(int index) { + ImageFrame frame = this[index]; + if (this.Count == 1 && this.frames.Contains(frame)) { throw new InvalidOperationException("Cannot remove last frame."); } - return this.frames.Remove(frame); + this.frames.Remove(frame); + + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); + } + + /// + public Image CloneFrame(int index) + { + ImageFrame frame = this[index]; + ImageFrame clonedFrame = frame.Clone(); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); + } + + /// + public ImageFrame CreateFrame() + { + var frame = new ImageFrame(this.RootFrame.Width, this.RootFrame.Height); + this.frames.Add(frame); + return frame; } /// @@ -152,8 +162,7 @@ namespace SixLabors.ImageSharp } } - /// - public void Dispose() + internal void Dispose() { foreach (ImageFrame f in this.frames) { diff --git a/src/ImageSharp/Image/ImageFrame{TPixel}.cs b/src/ImageSharp/Image/ImageFrame{TPixel}.cs index 73e3a80ae..45ed5f053 100644 --- a/src/ImageSharp/Image/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/Image/ImageFrame{TPixel}.cs @@ -103,15 +103,6 @@ namespace SixLabors.ImageSharp } } - /// - /// Performs an explicit conversion from to . - /// - /// The image. - /// - /// The result of the conversion. - /// - public static implicit operator ImageFrame(Image image) => image.Frames[0]; - /// /// Gets a reference to the pixel at the specified position. /// @@ -172,7 +163,7 @@ namespace SixLabors.ImageSharp /// /// Disposes the object and frees resources for the Garbage Collector. /// - public void Dispose() + internal void Dispose() { if (this.isDisposed) { @@ -197,7 +188,7 @@ namespace SixLabors.ImageSharp /// /// The pixel format. /// The - public ImageFrame CloneAs() + internal ImageFrame CloneAs() where TPixel2 : struct, IPixel { if (typeof(TPixel2) == typeof(TPixel)) @@ -234,9 +225,15 @@ namespace SixLabors.ImageSharp /// Clones the current instance. /// /// The - public ImageFrame Clone() + internal ImageFrame Clone() { return new ImageFrame(this); } + + /// + void IDisposable.Dispose() + { + this.Dispose(); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/Image{TPixel}.cs b/src/ImageSharp/Image/Image{TPixel}.cs index e92255c20..85e1aa858 100644 --- a/src/ImageSharp/Image/Image{TPixel}.cs +++ b/src/ImageSharp/Image/Image{TPixel}.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp { this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(width, height); + this.frames = new ImageFrameCollection(this, width, height); } /// @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp this.configuration = configuration ?? Configuration.Default; this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(frames); + this.frames = new ImageFrameCollection(this, frames); } /// @@ -148,30 +148,6 @@ namespace SixLabors.ImageSharp return new Image(this.configuration, this.MetaData.Clone(), frames); } - /// - /// Clones the current image - /// - /// The index of the frame to clone into the new image - /// Returns a new image with all the same metadata as the original but only the single frame. - public Image Clone(int frameIndex) - { - ImageFrame frame = this.frames[frameIndex]; - ImageFrame clonedFrame = frame.Clone(); - return new Image(this.configuration, this.MetaData.Clone(), new[] { clonedFrame }); - } - - /// - /// Extracts a frame from the current image - /// - /// The index of the frame to cloen into the new image - /// Returns a new image with all the same metadata as the original but only the single frame. - public Image Extract(int frameIndex) - { - ImageFrame frame = this.frames[frameIndex]; - this.frames.Remove(frame); // try and remove frame from the current image - return new Image(this.configuration, this.MetaData.Clone(), new[] { frame }); - } - /// public override string ToString() { @@ -192,22 +168,6 @@ namespace SixLabors.ImageSharp return target; } - /// - /// Returns a copy of the image in the given pixel format. - /// - /// The pixel format. - /// The index of the frame to clone into the new image - /// Returns a new with all the same metadata as the original but only the single frame. - public Image CloneAs(int frameIndex) - where TPixel2 : struct, IPixel - { - ImageFrame frame = this.frames[frameIndex]; - ImageFrame clonedFrame = frame.CloneAs(); - var target = new Image(this.configuration, this.MetaData, new[] { clonedFrame }); - - return target; - } - /// /// Releases managed resources. /// diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 480d2d4d8..45d0a70b8 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.3;netstandard1.1 + netstandard1.1;netstandard1.3 true true SixLabors.ImageSharp diff --git a/src/ImageSharp/ImageSharp.netstandard1.1.v3.ncrunchproject b/src/ImageSharp/ImageSharp.netstandard1.1.v3.ncrunchproject new file mode 100644 index 000000000..319cd523c --- /dev/null +++ b/src/ImageSharp/ImageSharp.netstandard1.1.v3.ncrunchproject @@ -0,0 +1,5 @@ + + + True + + \ No newline at end of file diff --git a/src/ImageSharp/Processing/Transforms/Resize.cs b/src/ImageSharp/Processing/Transforms/Resize.cs index 826741d94..7897e8f30 100644 --- a/src/ImageSharp/Processing/Transforms/Resize.cs +++ b/src/ImageSharp/Processing/Transforms/Resize.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp options.Size = new Size(options.Size.Width, (int)MathF.Round(img.Height * options.Size.Width / (float)img.Width)); } - Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img, options); + Rectangle targetRectangle = ResizeHelper.CalculateTargetLocationAndBounds(img.Frames.RootFrame, options); img.Mutate(x => Resize(x, options.Size.Width, options.Size.Height, options.Sampler, targetRectangle, options.Compand)); }); diff --git a/src/ImageSharp/Quantizers/Quantize.cs b/src/ImageSharp/Quantizers/Quantize.cs index 049090f43..d99d4af34 100644 --- a/src/ImageSharp/Quantizers/Quantize.cs +++ b/src/ImageSharp/Quantizers/Quantize.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp return source.Apply(img => { // TODO : move helper logic into the processor - QuantizedImage quantized = quantizer.Quantize(img, maxColors); + QuantizedImage quantized = quantizer.Quantize(img.Frames.RootFrame, maxColors); int palleteCount = quantized.Palette.Length - 1; using (var pixels = new PixelAccessor(quantized.Width, quantized.Height)) diff --git a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs index e19d7ddef..afae9cae8 100644 --- a/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFramesCollectionTests.cs @@ -3,92 +3,94 @@ using System.Collections.Generic; using System.Linq; using System.Text; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.PixelFormats; using Xunit; namespace SixLabors.ImageSharp.Tests { - public class ImageFramesCollectionTests + public class ImageFramesCollectionTests : IDisposable { + private Image image; + private ImageFrameCollection collection; + + public ImageFramesCollectionTests() + { + this.image = new Image(10, 10); + this.collection = new ImageFrameCollection(this.image, 10, 10); + } + [Fact] public void ImageFramesaLwaysHaveOneFrame() { - var collection = new ImageFrameCollection(10, 10); - Assert.Equal(1, collection.Count); + Assert.Equal(1, this.collection.Count); } [Fact] public void AddNewFrame_FramesMustHaveSameSize() { - var collection = new ImageFrameCollection(10, 10); - ArgumentException ex = Assert.Throws(() => { - collection.Add(new ImageFrame(1, 1)); + this.collection.AddFrame(new ImageFrame(1, 1)); }); Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message); } [Fact] - public void AddNewFrame_FramesNotBeNull() + public void AddNewFrame_Frame_FramesNotBeNull() { - var collection = new ImageFrameCollection(10, 10); ArgumentNullException ex = Assert.Throws(() => { - collection.Add(null); + this.collection.AddFrame((ImageFrame)null); }); Assert.StartsWith("Value cannot be null.", ex.Message); } [Fact] - public void InsertNewFrame_FramesMustHaveSameSize() + public void AddNewFrame_PixelBuffer_FramesNotBeNull() { - var collection = new ImageFrameCollection(10, 10); - ArgumentException ex = Assert.Throws(() => + ArgumentNullException ex = Assert.Throws(() => { - collection.Insert(1, new ImageFrame(1, 1)); + this.collection.AddFrame((Rgba32[])null); }); - Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message); + Assert.StartsWith("Value cannot be null.", ex.Message); } [Fact] - public void InsertNewFrame_FramesNotBeNull() + public void AddNewFrame_PixelBuffer_BufferIncorrectSize() { - var collection = new ImageFrameCollection(10, 10); - ArgumentNullException ex = Assert.Throws(() => + ArgumentOutOfRangeException ex = Assert.Throws(() => { - collection.Insert(1, null); + this.collection.AddFrame(new Rgba32[0]); }); - Assert.StartsWith("Value cannot be null.", ex.Message); + Assert.StartsWith("Value must be greater than or equal to 100.", ex.Message); } [Fact] - public void SetFrameAtIndex_FramesMustHaveSameSize() + public void InsertNewFrame_FramesMustHaveSameSize() { - var collection = new ImageFrameCollection(10, 10); ArgumentException ex = Assert.Throws(() => { - collection[0] = new ImageFrame(1, 1); + this.collection.InsertFrame(1, new ImageFrame(1, 1)); }); Assert.StartsWith("Frame must have the same dimensions as the image.", ex.Message); } [Fact] - public void SetFrameAtIndex_FramesNotBeNull() + public void InsertNewFrame_FramesNotBeNull() { - var collection = new ImageFrameCollection(10, 10); ArgumentNullException ex = Assert.Throws(() => { - collection[0] = null; + this.collection.InsertFrame(1, null); }); Assert.StartsWith("Value cannot be null.", ex.Message); @@ -100,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests ArgumentException ex = Assert.Throws(() => { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(1,1), }); @@ -112,13 +114,13 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void RemoveAtFrame_ThrowIfRemovingLastFrame() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10) }); InvalidOperationException ex = Assert.Throws(() => { - collection.RemoveAt(0); + collection.RemoveFrame(0); }); Assert.Equal("Cannot remove last frame.", ex.Message); } @@ -127,46 +129,19 @@ namespace SixLabors.ImageSharp.Tests public void RemoveAtFrame_CanRemoveFrameZeroIfMultipleFramesExist() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(10,10), }); - collection.RemoveAt(0); - Assert.Equal(1, collection.Count); - } - - [Fact] - public void RemoveFrame_ThrowIfRemovingLastFrame() - { - var collection = new ImageFrameCollection(new[] { - new ImageFrame(10,10) - }); - - InvalidOperationException ex = Assert.Throws(() => - { - collection.Remove(collection[0]); - }); - Assert.Equal("Cannot remove last frame.", ex.Message); - } - - [Fact] - public void RemoveFrame_CanRemoveFrameZeroIfMultipleFramesExist() - { - - var collection = new ImageFrameCollection(new[] { - new ImageFrame(10,10), - new ImageFrame(10,10), - }); - - collection.Remove(collection[0]); + collection.RemoveFrame(0); Assert.Equal(1, collection.Count); } [Fact] public void RootFrameIsFrameAtIndexZero() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(10,10), }); @@ -177,7 +152,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorPopulatesFrames() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(10,10), }); @@ -188,7 +163,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void DisposeClearsCollection() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(10,10), }); @@ -201,7 +176,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Dispose_DisposesAllInnerFrames() { - var collection = new ImageFrameCollection(new[] { + var collection = new ImageFrameCollection(this.image, new[] { new ImageFrame(10,10), new ImageFrame(10,10), }); @@ -215,5 +190,132 @@ namespace SixLabors.ImageSharp.Tests Assert.Null(f.PixelBuffer); }); } + + [Theory] + [WithTestPatternImages(10, 10, PixelTypes.Rgba32)] + public void CloneFrame(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image img = provider.GetImage()) + { + img.Frames.AddFrame(new ImageFrame(10, 10));// add a frame anyway + using (Image cloned = img.Frames.CloneFrame(0)) + { + Assert.Equal(2, img.Frames.Count); + cloned.ComparePixelBufferTo(img.GetPixelSpan()); + } + } + } + + [Theory] + [WithTestPatternImages(10, 10, PixelTypes.Rgba32)] + public void ExtractFrame(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image img = provider.GetImage()) + { + var sourcePixelData = img.GetPixelSpan().ToArray(); + + img.Frames.AddFrame(new ImageFrame(10, 10)); + using (Image cloned = img.Frames.ExportFrame(0)) + { + Assert.Equal(1, img.Frames.Count); + cloned.ComparePixelBufferTo(sourcePixelData); + } + } + } + + [Fact] + public void CreateFrame() + { + this.image.Frames.CreateFrame(); + Assert.Equal(2, this.image.Frames.Count); + } + + [Fact] + public void AddFrameFromPixelData() + { + var pixelData = this.image.Frames.RootFrame.GetPixelSpan().ToArray(); + this.image.Frames.AddFrame(pixelData); + Assert.Equal(2, this.image.Frames.Count); + } + + [Fact] + public void AddFrame_clones_sourceFrame() + { + var pixelData = this.image.Frames.RootFrame.GetPixelSpan().ToArray(); + var otherFRame = new ImageFrame(10, 10); + var addedFrame = this.image.Frames.AddFrame(otherFRame); + addedFrame.ComparePixelBufferTo(otherFRame.GetPixelSpan()); + Assert.NotEqual(otherFRame, addedFrame); + } + + [Fact] + public void InsertFrame_clones_sourceFrame() + { + var pixelData = this.image.Frames.RootFrame.GetPixelSpan().ToArray(); + var otherFRame = new ImageFrame(10, 10); + var addedFrame = this.image.Frames.InsertFrame(0, otherFRame); + addedFrame.ComparePixelBufferTo(otherFRame.GetPixelSpan()); + Assert.NotEqual(otherFRame, addedFrame); + } + + [Fact] + public void MoveFrame_LeavesFrmaeInCorrectLocation() + { + for (var i = 0; i < 9; i++) + { + this.image.Frames.CreateFrame(); + } + + var frame = this.image.Frames[4]; + this.image.Frames.MoveFrame(4, 7); + var newIndex = this.image.Frames.IndexOf(frame); + Assert.Equal(7, newIndex); + } + + + [Fact] + public void IndexOf_ReturnsCorrectIndex() + { + for (var i = 0; i < 9; i++) + { + this.image.Frames.CreateFrame(); + } + + var frame = this.image.Frames[4]; + var index = this.image.Frames.IndexOf(frame); + Assert.Equal(4, index); + } + + [Fact] + public void Contains_TrueIfMember() + { + for (var i = 0; i < 9; i++) + { + this.image.Frames.CreateFrame(); + } + + var frame = this.image.Frames[4]; + Assert.True(this.image.Frames.Contains(frame)); + } + + [Fact] + public void Contains_TFalseIfNoneMember() + { + for (var i = 0; i < 9; i++) + { + this.image.Frames.CreateFrame(); + } + + var frame = new ImageFrame(10, 10); + Assert.False(this.image.Frames.Contains(frame)); + } + + public void Dispose() + { + this.image.Dispose(); + this.collection.Dispose(); + } } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index 00338e0bd..da813f428 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -110,64 +110,5 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal("image/png", mime.DefaultMimeType); } } - - [Theory] - [WithTestPatternImages(10, 10, PixelTypes.Rgba32)] - public void CloneFrame(TestImageProvider provider) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - img.Frames.Add(new ImageFrame(10, 10));// add a frame anyway - using (Image cloned = img.Clone(0)) - { - Assert.Equal(2, img.Frames.Count); - cloned.ComparePixelBufferTo(img.GetPixelSpan()); - } - } - } - - [Theory] - [WithTestPatternImages(10, 10, PixelTypes.Rgba32)] - public void CloneFrameAs(TestImageProvider provider) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - img.Frames.Add(new ImageFrame(10, 10));// add a frame anyway - using (Image cloned = img.CloneAs(0)) - { - for (var x = 0; x < img.Width; x++) - { - for (var y = 0; y < img.Height; y++) - { - Bgra32 pixelClone = cloned[x, y]; - Bgra32 pixelSource = default(Bgra32); - img[x, y].ToBgra32(ref pixelSource); - Assert.Equal(pixelSource, pixelClone); - } - } - Assert.Equal(2, img.Frames.Count); - } - } - } - - [Theory] - [WithTestPatternImages(10, 10, PixelTypes.Rgba32)] - public void ExtractFrame(TestImageProvider provider) - where TPixel : struct, IPixel - { - using (Image img = provider.GetImage()) - { - var sourcePixelData = img.GetPixelSpan().ToArray(); - - img.Frames.Add(new ImageFrame(10, 10)); - using (Image cloned = img.Extract(0)) - { - Assert.Equal(1, img.Frames.Count); - cloned.ComparePixelBufferTo(sourcePixelData); - } - } - } } } diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject b/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject new file mode 100644 index 000000000..f015b4b86 --- /dev/null +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.v3.ncrunchproject @@ -0,0 +1,9 @@ + + + False + UseStaticAnalysis + + False + False + + \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs index 829bf3d10..d23ab0202 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageComparison/ImageComparer.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison Image actual) where TPixelA : struct, IPixel where TPixelB : struct, IPixel { - return comparer.CompareImagesOrFrames((ImageFrame)expected, (ImageFrame)actual); + return comparer.CompareImagesOrFrames(expected.Frames.RootFrame, actual.Frames.RootFrame); } public static IEnumerable> CompareImages( diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 7fd7a59a9..7da0f0696 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests public static void ModifyPixel(Image img, int x, int y, byte perChannelChange) where TPixel : struct, IPixel { - ModifyPixel((ImageFrame)img, x, y, perChannelChange); + ModifyPixel(img.Frames.RootFrame, x, y, perChannelChange); } public static void ModifyPixel(ImageFrame img, int x, int y, byte perChannelChange) diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index b367ecbd9..505cdc172 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -166,12 +166,28 @@ namespace SixLabors.ImageSharp.Tests for (int i = 0; i < expectedPixels.Length; i++) { - Assert.True(expectedPixels[i].Equals(actual[i]), $"Pixels are different on position {i}!" ); + Assert.True(expectedPixels[i].Equals(actual[i]), $"Pixels are different on position {i}!"); } - + return image; } + public static ImageFrame ComparePixelBufferTo( + this ImageFrame image, + Span expectedPixels) + where TPixel : struct, IPixel + { + Span actual = image.GetPixelSpan(); + + Assert.True(expectedPixels.Length == actual.Length, "Buffer sizes are not equal!"); + + for (int i = 0; i < expectedPixels.Length; i++) + { + Assert.True(expectedPixels[i].Equals(actual[i]), $"Pixels are different on position {i}!"); + } + + return image; + } public static Image CompareToOriginal( this Image image,