From 92ab411f3e688c1ecc3b4a4140ac74eaf14a48b6 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 15:42:48 -0700 Subject: [PATCH 01/21] Expose LoadPixelData overloads accepting Span --- src/ImageSharp/Image.LoadPixelData.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index 0179e62acc..5f85d61ba3 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -33,7 +33,7 @@ public static Image LoadPixelData(TPixel[] data, int width, int /// The height of the final image. /// The pixel format. /// A new . - private static Image LoadPixelData(Span data, int width, int height) + public static Image LoadPixelData(Span data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(Configuration.Default, data, width, height); @@ -57,7 +57,7 @@ public static Image LoadPixelData(byte[] data, int width, int he /// The height of the final image. /// The pixel format. /// A new . - private static Image LoadPixelData(Span data, int width, int height) + public static Image LoadPixelData(Span data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(Configuration.Default, data, width, height); @@ -83,7 +83,7 @@ public static Image LoadPixelData(Configuration config, byte[] d /// The height of the final image. /// The pixel format. /// A new . - private static Image LoadPixelData(Configuration config, Span data, int width, int height) + public static Image LoadPixelData(Configuration config, Span data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(config, MemoryMarshal.Cast(data), width, height); @@ -111,7 +111,7 @@ public static Image LoadPixelData(Configuration config, TPixel[] /// The height of the final image. /// The pixel format. /// A new . - private static Image LoadPixelData(Configuration config, Span data, int width, int height) + public static Image LoadPixelData(Configuration config, Span data, int width, int height) where TPixel : struct, IPixel { int count = width * height; From cddab85a5ac91104fdcb96f277e1d0b71f4ceb23 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:21:45 -0700 Subject: [PATCH 02/21] Cleanup ByteExtensions --- .../Common/Extensions/ByteExtensions.cs | 35 ++----------------- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 12 ++++--- 3 files changed, 11 insertions(+), 38 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs index b5b868deaa..ec53063e61 100644 --- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ByteExtensions.cs @@ -12,44 +12,15 @@ namespace SixLabors.ImageSharp /// internal static class ByteExtensions { - /// - /// Returns a reference to the given position of the array unsafe casted to . - /// - /// The byte array. - /// The offset in bytes. - /// The reference at the given offset. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref Rgb24 GetRgb24(this byte[] bytes, int offset) - { - DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset)); - - return ref Unsafe.As(ref bytes[offset]); - } - /// /// Returns a reference to the given position of the span unsafe casted to . /// /// The byte span. - /// The offset in bytes. - /// The reference at the given offset. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref Rgb24 GetRgb24(this Span bytes, int offset) - { - DebugGuard.MustBeLessThan(offset + 2, bytes.Length, nameof(offset)); - - return ref Unsafe.As(ref bytes[offset]); - } - - /// - /// Returns a reference to the given position of the buffer pointed by `baseRef` unsafe casted to . - /// - /// A reference to the beginning of the buffer - /// The offset in bytes. /// The reference at the given offset. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref Rgb24 GetRgb24(ref byte baseRef, int offset) + public static ref Rgb24 AsRgb24(this Span bytes) { - return ref Unsafe.As(ref Unsafe.Add(ref baseRef, offset)); - } + return ref Unsafe.As(ref bytes[0]); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 1900d0df05..6c03bd2b1e 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -461,7 +461,7 @@ private void ReadFrameColors(ref Image image, ref ImageFrame(ReadOnlySpan defilteredSca where TPixel : struct, IPixel { ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - byte[] pal = this.palette; + Span pal = this.palette; var color = default(TPixel); var rgba = default(Rgba32); @@ -868,7 +868,7 @@ private void ProcessScanlineFromPalette(ReadOnlySpan defilteredSca int pixelOffset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - rgba.Rgb = pal.GetRgb24(pixelOffset); + rgba.Rgb = pal.Slice(pixelOffset).AsRgb24(); color.PackFromRgba32(rgba); row[x] = color; @@ -883,7 +883,7 @@ private void ProcessScanlineFromPalette(ReadOnlySpan defilteredSca int index = newScanline[x]; int pixelOffset = index * 3; - rgba.Rgb = pal.GetRgb24(pixelOffset); + rgba.Rgb = pal.Slice(pixelOffset).AsRgb24(); color.PackFromRgba32(rgba); row[x] = color; @@ -946,9 +946,11 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); var rgba = default(Rgba32); + Span pal = this.palette; if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { + // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) @@ -957,7 +959,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi int offset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - rgba.Rgb = this.palette.GetRgb24(offset); + rgba.Rgb = pal.Slice(offset).AsRgb24(); color.PackFromRgba32(rgba); rowSpan[x] = color; @@ -972,7 +974,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi int index = newScanline[o]; int offset = index * 3; - rgba.Rgb = this.palette.GetRgb24(offset); + rgba.Rgb = pal.Slice(offset).AsRgb24(); color.PackFromRgba32(rgba); rowSpan[x] = color; From 54791bf782dc8faf124670e9184bdd7286e4a23f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:22:28 -0700 Subject: [PATCH 03/21] Remove trailing whitespace --- src/ImageSharp/Common/Extensions/ByteExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs index ec53063e61..ee41096cfe 100644 --- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ByteExtensions.cs @@ -21,6 +21,6 @@ internal static class ByteExtensions public static ref Rgb24 AsRgb24(this Span bytes) { return ref Unsafe.As(ref bytes[0]); - } + } } } \ No newline at end of file From c6c9ae8a2a070dfc27cdf66cb584fb348f3ea0ac Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:37:10 -0700 Subject: [PATCH 04/21] Simplify png decoder --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 20a650e1f9..b89c655c80 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -853,7 +853,7 @@ private void ProcessScanlineFromPalette(ReadOnlySpan defilteredSca where TPixel : struct, IPixel { ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); - Span pal = this.palette; + ReadOnlySpan pal = MemoryMarshal.Cast(this.palette); var color = default(TPixel); var rgba = default(Rgba32); @@ -865,10 +865,9 @@ private void ProcessScanlineFromPalette(ReadOnlySpan defilteredSca for (int x = 0; x < this.header.Width; x++) { int index = newScanline[x]; - int pixelOffset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - rgba.Rgb = pal.Slice(pixelOffset).AsRgb24(); + rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); row[x] = color; @@ -881,9 +880,8 @@ private void ProcessScanlineFromPalette(ReadOnlySpan defilteredSca for (int x = 0; x < this.header.Width; x++) { int index = newScanline[x]; - int pixelOffset = index * 3; - rgba.Rgb = pal.Slice(pixelOffset).AsRgb24(); + rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); row[x] = color; @@ -946,7 +944,7 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth); var rgba = default(Rgba32); - Span pal = this.palette; + Span pal = MemoryMarshal.Cast(this.palette); if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { @@ -956,10 +954,9 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; - int offset = index * 3; rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : (byte)255; - rgba.Rgb = pal.Slice(offset).AsRgb24(); + rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); rowSpan[x] = color; @@ -972,10 +969,8 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { int index = newScanline[o]; - int offset = index * 3; - - rgba.Rgb = pal.Slice(offset).AsRgb24(); + rgba.Rgb = pal[index]; color.PackFromRgba32(rgba); rowSpan[x] = color; } From 1653a93c22a243d762c11bca758e27dfe96b18ba Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:44:27 -0700 Subject: [PATCH 05/21] Simplify GifDecoder --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 24 +++++++------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 6c03bd2b1e..4fbd4baf51 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -39,11 +39,6 @@ internal sealed class GifDecoderCore /// private IManagedByteBuffer globalColorTable; - /// - /// The global color table length - /// - private int globalColorTableLength; - /// /// The area to restore. /// @@ -333,8 +328,8 @@ private void ReadFrame(ref Image image, ref ImageFrame p indices = this.configuration.MemoryManager.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, true); this.ReadFrameIndices(imageDescriptor, indices.Span); - IManagedByteBuffer colorTable = localColorTable ?? this.globalColorTable; - this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable.Span, imageDescriptor); + ReadOnlySpan colorTable = MemoryMarshal.Cast((localColorTable ?? this.globalColorTable).Span); + this.ReadFrameColors(ref image, ref previousFrame, indices.Span, colorTable, imageDescriptor); // Skip any remaining blocks this.Skip(0); @@ -370,7 +365,7 @@ private void ReadFrameIndices(in GifImageDescriptor imageDescriptor, Span /// The indexed pixels. /// The color table containing the available colors. /// The - private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Span indices, Span colorTable, in GifImageDescriptor descriptor) + private void ReadFrameColors(ref Image image, ref ImageFrame previousFrame, Span indices, ReadOnlySpan colorTable, in GifImageDescriptor descriptor) where TPixel : struct, IPixel { ref byte indicesRef = ref MemoryMarshal.GetReference(indices); @@ -458,11 +453,8 @@ private void ReadFrameColors(ref Image image, ref ImageFrame Date: Wed, 9 May 2018 16:44:34 -0700 Subject: [PATCH 06/21] Remove ByteExtensions --- .../Common/Extensions/ByteExtensions.cs | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/ImageSharp/Common/Extensions/ByteExtensions.cs diff --git a/src/ImageSharp/Common/Extensions/ByteExtensions.cs b/src/ImageSharp/Common/Extensions/ByteExtensions.cs deleted file mode 100644 index ee41096cfe..0000000000 --- a/src/ImageSharp/Common/Extensions/ByteExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp -{ - /// - /// Extension methods for the struct buffers. - /// - internal static class ByteExtensions - { - /// - /// Returns a reference to the given position of the span unsafe casted to . - /// - /// The byte span. - /// The reference at the given offset. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref Rgb24 AsRgb24(this Span bytes) - { - return ref Unsafe.As(ref bytes[0]); - } - } -} \ No newline at end of file From bddc20a34349d0b4de9c75dd341d6bf472407c25 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:44:45 -0700 Subject: [PATCH 07/21] Simplfiy ToRgbaHex --- src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 184928d0e4..f5ebdb3fd7 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -76,7 +76,10 @@ public static TPixel FromRGBA(byte red, byte green, byte blue, byte alpha) /// private static string ToRgbaHex(string hex) { - hex = hex.StartsWith("#") ? hex.Substring(1) : hex; + if (hex[0] == '#') + { + hex = hex.Substring(1); + } if (hex.Length == 8) { From 5156890a8e03e066a68c873ba56629987ed27a5f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 9 May 2018 16:56:08 -0700 Subject: [PATCH 08/21] =?UTF-8?q?=F0=9F=91=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index b89c655c80..cc98b8450b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -948,7 +948,6 @@ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defi if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) { - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) From 00af2df38bc2ad69c585a6df3be8526ace218cb6 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 07:59:51 -0700 Subject: [PATCH 09/21] Rename Gaurd.NotNullOrEmpty to NotNullOrWhiteSpace to match behavior & cleanup messages. Also remove the unused message arguments. --- src/ImageSharp/Common/Helpers/Guard.cs | 67 ++++++++----------- src/ImageSharp/MetaData/ImageProperty.cs | 2 +- .../PixelFormats/ColorBuilder{TPixel}.cs | 2 +- 3 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 9f0a46f80c..603cf566f5 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -15,16 +15,15 @@ namespace SixLabors.ImageSharp internal static class Guard { /// - /// Verifies, that the method parameter with specified object value is not null - /// and throws an exception if it is found to be so. + /// Ensures that the value is not null. /// - /// The target object, which cannot be null. + /// The target object, which cannot be null. /// The name of the parameter that is to be checked. /// The error message, if any to add to the exception. - /// is null - public static void NotNull(object target, string parameterName, string message = "") + /// is null + public static void NotNull(object value, string parameterName, string message = "") { - if (target == null) + if (value == null) { if (!string.IsNullOrWhiteSpace(message)) { @@ -36,57 +35,49 @@ public static void NotNull(object target, string parameterName, string message = } /// - /// Verifies, that the string method parameter with specified object value and message - /// is not null, not empty and does not contain only blanks and throws an exception - /// if the object is null. + /// Ensures that the target value is not null, empty, or whitespace. /// - /// The target string, which should be checked against being null or empty. + /// The target string, which should be checked against being null or empty. /// Name of the parameter. - /// The error message, if any to add to the exception. - /// is null. - /// is empty or contains only blanks. - public static void NotNullOrEmpty(string target, string parameterName, string message = "") + /// is null. + /// is empty or contains only blanks. + public static void NotNullOrWhiteSpace(string value, string parameterName) { - NotNull(target, parameterName, message); - - if (string.IsNullOrWhiteSpace(target)) + if (value == null) { - if (!string.IsNullOrWhiteSpace(message)) - { - throw new ArgumentException(message, parameterName); - } + throw new ArgumentNullException(parameterName); + } - throw new ArgumentException("Value cannot be null or empty and cannot contain only blanks.", parameterName); + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Must not be empty or whitespace.", parameterName); } } /// - /// Verifies, that the enumeration is not null and not empty. + /// Ensures that the enumeration is not null or empty. /// - /// The type of objects in the - /// The target enumeration, which should be checked against being null or empty. + /// The type of objects in the + /// The target enumeration, which should be checked against being null or empty. /// Name of the parameter. /// The error message, if any to add to the exception. - /// is null. - /// is empty. - public static void NotNullOrEmpty(IEnumerable target, string parameterName, string message = "") + /// is null. + /// is empty. + public static void NotNullOrEmpty(IEnumerable value, string parameterName) { - NotNull(target, parameterName, message); - - if (!target.Any()) + if (value == null) { - if (!string.IsNullOrWhiteSpace(message)) - { - throw new ArgumentException(message, parameterName); - } + throw new ArgumentNullException(parameterName); + } - throw new ArgumentException("Value cannot be empty.", parameterName); + if (!value.Any()) + { + throw new ArgumentException("Must not be empty.", parameterName); } } /// - /// Verifies that the specified value is less than a maximum value - /// and throws an exception if it is not. + /// Ensures that the specified value is less than a maximum value. /// /// The target value, which should be validated. /// The maximum value. diff --git a/src/ImageSharp/MetaData/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs index c67c1f3cf9..3e0cccd422 100644 --- a/src/ImageSharp/MetaData/ImageProperty.cs +++ b/src/ImageSharp/MetaData/ImageProperty.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.MetaData /// The value of the property. public ImageProperty(string name, string value) { - Guard.NotNullOrEmpty(name, nameof(name)); + Guard.NotNullOrWhiteSpace(name, nameof(name)); this.Name = name; this.Value = value; diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index f5ebdb3fd7..1e7645aeb9 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -23,7 +23,7 @@ public static class ColorBuilder /// Returns a that represents the color defined by the provided RGBA heax string. public static TPixel FromHex(string hex) { - Guard.NotNullOrEmpty(hex, nameof(hex)); + Guard.NotNullOrWhiteSpace(hex, nameof(hex)); hex = ToRgbaHex(hex); uint packedValue; From eb318a3a88f1440f70350736f3a2f210a8f4405c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 08:09:10 -0700 Subject: [PATCH 10/21] Don't use Linq to check if IEnumerable is empty. --- src/ImageSharp/ImageFrameCollection.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 0318a7068d..cacad34a46 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -32,7 +32,7 @@ internal ImageFrameCollection(Image parent, int width, int height, TPixe internal ImageFrameCollection(Image parent, IEnumerable> frames) { Guard.NotNull(parent, nameof(parent)); - Guard.NotNullOrEmpty(frames, nameof(frames)); + Guard.NotNull(frames, nameof(frames)); this.parent = parent; @@ -42,6 +42,12 @@ internal ImageFrameCollection(Image parent, IEnumerable From fd766a525f2e5e5b864d55b7ae3b53a7f1fea59c Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 08:12:32 -0700 Subject: [PATCH 11/21] React to Gaurd changes --- src/ImageSharp/Common/Helpers/Guard.cs | 26 +++++--------------- src/ImageSharp/ImageExtensions.cs | 2 +- tests/ImageSharp.Tests/Helpers/GuardTests.cs | 12 ++++----- 3 files changed, 13 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 603cf566f5..9258beb368 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; namespace SixLabors.ImageSharp { @@ -19,17 +18,11 @@ internal static class Guard /// /// The target object, which cannot be null. /// The name of the parameter that is to be checked. - /// The error message, if any to add to the exception. /// is null - public static void NotNull(object value, string parameterName, string message = "") + public static void NotNull(object value, string parameterName) { if (value == null) { - if (!string.IsNullOrWhiteSpace(message)) - { - throw new ArgumentNullException(parameterName, message); - } - throw new ArgumentNullException(parameterName); } } @@ -60,17 +53,16 @@ public static void NotNullOrWhiteSpace(string value, string parameterName) /// The type of objects in the /// The target enumeration, which should be checked against being null or empty. /// Name of the parameter. - /// The error message, if any to add to the exception. /// is null. /// is empty. - public static void NotNullOrEmpty(IEnumerable value, string parameterName) + public static void NotNullOrEmpty(ICollection value, string parameterName) { if (value == null) { throw new ArgumentNullException(parameterName); } - if (!value.Any()) + if (value.Count == 0) { throw new ArgumentException("Must not be empty.", parameterName); } @@ -182,15 +174,9 @@ public static void MustBeBetweenOrEqualTo(TValue value, TValue min, TVal /// Verifies, that the method parameter with specified target value is true /// and throws an exception if it is found to be so. /// - /// - /// The target value, which cannot be false. - /// - /// - /// The name of the parameter that is to be checked. - /// - /// - /// The error message, if any to add to the exception. - /// + /// The target value, which cannot be false. + /// The name of the parameter that is to be checked. + /// The error message, if any to add to the exception. /// /// is false /// diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 2cdb71fc0e..75d947469b 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -30,7 +30,7 @@ public static partial class ImageExtensions public static void Save(this Image source, string filePath) where TPixel : struct, IPixel { - Guard.NotNullOrEmpty(filePath, nameof(filePath)); + Guard.NotNullOrWhiteSpace(filePath, nameof(filePath)); string ext = Path.GetExtension(filePath).Trim('.'); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); diff --git a/tests/ImageSharp.Tests/Helpers/GuardTests.cs b/tests/ImageSharp.Tests/Helpers/GuardTests.cs index 83075dc83e..42913e02d4 100644 --- a/tests/ImageSharp.Tests/Helpers/GuardTests.cs +++ b/tests/ImageSharp.Tests/Helpers/GuardTests.cs @@ -35,27 +35,27 @@ public void NotNullThrowsWhenArgNameEmpty() /// [Fact] [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1122:UseStringEmptyForEmptyStrings", Justification = "Reviewed. Suppression is OK here.")] - public void NotEmptyThrowsWhenEmpty() + public void NotEmptyOrWhiteSpaceThrowsWhenEmpty() { - Assert.Throws(() => Guard.NotNullOrEmpty("", string.Empty)); + Assert.Throws(() => Guard.NotNullOrWhiteSpace("", string.Empty)); } /// /// Tests that the method throws when the argument is whitespace. /// [Fact] - public void NotEmptyThrowsWhenWhitespace() + public void NotEmptyOrWhiteSpaceThrowsOnWhitespace() { - Assert.Throws(() => Guard.NotNullOrEmpty(" ", string.Empty)); + Assert.Throws(() => Guard.NotNullOrWhiteSpace(" ", string.Empty)); } /// /// Tests that the method throws when the argument name is null. /// [Fact] - public void NotEmptyThrowsWhenParameterNameNull() + public void NotEmptyOrWhiteSpaceThrowsWhenParameterNameNull() { - Assert.Throws(() => Guard.NotNullOrEmpty(null, null)); + Assert.Throws(() => Guard.NotNullOrWhiteSpace(null, null)); } /// From 017c7fb3b767255c1ed221934e6a8270fffb2f04 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 08:12:59 -0700 Subject: [PATCH 12/21] Verify ColorBuilder throws on null and empty --- .../PixelFormats/ColorBuilderTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs new file mode 100644 index 0000000000..6c139c2c09 --- /dev/null +++ b/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colors +{ + public class ColorBuilderTests + { + [Fact] + public void ParseHexLeadingPoundIsOptional() + { + Assert.Equal(new Rgb24(0, 128, 128), ColorBuilder.FromHex("#008080")); + Assert.Equal(new Rgb24(0, 128, 128), ColorBuilder.FromHex("008080")); + } + + [Fact] + public void ParseHexThrowsOnEmpty() + { + Assert.Throws(() => ColorBuilder.FromHex("")); + } + + [Fact] + public void ParseHexThrowsOnNull() + { + Assert.Throws(() => ColorBuilder.FromHex(null)); + } + } +} From fda2d1fc04ffa94aeaada4ef313b88bec6ca74a6 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 08:21:33 -0700 Subject: [PATCH 13/21] Optimize ColorBuilder --- .../PixelFormats/ColorBuilder{TPixel}.cs | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs index 1e7645aeb9..c2c0277f9e 100644 --- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.Globalization; namespace SixLabors.ImageSharp.PixelFormats @@ -26,18 +27,14 @@ public static TPixel FromHex(string hex) Guard.NotNullOrWhiteSpace(hex, nameof(hex)); hex = ToRgbaHex(hex); - uint packedValue; - if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out packedValue)) + + if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint packedValue)) { throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); } TPixel result = default; - var rgba = new Rgba32( - (byte)(packedValue >> 24), - (byte)(packedValue >> 16), - (byte)(packedValue >> 8), - (byte)(packedValue >> 0)); + var rgba = new Rgba32(BinaryPrimitives.ReverseEndianness(packedValue)); result.PackFromRgba32(rgba); return result; @@ -96,12 +93,12 @@ private static string ToRgbaHex(string hex) return null; } - string red = char.ToString(hex[0]); - string green = char.ToString(hex[1]); - string blue = char.ToString(hex[2]); - string alpha = hex.Length == 3 ? "F" : char.ToString(hex[3]); + char r = hex[0]; + char g = hex[1]; + char b = hex[2]; + char a = hex.Length == 3 ? 'F' : hex[3]; - return string.Concat(red, red, green, green, blue, blue, alpha, alpha); + return new string(new[] { r, r, g, g, b, b, a, a }); } } } \ No newline at end of file From 4f779ca1fceedb1eeeffc71653fbf52d0eb9dc78 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 08:24:56 -0700 Subject: [PATCH 14/21] Improve ColorBuilder test coverage --- tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs b/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs index 6c139c2c09..e56cac2794 100644 --- a/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/ColorBuilderTests.cs @@ -3,12 +3,21 @@ using System; using SixLabors.ImageSharp.PixelFormats; + using Xunit; namespace SixLabors.ImageSharp.Tests.Colors { public class ColorBuilderTests { + [Fact] + public void ParseShortHex() + { + Assert.Equal(new Rgb24(255, 255, 255), ColorBuilder.FromHex("#fff")); + Assert.Equal(new Rgb24(255, 255, 255), ColorBuilder.FromHex("fff")); + Assert.Equal(new Rgba32(0, 0, 0, 255), ColorBuilder.FromHex("000f")); + } + [Fact] public void ParseHexLeadingPoundIsOptional() { From 46e0a859e67a3e8ac912f9ccedbeaf7f52305f53 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 09:08:00 -0700 Subject: [PATCH 15/21] Allow leading period in FindFormatByFileExtension --- src/ImageSharp/Formats/ImageFormatManager.cs | 7 +++++++ src/ImageSharp/ImageExtensions.cs | 2 +- .../TestUtilities/TestEnvironment.Formats.cs | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index 67ba111474..4e33a0445c 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -85,6 +85,13 @@ public void AddImageFormat(IImageFormat format) /// The if found otherwise null public IImageFormat FindFormatByFileExtension(string extension) { + Guard.NotNullOrWhiteSpace(extension, nameof(extension)); + + if (extension[0] == '.') + { + extension = extension.Substring(1); + } + return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); } diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 75d947469b..9f9a7e57ac 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -32,7 +32,7 @@ public static void Save(this Image source, string filePath) { Guard.NotNullOrWhiteSpace(filePath, nameof(filePath)); - string ext = Path.GetExtension(filePath).Trim('.'); + string ext = Path.GetExtension(filePath); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); if (format == null) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index fa9497a8f8..6bebf3887b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -32,8 +32,8 @@ internal static IImageEncoder GetReferenceEncoder(string filePath) internal static IImageFormat GetImageFormat(string filePath) { - string extension = Path.GetExtension(filePath).ToLower(); - if (extension[0] == '.') extension = extension.Substring(1); + string extension = Path.GetExtension(filePath); + IImageFormat format = Configuration.ImageFormatsManager.FindFormatByFileExtension(extension); return format; } From 202e472dc4bf03879927fb46954c2bd5bc98f5b9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 13:47:50 -0700 Subject: [PATCH 16/21] Use ReadOnlySpans in LoadPixelData --- src/ImageSharp/Image.LoadPixelData.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index 5f85d61ba3..307660b5a5 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -33,7 +33,7 @@ public static Image LoadPixelData(TPixel[] data, int width, int /// The height of the final image. /// The pixel format. /// A new . - public static Image LoadPixelData(Span data, int width, int height) + public static Image LoadPixelData(ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(Configuration.Default, data, width, height); @@ -72,7 +72,7 @@ public static Image LoadPixelData(Span data, int width, in /// A new . public static Image LoadPixelData(Configuration config, byte[] data, int width, int height) where TPixel : struct, IPixel - => LoadPixelData(config, MemoryMarshal.Cast(data.AsSpan()), width, height); + => LoadPixelData(config, MemoryMarshal.Cast(new ReadOnlySpan(data)), width, height); /// /// Create a new instance of the class from the given byte array in format. @@ -83,7 +83,7 @@ public static Image LoadPixelData(Configuration config, byte[] d /// The height of the final image. /// The pixel format. /// A new . - public static Image LoadPixelData(Configuration config, Span data, int width, int height) + public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(config, MemoryMarshal.Cast(data), width, height); @@ -99,7 +99,7 @@ public static Image LoadPixelData(Configuration config, Span LoadPixelData(Configuration config, TPixel[] data, int width, int height) where TPixel : struct, IPixel { - return LoadPixelData(config, data.AsSpan(), width, height); + return LoadPixelData(config, new ReadOnlySpan(data), width, height); } /// @@ -111,7 +111,7 @@ public static Image LoadPixelData(Configuration config, TPixel[] /// The height of the final image. /// The pixel format. /// A new . - public static Image LoadPixelData(Configuration config, Span data, int width, int height) + public static Image LoadPixelData(Configuration config, ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel { int count = width * height; From 45e5d5bc512aa0f20e33054f5071dcbbf530fb50 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 10 May 2018 13:48:16 -0700 Subject: [PATCH 17/21] Allow pixel data to be saved directly to a span --- src/ImageSharp/ImageExtensions.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 9f9a7e57ac..192287ba56 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -4,13 +4,11 @@ using System; using System.Collections.Generic; using System.IO; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Primitives; namespace SixLabors.ImageSharp { @@ -198,24 +196,24 @@ public static string ToBase64String(this Image source, IImageFor } /// - /// Saves the raw image to the given bytes. + /// Saves the raw image to the given byte buffer. /// /// The Pixel format. /// The source image /// The buffer to save the raw pixel data to. /// Thrown if the stream is null. - internal static void SavePixelData(this Image source, Span buffer) + public static void SavePixelData(this Image source, Span buffer) where TPixel : struct, IPixel => source.Frames.RootFrame.SavePixelData(MemoryMarshal.Cast(buffer)); /// - /// Saves the raw image to the given bytes. + /// Saves the raw image to the given byte buffer. /// /// The Pixel format. /// The source image /// The buffer to save the raw pixel data to. /// Thrown if the stream is null. - internal static void SavePixelData(this ImageFrame source, Span buffer) + public static void SavePixelData(this ImageFrame source, Span buffer) where TPixel : struct, IPixel { Span sourceBuffer = source.GetPixelSpan(); @@ -224,4 +222,4 @@ internal static void SavePixelData(this ImageFrame source, Span< sourceBuffer.CopyTo(buffer); } } -} +} \ No newline at end of file From a05b61835f7390ac647960575b2a93fd29fe4932 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 11 May 2018 10:31:17 -0700 Subject: [PATCH 18/21] Update Span ->ReadOnlySpan --- src/ImageSharp/Image.LoadPixelData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Image.LoadPixelData.cs b/src/ImageSharp/Image.LoadPixelData.cs index 307660b5a5..282f980865 100644 --- a/src/ImageSharp/Image.LoadPixelData.cs +++ b/src/ImageSharp/Image.LoadPixelData.cs @@ -57,7 +57,7 @@ public static Image LoadPixelData(byte[] data, int width, int he /// The height of the final image. /// The pixel format. /// A new . - public static Image LoadPixelData(Span data, int width, int height) + public static Image LoadPixelData(ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(Configuration.Default, data, width, height); From 92f353b1ac3ab382105d8298b35be1d4a3272813 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 11 May 2018 10:31:47 -0700 Subject: [PATCH 19/21] Tidy up ImageExtension docs --- src/ImageSharp/ImageExtensions.cs | 78 +++++++++++++++---------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index 192287ba56..d8cda2f8fc 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -19,10 +19,10 @@ public static partial class ImageExtensions { #if !NETSTANDARD1_1 /// - /// Saves the image to the given stream using the currently loaded image format. + /// Writes the image to the given stream using the currently loaded image format. /// - /// The Pixel format. - /// The source image + /// The pixel format. + /// The source image. /// The file path to save the image to. /// Thrown if the stream is null. public static void Save(this Image source, string filePath) @@ -62,13 +62,13 @@ public static void Save(this Image source, string filePath) } /// - /// Saves the image to the given stream using the currently loaded image format. + /// Writes the image to the given stream using the currently loaded image format. /// - /// The Pixel format. - /// The source image + /// The pixel format. + /// The source image. /// The file path to save the image to. /// The encoder to save the image with. - /// Thrown if the encoder is null. + /// Thrown if the encoder is null. public static void Save(this Image source, string filePath, IImageEncoder encoder) where TPixel : struct, IPixel { @@ -81,13 +81,13 @@ public static void Save(this Image source, string filePath, IIma #endif /// - /// Saves the image to the given stream using the currently loaded image format. + /// Writes the image to the given stream using the currently loaded image format. /// /// The Pixel format. - /// The source image + /// The source image. /// The stream to save the image to. - /// The format to save the image to. - /// Thrown if the stream is null. + /// The format to save the image in. + /// Thrown if the stream is null. public static void Save(this Image source, Stream stream, IImageFormat format) where TPixel : struct, IPixel { @@ -111,67 +111,67 @@ public static void Save(this Image source, Stream stream, IImage } /// - /// Saves the raw image pixels to a byte array in row-major order. + /// Returns the a copy of the image pixels as a byte array in row-major order. /// - /// The Pixel format. + /// The pixel format. /// The source image /// A copy of the pixel data as bytes from this frame. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static byte[] SavePixelData(this ImageFrame source) where TPixel : struct, IPixel => MemoryMarshal.AsBytes(source.GetPixelSpan()).ToArray(); /// - /// Saves the raw image pixels to the given byte array in row-major order. + /// Writes the raw image pixels to the given byte array in row-major order. /// - /// The Pixel format. - /// The source image + /// The pixel format. + /// The source image. /// The buffer to save the raw pixel data to. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static void SavePixelData(this ImageFrame source, byte[] buffer) where TPixel : struct, IPixel => SavePixelData(source, MemoryMarshal.Cast(buffer.AsSpan())); /// - /// Saves the raw image pixels to the given TPixel array in row-major order. + /// Writes the raw image pixels to the given TPixel array in row-major order. /// - /// The Pixel format. + /// The pixel format. /// The source image /// The buffer to save the raw pixel data to. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static void SavePixelData(this ImageFrame source, TPixel[] buffer) where TPixel : struct, IPixel => SavePixelData(source, buffer.AsSpan()); /// - /// Saves the raw image pixels to a byte array in row-major order. + /// Returns a copy of the raw image pixels as a byte array in row-major order. /// - /// The Pixel format. - /// The source image + /// The pixel format. + /// The source image. /// A copy of the pixel data from the first frame as bytes. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static byte[] SavePixelData(this Image source) where TPixel : struct, IPixel => source.Frames.RootFrame.SavePixelData(); /// - /// Saves the raw image pixels to the given byte array in row-major order. + /// Writes the raw image pixels to the given byte array in row-major order. /// - /// The Pixel format. - /// The source image + /// The pixel format. + /// The source image. /// The buffer to save the raw pixel data to. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static void SavePixelData(this Image source, byte[] buffer) where TPixel : struct, IPixel => source.Frames.RootFrame.SavePixelData(buffer); /// - /// Saves the raw image pixels to the given TPixel array in row-major order. + /// Writes the raw image pixels to the given TPixel array in row-major order. /// - /// The Pixel format. + /// The pixel format. /// The source image /// The buffer to save the raw pixel data to. - /// Thrown if the stream is null. + /// Thrown if the stream is null. public static void SavePixelData(this Image source, TPixel[] buffer) where TPixel : struct, IPixel => source.Frames.RootFrame.SavePixelData(buffer); @@ -180,7 +180,7 @@ public static void SavePixelData(this Image source, TPixel[] buf /// Returns a Base64 encoded string from the given image. /// /// - /// The Pixel format. + /// The pixel format. /// The source image /// The format. /// The @@ -196,22 +196,22 @@ public static string ToBase64String(this Image source, IImageFor } /// - /// Saves the raw image to the given byte buffer. + /// Writes the raw image bytes to the given byte span. /// - /// The Pixel format. + /// The pixel format. /// The source image - /// The buffer to save the raw pixel data to. + /// The span to save the raw pixel data to. /// Thrown if the stream is null. public static void SavePixelData(this Image source, Span buffer) where TPixel : struct, IPixel => source.Frames.RootFrame.SavePixelData(MemoryMarshal.Cast(buffer)); /// - /// Saves the raw image to the given byte buffer. + /// Writes the raw image pixels to the given TPixel span. /// - /// The Pixel format. + /// The pixel format. /// The source image - /// The buffer to save the raw pixel data to. + /// The span to save the raw pixel data to. /// Thrown if the stream is null. public static void SavePixelData(this ImageFrame source, Span buffer) where TPixel : struct, IPixel From 1695b593d4239595a96ca9b2254b46992bec738b Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 11 May 2018 10:32:42 -0700 Subject: [PATCH 20/21] Update three more spans to ReadOnly --- src/ImageSharp/Formats/Png/Filters/NoneFilter.cs | 2 +- src/ImageSharp/ImageFrame.LoadPixelData.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs index 0164ceafaa..14af8ca6a0 100644 --- a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs @@ -20,7 +20,7 @@ internal static class NoneFilter /// The scanline to encode /// The filtered scanline result. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Encode(Span scanline, Span result) + public static void Encode(ReadOnlySpan scanline, Span result) { // Insert a byte before the data. result[0] = 0; diff --git a/src/ImageSharp/ImageFrame.LoadPixelData.cs b/src/ImageSharp/ImageFrame.LoadPixelData.cs index 1306c28367..4639a104b1 100644 --- a/src/ImageSharp/ImageFrame.LoadPixelData.cs +++ b/src/ImageSharp/ImageFrame.LoadPixelData.cs @@ -23,7 +23,7 @@ internal static partial class ImageFrame /// The height of the final image. /// The pixel format. /// A new . - public static ImageFrame LoadPixelData(MemoryManager memoryManager, Span data, int width, int height) + public static ImageFrame LoadPixelData(MemoryManager memoryManager, ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel => LoadPixelData(memoryManager, MemoryMarshal.Cast(data), width, height); @@ -36,7 +36,7 @@ public static ImageFrame LoadPixelData(MemoryManager memoryManag /// The height of the final image. /// The pixel format. /// A new . - public static ImageFrame LoadPixelData(MemoryManager memoryManager, Span data, int width, int height) + public static ImageFrame LoadPixelData(MemoryManager memoryManager, ReadOnlySpan data, int width, int height) where TPixel : struct, IPixel { int count = width * height; From 93c44f4200b0cf2b6b480f09d56fce47bb8ad64a Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Fri, 11 May 2018 10:37:29 -0700 Subject: [PATCH 21/21] React to LoadPixelData change --- src/ImageSharp/ImageFrameCollection.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index cacad34a46..be15a6527c 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -117,7 +117,7 @@ public ImageFrame AddFrame(TPixel[] source) var frame = ImageFrame.LoadPixelData( this.parent.GetMemoryManager(), - new Span(source), + new ReadOnlySpan(source), this.RootFrame.Width, this.RootFrame.Height); this.frames.Add(frame);