From aac48f7b59a01c628a59d5e3f2d881c2db000c7e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 1 Sep 2018 11:39:11 +0100 Subject: [PATCH 01/13] Add usings for clarity. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index a420c07c8e..66dc0dcf43 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,9 @@ Our API is designed to be simple to consume. Here's an example of the code requi On platforms supporting netstandard 1.3+ ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; + // Image.Load(string path) is a shortcut for our default type. // Other pixel formats use Image.Load(string path)) using (Image image = Image.Load("foo.jpg")) @@ -83,6 +86,9 @@ using (Image image = Image.Load("foo.jpg")) On netstandard 1.1 - 1.2 ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; + // Image.Load(Stream stream) is a shortcut for our default type. // Other pixel formats use Image.Load(Stream stream)) using (FileStream stream = File.OpenRead("foo.jpg")) @@ -99,6 +105,9 @@ using (Image image = Image.Load(stream)) Setting individual pixel values can be performed as follows: ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + // Individual pixels using (Image image = new Image(400, 400)) { From 385b3fe68876a927670b88e468cb455cb45baf1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 17 Sep 2018 23:02:02 +0100 Subject: [PATCH 02/13] Fix png quantization and reduce Wu memory pressure --- .../Common/Extensions/ComparableExtensions.cs | 11 -- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 19 ++-- .../Quantization/WuFrameQuantizer{TPixel}.cs | 101 +++++++++--------- 4 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs index d6dade7703..1b0f8ad095 100644 --- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs @@ -137,17 +137,6 @@ namespace SixLabors.ImageSharp return value; } - /// - /// Converts an to a first restricting the value between the - /// minimum and maximum allowable ranges. - /// - /// The this method extends. - /// The - public static byte ToByte(this int value) - { - return (byte)value.Clamp(0, 255); - } - /// /// Converts an to a first restricting the value between the /// minimum and maximum allowable ranges. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7837c2da5c..9281927012 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { var metaData = new ImageMetaData(); - var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); + PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); Image image = null; @@ -307,7 +307,7 @@ namespace SixLabors.ImageSharp.Formats.Png public IImageInfo Identify(Stream stream) { var metaData = new ImageMetaData(); - var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); + PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); try diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 0b47c1c63e..e4d2fc510d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Collect the indexed pixel data if (quantized != null) { - this.WritePaletteChunk(stream, header, quantized); + this.WritePaletteChunk(stream, quantized); } this.WritePhysicalChunk(stream, metaData); @@ -555,30 +555,27 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The pixel format. /// The containing image data. - /// The . /// The quantized frame. - private void WritePaletteChunk(Stream stream, in PngHeader header, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, QuantizedFrame quantized) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; - byte pixelCount = palette.Length.ToByte(); - - // Get max colors for bit depth. - int colorTableLength = ImageMaths.GetColorCountForBitDepth(header.BitDepth) * 3; + int paletteLength = Math.Min(palette.Length, 256); + int colorTableLength = paletteLength * 3; Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) - using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(pixelCount)) + using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength)) { Span colorTableSpan = colorTable.GetSpan(); Span alphaTableSpan = alphaTable.GetSpan(); Span quantizedSpan = quantized.GetPixelSpan(); - for (byte i = 0; i < pixelCount; i++) + for (int i = 0; i < paletteLength; i++) { - if (quantizedSpan.IndexOf(i) > -1) + if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; palette[i].ToRgba32(ref rgba); @@ -604,7 +601,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Write the transparency data if (anyAlpha) { - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, pixelCount); + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index d71221b9d6..5cd3d53ea2 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -46,12 +46,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The index bits. /// - private const int IndexBits = 6; + private const int IndexBits = 5; /// /// The index alpha bits. /// - private const int IndexAlphaBits = 3; + private const int IndexAlphaBits = 5; /// /// The index count. @@ -201,57 +201,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.palette; } - /// - /// Quantizes the pixel - /// - /// The rgba used to quantize the pixel input - private void QuantizePixel(ref Rgba32 rgba) - { - // Add the color to a 3-D color histogram. - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); - - int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); - - Span vwtSpan = this.vwt.GetSpan(); - Span vmrSpan = this.vmr.GetSpan(); - Span vmgSpan = this.vmg.GetSpan(); - Span vmbSpan = this.vmb.GetSpan(); - Span vmaSpan = this.vma.GetSpan(); - Span m2Span = this.m2.GetSpan(); - - vwtSpan[index]++; - vmrSpan[index] += rgba.R; - vmgSpan[index] += rgba.G; - vmbSpan[index] += rgba.B; - vmaSpan[index] += rgba.A; - - var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); - m2Span[index] += Vector4.Dot(vector, vector); - } - /// protected override void FirstPass(ImageFrame source, int width, int height) { - // Build up the 3-D color histogram - // Loop through each row - for (int y = 0; y < height; y++) - { - Span row = source.GetPixelRowSpan(y); - ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); - - // And loop through each column - Rgba32 rgba = default; - for (int x = 0; x < width; x++) - { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); - this.QuantizePixel(ref rgba); - } - } - + this.Build3DHistogram(source, width, height); this.Get3DMoments(source.MemoryAllocator); this.BuildCube(); } @@ -466,6 +419,54 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + /// + /// Builds a 3-D color histogram of counts, r/g/b, c^2. + /// + /// The source data. + /// The width in pixels of the image. + /// The height in pixels of the image. + private void Build3DHistogram(ImageFrame source, int width, int height) + { + // Build up the 3-D color histogram + // Loop through each row + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + Span m2Span = this.m2.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span row = source.GetPixelRowSpan(y); + ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); + + // And loop through each column + Rgba32 rgba = default; + for (int x = 0; x < width; x++) + { + ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); + pixel.ToRgba32(ref rgba); + + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); + + int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); + + vwtSpan[index]++; + vmrSpan[index] += rgba.R; + vmgSpan[index] += rgba.G; + vmbSpan[index] += rgba.B; + vmaSpan[index] += rgba.A; + + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } + } + } + /// /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box. /// From 6a73c5c1dffe536f03be39f1222b8ec921bcced7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 17 Sep 2018 23:26:59 +0100 Subject: [PATCH 03/13] Minor optimizations to Wu --- .../Quantization/WuFrameQuantizer{TPixel}.cs | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 5cd3d53ea2..13bc057da8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : struct, IPixel { // TODO: The WuFrameQuantizer code is rising several questions: - // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) + // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) JS. I'm afraid so. // - Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case? // (T, R, G, B, A, M2) could be grouped together! // - It's a frequently used class, we need tests! (So we can optimize safely.) There are tests in the original!!! We should just adopt them! @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int IndexBits = 5; /// - /// The index alpha bits. + /// The index alpha bits. Keep separate for now to allow easy adjustment. /// private const int IndexAlphaBits = 5; @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1; /// - /// The table length. + /// The table length. Now 1185921. /// private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount; @@ -179,18 +179,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.palette is null) { this.palette = new TPixel[this.colors]; + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + for (int k = 0; k < this.colors; k++) { this.Mark(ref this.colorCube[k], (byte)k); - float weight = Volume(ref this.colorCube[k], this.vwt.GetSpan()); + float weight = Volume(ref this.colorCube[k], vwtSpan); if (MathF.Abs(weight) > Constants.Epsilon) { - float r = Volume(ref this.colorCube[k], this.vmr.GetSpan()); - float g = Volume(ref this.colorCube[k], this.vmg.GetSpan()); - float b = Volume(ref this.colorCube[k], this.vmb.GetSpan()); - float a = Volume(ref this.colorCube[k], this.vma.GetSpan()); + float r = Volume(ref this.colorCube[k], vmrSpan); + float g = Volume(ref this.colorCube[k], vmgSpan); + float b = Volume(ref this.colorCube[k], vmbSpan); + float a = Volume(ref this.colorCube[k], vmaSpan); ref TPixel color = ref this.palette[k]; color.PackFromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); @@ -427,8 +433,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The height in pixels of the image. private void Build3DHistogram(ImageFrame source, int width, int height) { - // Build up the 3-D color histogram - // Loop through each row Span vwtSpan = this.vwt.GetSpan(); Span vmrSpan = this.vmr.GetSpan(); Span vmgSpan = this.vmg.GetSpan(); @@ -436,6 +440,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span vmaSpan = this.vma.GetSpan(); Span m2Span = this.m2.GetSpan(); + // Build up the 3-D color histogram + // Loop through each row for (int y = 0; y < height; y++) { Span row = source.GetPixelRowSpan(y); @@ -632,22 +638,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The . private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW) { - long baseR = Bottom(ref cube, direction, this.vmr.GetSpan()); - long baseG = Bottom(ref cube, direction, this.vmg.GetSpan()); - long baseB = Bottom(ref cube, direction, this.vmb.GetSpan()); - long baseA = Bottom(ref cube, direction, this.vma.GetSpan()); - long baseW = Bottom(ref cube, direction, this.vwt.GetSpan()); + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + + long baseR = Bottom(ref cube, direction, vmrSpan); + long baseG = Bottom(ref cube, direction, vmgSpan); + long baseB = Bottom(ref cube, direction, vmbSpan); + long baseA = Bottom(ref cube, direction, vmaSpan); + long baseW = Bottom(ref cube, direction, vwtSpan); float max = 0F; cut = -1; for (int i = first; i < last; i++) { - float halfR = baseR + Top(ref cube, direction, i, this.vmr.GetSpan()); - float halfG = baseG + Top(ref cube, direction, i, this.vmg.GetSpan()); - float halfB = baseB + Top(ref cube, direction, i, this.vmb.GetSpan()); - float halfA = baseA + Top(ref cube, direction, i, this.vma.GetSpan()); - float halfW = baseW + Top(ref cube, direction, i, this.vwt.GetSpan()); + float halfR = baseR + Top(ref cube, direction, i, vmrSpan); + float halfG = baseG + Top(ref cube, direction, i, vmgSpan); + float halfB = baseB + Top(ref cube, direction, i, vmbSpan); + float halfA = baseA + Top(ref cube, direction, i, vmaSpan); + float halfW = baseW + Top(ref cube, direction, i, vwtSpan); if (MathF.Abs(halfW) < Constants.Epsilon) { From 16471da37a5101979ad10b8011611f218a466def Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 18 Sep 2018 22:41:19 +0100 Subject: [PATCH 04/13] Ensure frame metadata is a deep copy. --- .../Formats/Gif/GifFrameMetaData.cs | 23 +++++++++++++- src/ImageSharp/IDeepCloneable.cs | 31 +++++++++++++++++++ src/ImageSharp/ImageFrame{TPixel}.cs | 4 +-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 20 +++++------- .../Transforms/AffineTransformProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- 8 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 src/ImageSharp/IDeepCloneable.cs diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index cc04d48314..5b4023f0f3 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Provides Gif specific metadata information for the image frame. /// - public class GifFrameMetaData + public class GifFrameMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public GifFrameMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + internal GifFrameMetaData(GifFrameMetaData other) + { + this.ColorTableLength = other.ColorTableLength; + this.FrameDelay = other.FrameDelay; + this.DisposalMethod = other.DisposalMethod; + } + /// /// Gets or sets the length of the color table for paletted images. /// If not 0, then this field indicates the maximum number of colors to use when quantizing the @@ -29,5 +47,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// be treated after being displayed. /// public GifDisposalMethod DisposalMethod { get; set; } + + /// + public IDeepCloneable DeepClone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs new file mode 100644 index 0000000000..a792fc044d --- /dev/null +++ b/src/ImageSharp/IDeepCloneable.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp +{ + /// + /// A generic interface for a deeply cloneable type. + /// + /// The type of object to clone. + public interface IDeepCloneable + where T : class, IDeepCloneable + { + /// + /// Creates a new that is a deep copy of the current instance. + /// + /// The . + T DeepClone(); + } + + /// + /// An interface for objects that can be cloned. This creates a deep copy of the object. + /// + public interface IDeepCloneable + { + /// + /// Creates a new object that is a deep copy of the current instance. + /// + /// The . + IDeepCloneable DeepClone(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 132ab598e5..dfbae817d6 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.Clone(); + this.MetaData = source.MetaData.DeepClone(); } /// @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp return this.Clone() as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.DeepClone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 4b819e2013..f1f884be68 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using SixLabors.ImageSharp.Formats; @@ -10,9 +9,9 @@ namespace SixLabors.ImageSharp.MetaData /// /// Encapsulates the metadata of an image frame. /// - public sealed class ImageFrameMetaData + public sealed class ImageFrameMetaData : IDeepCloneable { - private readonly Dictionary formatMetaData = new Dictionary(); + private readonly Dictionary formatMetaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -32,17 +31,14 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.formatMetaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } } - /// - /// Clones this ImageFrameMetaData. - /// - /// The cloned instance. - public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); + /// + public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. @@ -55,9 +51,9 @@ namespace SixLabors.ImageSharp.MetaData /// public TFormatFrameMetaData GetFormatMetaData(IImageFormat key) where TFormatMetaData : class - where TFormatFrameMetaData : class + where TFormatFrameMetaData : class, IDeepCloneable { - if (this.formatMetaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out IDeepCloneable meta)) { return (TFormatFrameMetaData)meta; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3993ab1a8d..a7cbb0337c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 0c52123755..ab1044df36 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 042ce2ff6d..680ce679e1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index fd3c34d6c1..c3d7666221 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); From eb9e051da0344787fa26023f1d9ee0368fa4d696 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 19 Sep 2018 12:11:54 +0100 Subject: [PATCH 05/13] All metadata now performs a deep clone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 20 +++++- .../Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 23 ++++++- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 18 ++++- src/ImageSharp/Formats/Png/PngMetaData.cs | 23 ++++++- src/ImageSharp/ImageFrameCollection.cs | 4 +- src/ImageSharp/Image{TPixel}.cs | 4 +- src/ImageSharp/MetaData/ImageMetaData.cs | 38 +++++----- .../MetaData/Profiles/Exif/ExifProfile.cs | 27 +++----- .../MetaData/Profiles/Exif/ExifValue.cs | 69 +++++++++---------- .../MetaData/Profiles/ICC/IccProfile.cs | 36 +++++----- .../Transforms/AffineTransformProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../MetaData/ImageMetaDataTests.cs | 2 +- .../Profiles/Exif/ExifProfileTests.cs | 28 ++++---- 17 files changed, 182 insertions(+), 120 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 3d678c13e1..8b33e30fa6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -6,13 +6,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Provides Bmp specific metadata information for the image. /// - public class BmpMetaData + public class BmpMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public BmpMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private BmpMetaData(BmpMetaData other) => this.BitsPerPixel = other.BitsPerPixel; + /// /// Gets or sets the number of bits per pixel. /// public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + /// + public IDeepCloneable DeepClone() => new BmpMetaData(this); + // TODO: Colors used once we support encoding palette bmps. } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 5b4023f0f3..0042c6a108 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Initializes a new instance of the class. /// /// The metadata to create an instance from. - internal GifFrameMetaData(GifFrameMetaData other) + private GifFrameMetaData(GifFrameMetaData other) { this.ColorTableLength = other.ColorTableLength; this.FrameDelay = other.FrameDelay; diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index f58f5dff3e..bb7fb50518 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Provides Gif specific metadata information for the image. /// - public class GifMetaData + public class GifMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public GifMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private GifMetaData(GifMetaData other) + { + this.RepeatCount = other.RepeatCount; + this.ColorTableMode = other.ColorTableMode; + this.GlobalColorTableLength = other.GlobalColorTableLength; + } + /// /// Gets or sets the number of times any animation is repeated. /// @@ -25,5 +43,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Gets or sets the length of the global color table if present. /// public int GlobalColorTableLength { get; set; } + + /// + public IDeepCloneable DeepClone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index bd7232e602..fcad29e5d0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -6,11 +6,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Provides Jpeg specific metadata information for the image. /// - public class JpegMetaData + public class JpegMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public JpegMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private JpegMetaData(JpegMetaData other) => this.Quality = other.Quality; + /// /// Gets or sets the encoded quality. /// public int Quality { get; set; } = 75; + + /// + public IDeepCloneable DeepClone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 1eb3cdad6a..9c76765146 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Provides Png specific metadata information for the image. /// - public class PngMetaData + public class PngMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public PngMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private PngMetaData(PngMetaData other) + { + this.BitDepth = other.BitDepth; + this.ColorType = other.ColorType; + this.Gamma = other.Gamma; + } + /// /// Gets or sets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. @@ -23,5 +41,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets the gamma value for the image. /// public float Gamma { get; set; } + + /// + public IDeepCloneable DeepClone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 59571ce92e..c55d636279 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); } /// diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 8bc5a40bdc..bdb1447f29 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp public Image Clone() { IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); + return new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); + var target = new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); return target; } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 7e74157e70..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.MetaData /// /// Encapsulates the metadata of an image. /// - public sealed class ImageMetaData + public sealed class ImageMetaData : IDeepCloneable { /// /// The default horizontal resolution value (dots per inch) in x direction. @@ -26,7 +25,13 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary formatMetaData = new Dictionary(); + /// + /// The default pixel resolution units. + /// The default value is . + /// + public const PixelResolutionUnit DefaultPixelResolutionUnits = PixelResolutionUnit.PixelsPerInch; + + private readonly Dictionary formatMetaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -37,6 +42,7 @@ namespace SixLabors.ImageSharp.MetaData { this.horizontalResolution = DefaultHorizontalResolution; this.verticalResolution = DefaultVerticalResolution; + this.ResolutionUnits = DefaultPixelResolutionUnits; } /// @@ -52,9 +58,9 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.formatMetaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } foreach (ImageProperty property in other.Properties) @@ -62,13 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile != null - ? new ExifProfile(other.ExifProfile) - : null; - - this.IccProfile = other.IccProfile != null - ? new IccProfile(other.IccProfile) - : null; + this.ExifProfile = other.ExifProfile?.DeepClone(); + this.IccProfile = other.IccProfile?.DeepClone(); } /// @@ -114,7 +115,7 @@ namespace SixLabors.ImageSharp.MetaData /// 02 : Pixels per centimeter /// 03 : Pixels per meter /// - public PixelResolutionUnit ResolutionUnits { get; set; } = PixelResolutionUnit.PixelsPerInch; + public PixelResolutionUnit ResolutionUnits { get; set; } /// /// Gets or sets the Exif profile. @@ -140,9 +141,9 @@ namespace SixLabors.ImageSharp.MetaData /// The . /// public TFormatMetaData GetFormatMetaData(IImageFormat key) - where TFormatMetaData : class + where TFormatMetaData : class, IDeepCloneable { - if (this.formatMetaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out IDeepCloneable meta)) { return (TFormatMetaData)meta; } @@ -152,11 +153,8 @@ namespace SixLabors.ImageSharp.MetaData return newMeta; } - /// - /// Clones this into a new instance - /// - /// The cloned metadata instance - public ImageMetaData Clone() => new ImageMetaData(this); + /// + public ImageMetaData DeepClone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 1dd8857217..b48b146f11 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -12,23 +12,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Represents an EXIF profile providing access to the collection of values. /// - public sealed class ExifProfile + public sealed class ExifProfile : IDeepCloneable { /// /// The byte array to read the EXIF profile from. /// - private byte[] data; + private readonly byte[] data; /// /// The collection of EXIF values /// private List values; - /// - /// The list of invalid EXIF tags - /// - private IReadOnlyList invalidTags; - /// /// The thumbnail offset position in the byte stream /// @@ -55,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.Parts = ExifParts.All; this.data = data; - this.invalidTags = new List(); + this.InvalidTags = new List(); } /// @@ -63,22 +58,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// by making a copy from another EXIF profile. /// /// The other EXIF profile, where the clone should be made from. - /// is null. - public ExifProfile(ExifProfile other) + private ExifProfile(ExifProfile other) { - Guard.NotNull(other, nameof(other)); - this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - this.invalidTags = new List(other.invalidTags); + this.InvalidTags = new List(other.InvalidTags); if (other.values != null) { this.values = new List(other.Values.Count); foreach (ExifValue value in other.Values) { - this.values.Add(new ExifValue(value)); + this.values.Add(value.DeepClone()); } } @@ -97,7 +89,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the tags that where found but contained an invalid value. /// - public IReadOnlyList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags { get; private set; } /// /// Gets the values of this EXIF profile. @@ -249,6 +241,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return writer.GetData(); } + /// + public ExifProfile DeepClone() => new ExifProfile(this); + /// /// Synchronizes the profiles with the specified meta data. /// @@ -294,7 +289,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - this.invalidTags = new List(reader.InvalidTags); + this.InvalidTags = new List(reader.InvalidTags); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index e6da9b7d1e..ccacfd0bf9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -11,15 +11,30 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Represent the value of the EXIF profile. /// - public sealed class ExifValue : IEquatable + public sealed class ExifValue : IEquatable, IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + /// The tag. + /// The data type. + /// The value. + /// Whether the value is an array. + internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) + { + this.Tag = tag; + this.DataType = dataType; + this.IsArray = isArray && dataType != ExifDataType.Ascii; + this.Value = value; + } + /// /// Initializes a new instance of the class /// by making a copy from another exif value. /// /// The other exif value, where the clone should be made from. - /// is null. - public ExifValue(ExifValue other) + /// is null. + private ExifValue(ExifValue other) { Guard.NotNull(other, nameof(other)); @@ -29,30 +44,17 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (!other.IsArray) { + // All types are value types except for string which is immutable so safe to simply assign. this.Value = other.Value; } else { + // All array types are value types so Clone() is sufficient here. var array = (Array)other.Value; this.Value = array.Clone(); } } - /// - /// Initializes a new instance of the class. - /// - /// The tag. - /// The data type. - /// The value. - /// Whether the value is an array. - internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) - { - this.Tag = tag; - this.DataType = dataType; - this.IsArray = isArray && dataType != ExifDataType.Ascii; - this.Value = value; - } - /// /// Gets the data type of the exif value. /// @@ -145,10 +147,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// True if the parameter is equal to the parameter; otherwise, false. /// - public static bool operator ==(ExifValue left, ExifValue right) - { - return ReferenceEquals(left, right) || left.Equals(right); - } + public static bool operator ==(ExifValue left, ExifValue right) => ReferenceEquals(left, right) || left.Equals(right); /// /// Compares two objects for equality. @@ -162,16 +161,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - public static bool operator !=(ExifValue left, ExifValue right) - { - return !(left == right); - } + public static bool operator !=(ExifValue left, ExifValue right) => !(left == right); /// - public override bool Equals(object obj) - { - return obj is ExifValue other && this.Equals(other); - } + public override bool Equals(object obj) => obj is ExifValue other && this.Equals(other); /// public bool Equals(ExifValue other) @@ -187,9 +180,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } return - this.Tag == other.Tag && - this.DataType == other.DataType && - object.Equals(this.Value, other.Value); + this.Tag == other.Tag + && this.DataType == other.DataType + && object.Equals(this.Value, other.Value); } /// @@ -205,10 +198,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public override int GetHashCode() - { - return this.GetHashCode(this); - } + public override int GetHashCode() => this.GetHashCode(this); /// public override string ToString() @@ -238,6 +228,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return sb.ToString(); } + /// + public ExifValue DeepClone() => new ExifValue(this); + /// /// Creates a new /// @@ -584,7 +577,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private static ExifValue CreateNumber(ExifTag tag, object value, bool isArray) { Type type = value?.GetType(); - if (type != null && type.IsArray) + if (type?.IsArray == true) { type = type.GetElementType(); } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index dac56c608e..44990b7ecc 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Represents an ICC profile /// - public sealed class IccProfile + public sealed class IccProfile : IDeepCloneable { /// /// The byte array to read the ICC profile from @@ -42,23 +42,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Initializes a new instance of the class. /// /// The raw ICC profile data - public IccProfile(byte[] data) - { - this.data = data; - } - - /// - /// Initializes a new instance of the class - /// by making a copy from another ICC profile. - /// - /// The other ICC profile, where the clone should be made from. - /// is null.> - public IccProfile(IccProfile other) - { - Guard.NotNull(other, nameof(other)); - - this.data = other.ToByteArray(); - } + public IccProfile(byte[] data) => this.data = data; /// /// Initializes a new instance of the class. @@ -74,6 +58,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc this.entries = new List(entries); } + /// + /// Initializes a new instance of the class + /// by making a copy from another ICC profile. + /// + /// The other ICC profile, where the clone should be made from. + /// is null.> + private IccProfile(IccProfile other) + { + Guard.NotNull(other, nameof(other)); + + this.data = other.ToByteArray(); + } + /// /// Gets or sets the profile header /// @@ -100,6 +97,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } + /// + public IccProfile DeepClone() => new IccProfile(this); + #if !NETSTANDARD1_1 /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index a7cbb0337c..a7e1589259 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index ab1044df36..df1ac32746 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 680ce679e1..15816cb4dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index c3d7666221..b1c0632c66 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index d681c90ba2..8a6c516618 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 3deb382ea6..c10ffb6c8e 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => { new ExifProfile((ExifProfile)null); }); + Assert.Throws(() => ((ExifProfile)null).DeepClone()); ExifProfile profile = GetExifProfile(); - var clone = new ExifProfile(profile); + ExifProfile clone = profile.DeepClone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = new ExifProfile(profile); + clone = profile.DeepClone(); TestProfile(clone); } @@ -234,10 +234,12 @@ namespace SixLabors.ImageSharp.Tests exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); - var metaData = new ImageMetaData(); - metaData.ExifProfile = exifProfile; - metaData.HorizontalResolution = 200; - metaData.VerticalResolution = 300; + var metaData = new ImageMetaData + { + ExifProfile = exifProfile, + HorizontalResolution = 200, + VerticalResolution = 300 + }; metaData.HorizontalResolution = 100; @@ -355,11 +357,11 @@ namespace SixLabors.ImageSharp.Tests // act Image reloadedImage = WriteAndRead(image, imageFormat); - + // assert ExifProfile actual = reloadedImage.MetaData.ExifProfile; Assert.NotNull(actual); - foreach(KeyValuePair expectedProfileValue in TestProfileValues) + foreach (KeyValuePair expectedProfileValue in TestProfileValues) { ExifValue actualProfileValue = actual.GetValue(expectedProfileValue.Key); Assert.NotNull(actualProfileValue); @@ -371,7 +373,7 @@ namespace SixLabors.ImageSharp.Tests public void ProfileToByteArray() { // arrange - byte[] exifBytesWithExifCode = ProfileResolver.ExifMarker.Concat(ExifConstants.LittleEndianByteOrderMarker).ToArray(); + byte[] exifBytesWithExifCode = ProfileResolver.ExifMarker.Concat(ExifConstants.LittleEndianByteOrderMarker).ToArray(); byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker; ExifProfile expectedProfile = CreateExifProfile(); var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); @@ -384,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(actualBytes); Assert.NotEmpty(actualBytes); Assert.Equal(exifBytesWithoutExifCode, actualBytes.Take(exifBytesWithoutExifCode.Length).ToArray()); - foreach(ExifTag expectedProfileTag in expectedProfileTags) + foreach (ExifTag expectedProfileTag in expectedProfileTags) { ExifValue actualProfileValue = actualProfile.GetValue(expectedProfileTag); ExifValue expectedProfileValue = expectedProfile.GetValue(expectedProfileTag); @@ -396,7 +398,7 @@ namespace SixLabors.ImageSharp.Tests { var profile = new ExifProfile(); - foreach(KeyValuePair exifProfileValue in TestProfileValues) + foreach (KeyValuePair exifProfileValue in TestProfileValues) { profile.SetValue(exifProfileValue.Key, exifProfileValue.Value); } @@ -416,7 +418,7 @@ namespace SixLabors.ImageSharp.Tests private static Image WriteAndRead(Image image, TestImageWriteFormat imageFormat) { - switch(imageFormat) + switch (imageFormat) { case TestImageWriteFormat.Jpeg: return WriteAndReadJpeg(image); From bcfece8a2c629e5ddd93f07200b56179c39c75a3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 19 Sep 2018 13:01:53 +0100 Subject: [PATCH 06/13] Add metadata cloning tests --- .../Formats/Bmp/BmpMetaDataTests.cs | 22 +++++++++++++ .../Formats/Gif/GifFrameMetaDataTests.cs | 32 +++++++++++++++++++ .../Formats/Gif/GifMetaDataTests.cs | 32 +++++++++++++++++++ .../Formats/Jpg/JpegMetaDataTests.cs | 22 +++++++++++++ .../Formats/Png/PngMetaDataTests.cs | 31 ++++++++++++++++++ .../MetaData/ImageFrameMetaDataTests.cs | 8 +++++ .../MetaData/ImageMetaDataTests.cs | 32 ++++++++++++++++--- 7 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs new file mode 100644 index 0000000000..991768a11a --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Bmp; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Bmp +{ + public class BmpMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; + var clone = (BmpMetaData)meta.DeepClone(); + + clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; + + Assert.False(meta.BitsPerPixel.Equals(clone.BitsPerPixel)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs new file mode 100644 index 0000000000..a39fc47b40 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Gif; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Gif +{ + public class GifFrameMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new GifFrameMetaData() + { + FrameDelay = 1, + DisposalMethod = GifDisposalMethod.RestoreToBackground, + ColorTableLength = 2 + }; + + var clone = (GifFrameMetaData)meta.DeepClone(); + + clone.FrameDelay = 2; + clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; + clone.ColorTableLength = 1; + + Assert.False(meta.FrameDelay.Equals(clone.FrameDelay)); + Assert.False(meta.DisposalMethod.Equals(clone.DisposalMethod)); + Assert.False(meta.ColorTableLength.Equals(clone.ColorTableLength)); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs new file mode 100644 index 0000000000..29db32b4ab --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Gif; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Gif +{ + public class GifMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new GifMetaData() + { + RepeatCount = 1, + ColorTableMode = GifColorTableMode.Global, + GlobalColorTableLength = 2 + }; + + var clone = (GifMetaData)meta.DeepClone(); + + clone.RepeatCount = 2; + clone.ColorTableMode = GifColorTableMode.Local; + clone.GlobalColorTableLength = 1; + + Assert.False(meta.RepeatCount.Equals(clone.RepeatCount)); + Assert.False(meta.ColorTableMode.Equals(clone.ColorTableMode)); + Assert.False(meta.GlobalColorTableLength.Equals(clone.GlobalColorTableLength)); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs new file mode 100644 index 0000000000..431de4be31 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Jpeg; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Jpg +{ + public class JpegMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new JpegMetaData() { Quality = 50 }; + var clone = (JpegMetaData)meta.DeepClone(); + + clone.Quality = 99; + + Assert.False(meta.Quality.Equals(clone.Quality)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs new file mode 100644 index 0000000000..a21bb9acbe --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Png; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Png +{ + public class PngMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new PngMetaData() + { + BitDepth = PngBitDepth.Bit16, + ColorType = PngColorType.GrayscaleWithAlpha, + Gamma = 2 + }; + var clone = (PngMetaData)meta.DeepClone(); + + clone.BitDepth = PngBitDepth.Bit2; + clone.ColorType = PngColorType.Palette; + clone.Gamma = 1; + + Assert.False(meta.BitDepth.Equals(clone.BitDepth)); + Assert.False(meta.ColorType.Equals(clone.ColorType)); + Assert.False(meta.Gamma.Equals(clone.Gamma)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 0a0ca1efa4..8c49039603 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -32,5 +32,13 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); Assert.Equal(disposalMethod, cloneGifFrameMetaData.DisposalMethod); } + + [Fact] + public void CloneIsDeep() + { + var metaData = new ImageFrameMetaData(); + ImageFrameMetaData clone = metaData.DeepClone(); + Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); + } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 8a6c516618..b9619cb3f8 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; @@ -37,19 +37,43 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(imageProperty, clone.Properties[0]); } + [Fact] + public void CloneIsDeep() + { + var metaData = new ImageMetaData(); + + var exifProfile = new ExifProfile(); + var imageProperty = new ImageProperty("name", "value"); + + metaData.ExifProfile = exifProfile; + metaData.HorizontalResolution = 4; + metaData.VerticalResolution = 2; + metaData.Properties.Add(imageProperty); + + ImageMetaData clone = metaData.DeepClone(); + clone.HorizontalResolution = 2; + clone.VerticalResolution = 4; + + Assert.False(metaData.ExifProfile.Equals(clone.ExifProfile)); + Assert.False(metaData.HorizontalResolution.Equals(clone.HorizontalResolution)); + Assert.False(metaData.VerticalResolution.Equals(clone.VerticalResolution)); + Assert.False(metaData.Properties.Equals(clone.Properties)); + Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); + } + [Fact] public void HorizontalResolution() { var metaData = new ImageMetaData(); Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=0; + metaData.HorizontalResolution = 0; Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=-1; + metaData.HorizontalResolution = -1; Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=1; + metaData.HorizontalResolution = 1; Assert.Equal(1, metaData.HorizontalResolution); } From 251ae936a72f7f789db12abc7a7f0b8d9e9bfaee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 18:07:11 +0100 Subject: [PATCH 07/13] Rename DeepClone => Clone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 2 +- src/ImageSharp/IDeepCloneable.cs | 4 ++-- src/ImageSharp/ImageFrameCollection.cs | 4 ++-- src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 4 ++-- src/ImageSharp/MetaData/ImageMetaData.cs | 8 ++++---- src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs | 4 ++-- src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs | 2 +- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 2 +- .../Processors/Transforms/AffineTransformProcessor.cs | 4 ++-- .../Processing/Processors/Transforms/CropProcessor.cs | 4 ++-- .../Processors/Transforms/ProjectiveTransformProcessor.cs | 4 ++-- .../Processing/Processors/Transforms/ResizeProcessor.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs | 2 +- .../ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs | 2 +- .../ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifProfileTests.cs | 6 +++--- 26 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 8b33e30fa6..134c8904b8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - public IDeepCloneable DeepClone() => new BmpMetaData(this); + public IDeepCloneable Clone() => new BmpMetaData(this); // TODO: Colors used once we support encoding palette bmps. } diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 0042c6a108..47af2bbdc0 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -49,6 +49,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public GifDisposalMethod DisposalMethod { get; set; } /// - public IDeepCloneable DeepClone() => new GifFrameMetaData(this); + public IDeepCloneable Clone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index bb7fb50518..7a91a3a75e 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -45,6 +45,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public int GlobalColorTableLength { get; set; } /// - public IDeepCloneable DeepClone() => new GifMetaData(this); + public IDeepCloneable Clone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index fcad29e5d0..5cef3355a0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public int Quality { get; set; } = 75; /// - public IDeepCloneable DeepClone() => new JpegMetaData(this); + public IDeepCloneable Clone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..e9f0dc6c42 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -43,6 +43,6 @@ namespace SixLabors.ImageSharp.Formats.Png public float Gamma { get; set; } /// - public IDeepCloneable DeepClone() => new PngMetaData(this); + public IDeepCloneable Clone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index a792fc044d..04c60a6252 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp /// Creates a new that is a deep copy of the current instance. /// /// The . - T DeepClone(); + T Clone(); } /// @@ -26,6 +26,6 @@ namespace SixLabors.ImageSharp /// Creates a new object that is a deep copy of the current instance. /// /// The . - IDeepCloneable DeepClone(); + IDeepCloneable Clone(); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index c55d636279..59571ce92e 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); } /// diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index dfbae817d6..132ab598e5 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.DeepClone(); + this.MetaData = source.MetaData.Clone(); } /// @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp return this.Clone() as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.DeepClone()); + var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index bdb1447f29..8bc5a40bdc 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp public Image Clone() { IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); + return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); + var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); return target; } diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index f1f884be68..26c717f2a4 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetaData.Add(meta.Key, meta.Value.Clone()); } } /// - public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); + public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 73549d98aa..44c1738cf0 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetaData.Add(meta.Key, meta.Value.Clone()); } foreach (ImageProperty property in other.Properties) @@ -68,8 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile?.DeepClone(); - this.IccProfile = other.IccProfile?.DeepClone(); + this.ExifProfile = other.ExifProfile?.Clone(); + this.IccProfile = other.IccProfile?.Clone(); } /// @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.MetaData } /// - public ImageMetaData DeepClone() => new ImageMetaData(this); + public ImageMetaData Clone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b48b146f11..7b71a78eb9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (ExifValue value in other.Values) { - this.values.Add(value.DeepClone()); + this.values.Add(value.Clone()); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifProfile DeepClone() => new ExifProfile(this); + public ExifProfile Clone() => new ExifProfile(this); /// /// Synchronizes the profiles with the specified meta data. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index ccacfd0bf9..88827820c3 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifValue DeepClone() => new ExifValue(this); + public ExifValue Clone() => new ExifValue(this); /// /// Creates a new diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 44990b7ecc..3885303d45 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } /// - public IccProfile DeepClone() => new IccProfile(this); + public IccProfile Clone() => new IccProfile(this); #if !NETSTANDARD1_1 diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index a7e1589259..3993ab1a8d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index df1ac32746..0c52123755 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,10 +36,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 15816cb4dd..042ce2ff6d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index b1c0632c66..fd3c34d6c1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,10 +215,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs index 991768a11a..ca36a1eb5f 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp public void CloneIsDeep() { var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; - var clone = (BmpMetaData)meta.DeepClone(); + var clone = (BmpMetaData)meta.Clone(); clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs index a39fc47b40..4879a56739 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif ColorTableLength = 2 }; - var clone = (GifFrameMetaData)meta.DeepClone(); + var clone = (GifFrameMetaData)meta.Clone(); clone.FrameDelay = 2; clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs index 29db32b4ab..4f42753164 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif GlobalColorTableLength = 2 }; - var clone = (GifMetaData)meta.DeepClone(); + var clone = (GifMetaData)meta.Clone(); clone.RepeatCount = 2; clone.ColorTableMode = GifColorTableMode.Local; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs index 431de4be31..054e79f514 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void CloneIsDeep() { var meta = new JpegMetaData() { Quality = 50 }; - var clone = (JpegMetaData)meta.DeepClone(); + var clone = (JpegMetaData)meta.Clone(); clone.Quality = 99; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs index a21bb9acbe..4b209613ae 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png ColorType = PngColorType.GrayscaleWithAlpha, Gamma = 2 }; - var clone = (PngMetaData)meta.DeepClone(); + var clone = (PngMetaData)meta.Clone(); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 8c49039603..428b7c431a 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests public void CloneIsDeep() { var metaData = new ImageFrameMetaData(); - ImageFrameMetaData clone = metaData.DeepClone(); + ImageFrameMetaData clone = metaData.Clone(); Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index b9619cb3f8..79fd7b7d2b 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.DeepClone(); + ImageMetaData clone = metaData.Clone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.DeepClone(); + ImageMetaData clone = metaData.Clone(); clone.HorizontalResolution = 2; clone.VerticalResolution = 4; diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index c10ffb6c8e..ee41c1759f 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => ((ExifProfile)null).DeepClone()); + Assert.Throws(() => ((ExifProfile)null).Clone()); ExifProfile profile = GetExifProfile(); - ExifProfile clone = profile.DeepClone(); + ExifProfile clone = profile.Clone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = profile.DeepClone(); + clone = profile.Clone(); TestProfile(clone); } From 061436f7656828f4f07586b87e118479b6b3f836 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 20 Sep 2018 11:08:49 -0700 Subject: [PATCH 08/13] Fix issue on mono <= 5.14 when reading multiple png data chunks. Fixes #598 --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 139 +++++++++++------- .../Formats/Png/Zlib/ZlibInflateStream.cs | 16 +- 2 files changed, 98 insertions(+), 57 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 9281927012..76162eacbb 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -187,6 +187,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private bool hasTrans; + /// + /// The next chunk of data to return + /// + private PngChunk? nextChunk; + /// /// Initializes a new instance of the class. /// @@ -223,67 +228,66 @@ namespace SixLabors.ImageSharp.Formats.Png Image image = null; try { - using (var deframeStream = new ZlibInflateStream(this.currentStream)) + while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) { - while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) + try { - try + switch (chunk.Type) { - switch (chunk.Type) - { - case PngChunkType.Header: - this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); - this.ValidateHeader(); - break; - case PngChunkType.Physical: - this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); - break; - case PngChunkType.Gamma: - this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); - break; - case PngChunkType.Data: - if (image is null) - { - this.InitializeImage(metaData, out image); - } - - deframeStream.AllocateNewBytes(chunk.Length); + case PngChunkType.Header: + this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); + this.ValidateHeader(); + break; + case PngChunkType.Physical: + this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Gamma: + this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Data: + if (image is null) + { + this.InitializeImage(metaData, out image); + } + + using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) + { + deframeStream.AllocateNewBytes(chunk.Length); this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); - this.currentStream.Read(this.crcBuffer, 0, 4); - break; - case PngChunkType.Palette: - byte[] pal = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); - this.palette = pal; - break; - case PngChunkType.PaletteAlpha: - byte[] alpha = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); - this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha); - break; - case PngChunkType.Text: - this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); - break; - case PngChunkType.Exif: - if (!this.ignoreMetadata) - { - byte[] exifData = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); - metaData.ExifProfile = new ExifProfile(exifData); - } - - break; - case PngChunkType.End: - this.isEndChunkReached = true; - break; - } - } - finally - { - chunk.Data?.Dispose(); // Data is rented in ReadChunkData() + } + break; + case PngChunkType.Palette: + byte[] pal = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); + this.palette = pal; + break; + case PngChunkType.PaletteAlpha: + byte[] alpha = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); + this.paletteAlpha = alpha; + this.AssignTransparentMarkers(alpha); + break; + case PngChunkType.Text: + this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); + break; + case PngChunkType.Exif: + if (!this.ignoreMetadata) + { + byte[] exifData = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); + metaData.ExifProfile = new ExifProfile(exifData); + } + + break; + case PngChunkType.End: + this.isEndChunkReached = true; + break; } } + finally + { + chunk.Data?.Dispose(); // Data is rented in ReadChunkData() + } } if (image is null) @@ -1366,6 +1370,25 @@ namespace SixLabors.ImageSharp.Formats.Png metadata.Properties.Add(new ImageProperty(name, value)); } + /// + /// Reads the next data chunk. + /// + /// Count of bytes in the next data chunk, or 0 if there are no more data chunks left. + private int ReadNextDataChunk() + { + this.currentStream.Read(this.crcBuffer, 0, 4); + + this.TryReadChunk(out PngChunk chunk); + + if (chunk.Type == PngChunkType.Data) + { + return chunk.Length; + } + + this.nextChunk = chunk; + return 0; + } + /// /// Reads a chunk from the stream. /// @@ -1375,6 +1398,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// private bool TryReadChunk(out PngChunk chunk) { + if (this.nextChunk != null) + { + chunk = this.nextChunk.Value; + return true; + } + int length = this.ReadChunkLength(); if (length == -1) diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index 55432d60b1..c2f6d6d881 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -52,13 +52,20 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// private int currentDataRemaining; + /// + /// Delegate to get more data once we've exhausted the current data remaining + /// + private Func getData; + /// /// Initializes a new instance of the class. /// /// The inner raw stream - public ZlibInflateStream(Stream innerStream) + /// A delegate to get more data from the inner stream + public ZlibInflateStream(Stream innerStream, Func getData) { this.innerStream = innerStream; + this.getData = getData; } /// @@ -112,7 +119,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (this.currentDataRemaining == 0) { - return 0; + this.currentDataRemaining = this.getData(); + + if (this.currentDataRemaining == 0) + { + return 0; + } } int bytesToRead = Math.Min(count, this.currentDataRemaining); From 6e47624413df86782db4e034110506bb26e868cb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 21:07:31 +0100 Subject: [PATCH 09/13] Add Clone overloads for new configuration. --- src/ImageSharp/Configuration.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 50 +++++++---- src/ImageSharp/Image{TPixel}.cs | 88 ++++++++++--------- tests/ImageSharp.Tests/ConfigurationTests.cs | 2 +- .../Image/ImageTests.WrapMemory.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 4 +- .../ImageProviders/TestImageProvider.cs | 2 +- 7 files changed, 86 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 1b009bfedd..354701747a 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp /// Creates a shallow copy of the /// /// A new configuration instance - public Configuration ShallowCopy() + public Configuration Clone() { return new Configuration { diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 132ab598e5..9ff6c6511c 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -95,6 +95,10 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// + /// 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 memory source. internal ImageFrame(Configuration configuration, int width, int height, MemorySource memorySource) : this(configuration, width, height, memorySource, new ImageFrameMetaData()) { @@ -103,12 +107,12 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// - internal ImageFrame( - Configuration configuration, - int width, - int height, - MemorySource memorySource, - ImageFrameMetaData metaData) + /// 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 memory source. + /// The meta data. + internal ImageFrame(Configuration configuration, int width, int height, MemorySource memorySource, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); @@ -247,25 +251,47 @@ namespace SixLabors.ImageSharp /// public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + /// + /// Clones the current instance. + /// + /// The + internal ImageFrame Clone() => this.Clone(this.configuration); + + /// + /// Clones the current instance. + /// + /// The configuration providing initialization code which allows extending the library. + /// The + internal ImageFrame Clone(Configuration configuration) => new ImageFrame(configuration, this); + /// /// Returns a copy of the image frame in the given pixel format. /// /// The pixel format. /// The internal ImageFrame CloneAs() + where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + + /// + /// Returns a copy of the image frame in the given pixel format. + /// + /// The pixel format. + /// The configuration providing initialization code which allows extending the library. + /// The + internal ImageFrame CloneAs(Configuration configuration) where TPixel2 : struct, IPixel { if (typeof(TPixel2) == typeof(TPixel)) { - return this.Clone() as ImageFrame; + return this.Clone(configuration) as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.Clone()); ParallelFor.WithTemporaryBuffer( 0, this.Height, - this.configuration, + configuration, this.Width, (int y, IMemoryOwner tempRowBuffer) => { @@ -298,12 +324,6 @@ namespace SixLabors.ImageSharp }); } - /// - /// Clones the current instance. - /// - /// The - internal ImageFrame Clone() => new ImageFrame(this.configuration, this); - /// void IDisposable.Dispose() => this.Dispose(); } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 8bc5a40bdc..3ee369fdad 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -11,7 +11,6 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; namespace SixLabors.ImageSharp { @@ -23,15 +22,12 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { private readonly Configuration configuration; - private readonly ImageFrameCollection frames; /// /// 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 configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. public Image(Configuration configuration, int width, int height) @@ -43,9 +39,7 @@ namespace SixLabors.ImageSharp /// 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 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. @@ -69,9 +63,7 @@ namespace SixLabors.ImageSharp /// 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 configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. /// The images metadata. @@ -80,37 +72,41 @@ namespace SixLabors.ImageSharp this.configuration = configuration ?? Configuration.Default; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); + this.Frames = new ImageFrameCollection(this, width, height, default(TPixel)); } /// /// Initializes a new instance of the class /// wrapping an external /// + /// The configuration providing initialization code which allows extending the library. + /// The memory source. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The images metadata. internal Image(Configuration configuration, MemorySource memorySource, int width, int height, ImageMetaData metadata) { this.configuration = configuration; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata; - this.frames = new ImageFrameCollection(this, width, height, memorySource); + this.Frames = new ImageFrameCollection(this, width, height, memorySource); } /// /// 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 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. /// The images metadata. - internal Image(Configuration configuration, int width, int height, TPixel backgroundColor, 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.frames = new ImageFrameCollection(this, width, height, backgroundColor); + this.Frames = new ImageFrameCollection(this, width, height, backgroundColor); } /// @@ -126,7 +122,7 @@ namespace SixLabors.ImageSharp this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, frames); + this.Frames = new ImageFrameCollection(this, frames); } /// @@ -138,10 +134,10 @@ namespace SixLabors.ImageSharp public PixelTypeInfo PixelType { get; } /// - public int Width => this.frames.RootFrame.Width; + public int Width => this.Frames.RootFrame.Width; /// - public int Height => this.frames.RootFrame.Height; + public int Height => this.Frames.RootFrame.Height; /// public ImageMetaData MetaData { get; } @@ -149,12 +145,12 @@ namespace SixLabors.ImageSharp /// /// Gets the frames. /// - public ImageFrameCollection Frames => this.frames; + public ImageFrameCollection Frames { get; } /// /// Gets the root frame. /// - private IPixelSource PixelSource => this.frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image)); + private IPixelSource PixelSource => this.Frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image)); /// /// Gets or sets the pixel at the specified position. @@ -187,16 +183,17 @@ namespace SixLabors.ImageSharp /// Clones the current image /// /// Returns a new image with all the same metadata as the original. - public Image Clone() - { - IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); - } + public Image Clone() => this.Clone(this.configuration); - /// - public override string ToString() + /// + /// Clones the current image with the given configueation. + /// + /// The configuration providing initialization code which allows extending the library. + /// Returns a new with all the same pixel data as the original. + public Image Clone(Configuration configuration) { - return $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + IEnumerable> clonedFrames = this.Frames.Select(x => x.Clone(configuration)); + return new Image(configuration, this.MetaData.Clone(), clonedFrames); } /// @@ -205,22 +202,27 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The public Image CloneAs() - where TPixel2 : struct, IPixel - { - IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); - - return target; - } + where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); /// - /// Releases managed resources. + /// Returns a copy of the image in the given pixel format. /// - public void Dispose() + /// The pixel format. + /// The configuration providing initialization code which allows extending the library. + /// The + public Image CloneAs(Configuration configuration) + where TPixel2 : struct, IPixel { - this.frames.Dispose(); + IEnumerable> clonedFrames = this.Frames.Select(x => x.CloneAs(configuration)); + return new Image(configuration, this.MetaData.Clone(), clonedFrames); } + /// + public void Dispose() => this.Frames.Dispose(); + + /// + public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + /// /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// @@ -229,9 +231,9 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - for (int i = 0; i < this.frames.Count; i++) + for (int i = 0; i < this.Frames.Count; i++) { - this.frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.frames[i]); + this.Frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.Frames[i]); } } } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 6a8479b2b2..963d674466 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests { // the shallow copy of configuration should behave exactly like the default configuration, // so by using the copy, we test both the default and the copy. - this.DefaultConfiguration = Configuration.CreateDefaultInstance().ShallowCopy(); + this.DefaultConfiguration = Configuration.CreateDefaultInstance().Clone(); this.ConfigurationEmpty = new Configuration(); } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 69572425c9..16d999ad25 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void WrapMemory_CreatedImageIsCorrect() { - Configuration cfg = Configuration.Default.ShallowCopy(); + Configuration cfg = Configuration.Default.Clone(); var metaData = new ImageMetaData(); var array = new Rgba32[25]; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index ed142ed974..f3c04d5e14 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Configuration_Width_Height() { - Configuration configuration = Configuration.Default.ShallowCopy(); + Configuration configuration = Configuration.Default.Clone(); using (var image = new Image(configuration, 11, 23)) { @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Configuration_Width_Height_BackroundColor() { - Configuration configuration = Configuration.Default.ShallowCopy(); + Configuration configuration = Configuration.Default.Clone(); Rgba32 color = Rgba32.Aquamarine; using (var image = new Image(configuration, 11, 23, color)) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index ab0cc42f93..30ac0856c7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests public virtual string SourceFileOrDescription => ""; - public Configuration Configuration { get; set; } = Configuration.Default.ShallowCopy(); + public Configuration Configuration { get; set; } = Configuration.Default.Clone(); /// /// Utility instance to provide informations about the test image & manage input/output From 4979e1971f5fa16fb440ee1bdee15a51d0287c56 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 20 Sep 2018 13:44:33 -0700 Subject: [PATCH 10/13] Fixes to make all unit tests pass - Also fix some formatting warnings --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 23 +++++++--- .../Formats/Png/Zlib/ZlibInflateStream.cs | 44 +++++++++++-------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 76162eacbb..ef2f226556 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -252,9 +252,10 @@ namespace SixLabors.ImageSharp.Formats.Png using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) { - deframeStream.AllocateNewBytes(chunk.Length); + deframeStream.AllocateNewBytes(chunk.Length); this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); } + break; case PngChunkType.Palette: byte[] pal = new byte[chunk.Length]; @@ -1376,16 +1377,23 @@ namespace SixLabors.ImageSharp.Formats.Png /// Count of bytes in the next data chunk, or 0 if there are no more data chunks left. private int ReadNextDataChunk() { - this.currentStream.Read(this.crcBuffer, 0, 4); + if (this.nextChunk != null) + { + return 0; + } - this.TryReadChunk(out PngChunk chunk); + this.currentStream.Read(this.crcBuffer, 0, 4); - if (chunk.Type == PngChunkType.Data) + if (this.TryReadChunk(out PngChunk chunk)) { - return chunk.Length; + if (chunk.Type == PngChunkType.Data) + { + return chunk.Length; + } + + this.nextChunk = chunk; } - this.nextChunk = chunk; return 0; } @@ -1401,6 +1409,9 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.nextChunk != null) { chunk = this.nextChunk.Value; + + this.nextChunk = null; + return true; } diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index c2f6d6d881..a92220a595 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -42,11 +42,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// private bool isDisposed; - /// - /// Whether the crc value has been read. - /// - private bool crcRead; - /// /// The current data remaining to be read /// @@ -119,17 +114,36 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (this.currentDataRemaining == 0) { - this.currentDataRemaining = this.getData(); + // last buffer was read in its entirety, let's make sure we don't actually have more + this.currentDataRemaining = this.getData(); - if (this.currentDataRemaining == 0) - { - return 0; - } + if (this.currentDataRemaining == 0) + { + return 0; + } } int bytesToRead = Math.Min(count, this.currentDataRemaining); this.currentDataRemaining -= bytesToRead; - return this.innerStream.Read(buffer, offset, bytesToRead); + int bytesRead = this.innerStream.Read(buffer, offset, bytesToRead); + + // keep reading data until we've reached the end of the stream or filled the buffer + while (this.currentDataRemaining == 0 && bytesRead < count) + { + this.currentDataRemaining = this.getData(); + + if (this.currentDataRemaining == 0) + { + return bytesRead; + } + + offset += bytesRead; + bytesToRead = Math.Min(count - bytesRead, this.currentDataRemaining); + this.currentDataRemaining -= bytesToRead; + bytesRead += this.innerStream.Read(buffer, offset, bytesToRead); + } + + return bytesRead; } /// @@ -165,14 +179,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { this.compressedStream.Dispose(); this.compressedStream = null; - - if (!this.crcRead) - { - // Consume the trailing 4 bytes - this.innerStream.Read(ChecksumBuffer, 0, 4); - this.currentDataRemaining -= 4; - this.crcRead = true; - } } } From b36a58bcded1e7c4199e2fe3359dafa61dba88f0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 23:09:28 +0100 Subject: [PATCH 11/13] Clone => DeepClone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 2 +- src/ImageSharp/IDeepCloneable.cs | 4 ++-- src/ImageSharp/ImageFrameCollection.cs | 18 ++++++------------ src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 4 ++-- src/ImageSharp/MetaData/ImageMetaData.cs | 8 ++++---- .../MetaData/Profiles/Exif/ExifProfile.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifValue.cs | 2 +- .../MetaData/Profiles/ICC/IccProfile.cs | 2 +- .../Transforms/AffineTransformProcessor.cs | 4 ++-- .../Processors/Transforms/CropProcessor.cs | 4 ++-- .../Transforms/ProjectiveTransformProcessor.cs | 4 ++-- .../Processors/Transforms/ResizeProcessor.cs | 4 ++-- .../Formats/Bmp/BmpMetaDataTests.cs | 2 +- .../Formats/Gif/GifFrameMetaDataTests.cs | 2 +- .../Formats/Gif/GifMetaDataTests.cs | 2 +- .../Formats/Jpg/JpegMetaDataTests.cs | 2 +- .../Formats/Png/PngMetaDataTests.cs | 2 +- .../MetaData/ImageFrameMetaDataTests.cs | 2 +- .../MetaData/ImageMetaDataTests.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifProfileTests.cs | 6 +++--- 26 files changed, 46 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 134c8904b8..8b33e30fa6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - public IDeepCloneable Clone() => new BmpMetaData(this); + public IDeepCloneable DeepClone() => new BmpMetaData(this); // TODO: Colors used once we support encoding palette bmps. } diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 47af2bbdc0..0042c6a108 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -49,6 +49,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public GifDisposalMethod DisposalMethod { get; set; } /// - public IDeepCloneable Clone() => new GifFrameMetaData(this); + public IDeepCloneable DeepClone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index 7a91a3a75e..bb7fb50518 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -45,6 +45,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public int GlobalColorTableLength { get; set; } /// - public IDeepCloneable Clone() => new GifMetaData(this); + public IDeepCloneable DeepClone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index 5cef3355a0..fcad29e5d0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public int Quality { get; set; } = 75; /// - public IDeepCloneable Clone() => new JpegMetaData(this); + public IDeepCloneable DeepClone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index e9f0dc6c42..9c76765146 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -43,6 +43,6 @@ namespace SixLabors.ImageSharp.Formats.Png public float Gamma { get; set; } /// - public IDeepCloneable Clone() => new PngMetaData(this); + public IDeepCloneable DeepClone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index 04c60a6252..a792fc044d 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp /// Creates a new that is a deep copy of the current instance. /// /// The . - T Clone(); + T DeepClone(); } /// @@ -26,6 +26,6 @@ namespace SixLabors.ImageSharp /// Creates a new object that is a deep copy of the current instance. /// /// The . - IDeepCloneable Clone(); + IDeepCloneable DeepClone(); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 59571ce92e..bbe05ce435 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp public ImageFrame InsertFrame(int index, ImageFrame source) { this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(); + ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); this.frames.Insert(index, clonedFrame); return clonedFrame; } @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp public ImageFrame AddFrame(ImageFrame source) { this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(); + ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); this.frames.Add(clonedFrame); return clonedFrame; } @@ -155,10 +155,7 @@ namespace SixLabors.ImageSharp /// /// true if the contains the specified frame; otherwise, false. /// - public bool Contains(ImageFrame frame) - { - return this.frames.Contains(frame); - } + public bool Contains(ImageFrame frame) => this.frames.Contains(frame); /// /// Moves an from to . @@ -195,7 +192,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); } /// @@ -208,7 +205,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); } /// @@ -217,10 +214,7 @@ namespace SixLabors.ImageSharp /// /// The new . /// - public ImageFrame CreateFrame() - { - return this.CreateFrame(default); - } + public ImageFrame CreateFrame() => this.CreateFrame(default); /// /// Creates a new and appends it to the end of the collection. diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 9ff6c6511c..5f1aa5a38e 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.Clone(); + this.MetaData = source.MetaData.DeepClone(); } /// @@ -286,7 +286,7 @@ namespace SixLabors.ImageSharp return this.Clone(configuration) as ImageFrame; } - var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 3ee369fdad..9d4c1ef0b3 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp public Image Clone(Configuration configuration) { IEnumerable> clonedFrames = this.Frames.Select(x => x.Clone(configuration)); - return new Image(configuration, this.MetaData.Clone(), clonedFrames); + return new Image(configuration, this.MetaData.DeepClone(), clonedFrames); } /// @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.Frames.Select(x => x.CloneAs(configuration)); - return new Image(configuration, this.MetaData.Clone(), clonedFrames); + return new Image(configuration, this.MetaData.DeepClone(), clonedFrames); } /// diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 26c717f2a4..f1f884be68 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.Clone()); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } } /// - public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); + public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 44c1738cf0..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.Clone()); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } foreach (ImageProperty property in other.Properties) @@ -68,8 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile?.Clone(); - this.IccProfile = other.IccProfile?.Clone(); + this.ExifProfile = other.ExifProfile?.DeepClone(); + this.IccProfile = other.IccProfile?.DeepClone(); } /// @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.MetaData } /// - public ImageMetaData Clone() => new ImageMetaData(this); + public ImageMetaData DeepClone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 7b71a78eb9..b48b146f11 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (ExifValue value in other.Values) { - this.values.Add(value.Clone()); + this.values.Add(value.DeepClone()); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifProfile Clone() => new ExifProfile(this); + public ExifProfile DeepClone() => new ExifProfile(this); /// /// Synchronizes the profiles with the specified meta data. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 88827820c3..ccacfd0bf9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifValue Clone() => new ExifValue(this); + public ExifValue DeepClone() => new ExifValue(this); /// /// Creates a new diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 3885303d45..44990b7ecc 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } /// - public IccProfile Clone() => new IccProfile(this); + public IccProfile DeepClone() => new IccProfile(this); #if !NETSTANDARD1_1 diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3993ab1a8d..a7e1589259 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 0c52123755..df1ac32746 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,10 +36,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 042ce2ff6d..15816cb4dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index fd3c34d6c1..b1c0632c66 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,10 +215,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs index ca36a1eb5f..991768a11a 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp public void CloneIsDeep() { var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; - var clone = (BmpMetaData)meta.Clone(); + var clone = (BmpMetaData)meta.DeepClone(); clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs index 4879a56739..a39fc47b40 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif ColorTableLength = 2 }; - var clone = (GifFrameMetaData)meta.Clone(); + var clone = (GifFrameMetaData)meta.DeepClone(); clone.FrameDelay = 2; clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs index 4f42753164..29db32b4ab 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif GlobalColorTableLength = 2 }; - var clone = (GifMetaData)meta.Clone(); + var clone = (GifMetaData)meta.DeepClone(); clone.RepeatCount = 2; clone.ColorTableMode = GifColorTableMode.Local; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs index 054e79f514..431de4be31 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void CloneIsDeep() { var meta = new JpegMetaData() { Quality = 50 }; - var clone = (JpegMetaData)meta.Clone(); + var clone = (JpegMetaData)meta.DeepClone(); clone.Quality = 99; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs index 4b209613ae..a21bb9acbe 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png ColorType = PngColorType.GrayscaleWithAlpha, Gamma = 2 }; - var clone = (PngMetaData)meta.Clone(); + var clone = (PngMetaData)meta.DeepClone(); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 428b7c431a..8c49039603 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests public void CloneIsDeep() { var metaData = new ImageFrameMetaData(); - ImageFrameMetaData clone = metaData.Clone(); + ImageFrameMetaData clone = metaData.DeepClone(); Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 79fd7b7d2b..b9619cb3f8 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); clone.HorizontalResolution = 2; clone.VerticalResolution = 4; diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index ee41c1759f..c10ffb6c8e 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => ((ExifProfile)null).Clone()); + Assert.Throws(() => ((ExifProfile)null).DeepClone()); ExifProfile profile = GetExifProfile(); - ExifProfile clone = profile.Clone(); + ExifProfile clone = profile.DeepClone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = profile.Clone(); + clone = profile.DeepClone(); TestProfile(clone); } From d3290243d8640f5455126b7aff4b0c342c6e5e71 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 21 Sep 2018 23:40:25 +0200 Subject: [PATCH 12/13] covariant interface: IDeepCloneable --- src/ImageSharp/IDeepCloneable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index a792fc044d..f80247a5d0 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -7,8 +7,8 @@ namespace SixLabors.ImageSharp /// A generic interface for a deeply cloneable type. /// /// The type of object to clone. - public interface IDeepCloneable - where T : class, IDeepCloneable + public interface IDeepCloneable + where T : class { /// /// Creates a new that is a deep copy of the current instance. From f8c08beaf03d102c2c2bb082985140efcc009abb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:07:25 +0200 Subject: [PATCH 13/13] skip tests in ReferenceDecoderBenchmarks --- .../TestUtilities/Tests/ReferenceDecoderBenchmarks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs index 724c2e4144..033f0866a3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests private ITestOutputHelper Output { get; } public const string SkipBenchmarks = -#if false +#if true "Benchmark, enable manually!"; #else null;