From 8a3eb63eb7b06dec667a879b5aef915271bab204 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 11 May 2017 02:53:04 +0200 Subject: [PATCH] removed bytesPerScanline parameters, added param checking --- src/ImageSharp/Common/Helpers/Guard.cs | 38 +++++++++++++++++++ .../Formats/Png/Filters/AverageFilter.cs | 17 +++++---- .../Formats/Png/Filters/PaethFilter.cs | 15 +++++--- .../Formats/Png/Filters/SubFilter.cs | 12 +++--- .../Formats/Png/Filters/UpFilter.cs | 15 +++++--- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 25 ++++++------ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 20 ++++------ 7 files changed, 91 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index cf307e936..41a715af9 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -230,5 +230,43 @@ namespace ImageSharp throw new ArgumentException(message, parameterName); } } + + /// + /// Verifies, that the target span is of same size than the 'other' span. + /// + /// The element type of the spans + /// The target span. + /// The 'other' span to compare 'target' to. + /// The name of the parameter that is to be checked. + /// + /// is true + /// + public static void MustBeSameSized(BufferSpan target, BufferSpan other, string parameterName) + where T : struct + { + if (target.Length != other.Length) + { + throw new ArgumentException("Span-s must be the same size!", parameterName); + } + } + + /// + /// Verifies, that the `target` span has the length of 'minSpan', or longer. + /// + /// The element type of the spans + /// The target span. + /// The 'minSpan' span to compare 'target' to. + /// The name of the parameter that is to be checked. + /// + /// is true + /// + public static void MustBeSizedAtLeast(BufferSpan target, BufferSpan minSpan, string parameterName) + where T : struct + { + if (target.Length < minSpan.Length) + { + throw new ArgumentException($"Span-s must be at least of length {minSpan.Length}!", parameterName); + } + } } } diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index fcfe698ba..80bcb653a 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -12,23 +12,24 @@ namespace ImageSharp.Formats /// the value of a pixel. /// /// - internal static unsafe class AverageFilter + internal static class AverageFilter { /// /// Decodes the scanline /// /// The scanline to decode /// The previous scanline. - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Decode(BufferSpan scanline, BufferSpan previousScanline, int bytesPerScanline, int bytesPerPixel) + public static void Decode(BufferSpan scanline, BufferSpan previousScanline, int bytesPerPixel) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); // Average(x) + floor((Raw(x-bpp)+Prior(x))/2) - for (int x = 1; x < bytesPerScanline; x++) + for (int x = 1; x < scanline.Length; x++) { if (x - bytesPerPixel < 1) { @@ -52,11 +53,13 @@ namespace ImageSharp.Formats /// The scanline to encode /// The previous scanline. /// The filtered scanline result. - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result, int bytesPerScanline, int bytesPerPixel) + public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result, int bytesPerPixel) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + Guard.MustBeSizedAtLeast(result, scanline, nameof(result)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); ref byte resultBaseRef = ref result.DangerousGetPinnableReference(); @@ -64,7 +67,7 @@ namespace ImageSharp.Formats // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) resultBaseRef = 3; - for (int x = 0; x < bytesPerScanline; x++) + for (int x = 0; x < scanline.Length; x++) { if (x - bytesPerPixel < 0) { diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index b7b3e8123..9f21f0759 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -20,16 +20,17 @@ namespace ImageSharp.Formats /// /// The scanline to decode /// The previous scanline. - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Decode(BufferSpan scanline, BufferSpan previousScanline, int bytesPerScanline, int bytesPerPixel) + public static void Decode(BufferSpan scanline, BufferSpan previousScanline, int bytesPerPixel) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) - for (int x = 1; x < bytesPerScanline; x++) + for (int x = 1; x < scanline.Length; x++) { if (x - bytesPerPixel < 1) { @@ -54,11 +55,13 @@ namespace ImageSharp.Formats /// The scanline to encode /// The previous scanline. /// The filtered scanline result. - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result, int bytesPerScanline, int bytesPerPixel) + public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result, int bytesPerPixel) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + Guard.MustBeSizedAtLeast(result, scanline, nameof(result)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); ref byte resultBaseRef = ref result.DangerousGetPinnableReference(); @@ -66,7 +69,7 @@ namespace ImageSharp.Formats // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) resultBaseRef = 4; - for (int x = 0; x < bytesPerScanline; x++) + for (int x = 0; x < scanline.Length; x++) { if (x - bytesPerPixel < 0) { diff --git a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs index 6c88f385e..3a5396cb3 100644 --- a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs @@ -18,15 +18,14 @@ namespace ImageSharp.Formats /// Decodes the scanline /// /// The scanline to decode - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Decode(BufferSpan scanline, int bytesPerScanline, int bytesPerPixel) + public static void Decode(BufferSpan scanline, int bytesPerPixel) { ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); // Sub(x) + Raw(x-bpp) - for (int x = 1; x < bytesPerScanline; x++) + for (int x = 1; x < scanline.Length; x++) { if (x - bytesPerPixel < 1) { @@ -47,18 +46,19 @@ namespace ImageSharp.Formats /// /// The scanline to encode /// The filtered scanline result. - /// The number of bytes per scanline /// The bytes per pixel. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Encode(BufferSpan scanline, BufferSpan result, int bytesPerScanline, int bytesPerPixel) + public static void Encode(BufferSpan scanline, BufferSpan result, int bytesPerPixel) { + Guard.MustBeSizedAtLeast(result, scanline, nameof(result)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte resultBaseRef = ref result.DangerousGetPinnableReference(); // Sub(x) = Raw(x) - Raw(x-bpp) resultBaseRef = 1; - for (int x = 0; x < bytesPerScanline; x++) + for (int x = 0; x < scanline.Length; x++) { if (x - bytesPerPixel < 0) { diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs index c1969e8cb..b30c49c45 100644 --- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs @@ -19,15 +19,16 @@ namespace ImageSharp.Formats /// /// The scanline to decode /// The previous scanline. - /// The number of bytes per scanline [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Decode(BufferSpan scanline, BufferSpan previousScanline, int bytesPerScanline) + public static void Decode(BufferSpan scanline, BufferSpan previousScanline) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); // Up(x) + Prior(x) - for (int x = 1; x < bytesPerScanline; x++) + for (int x = 1; x < scanline.Length; x++) { ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x); @@ -41,10 +42,12 @@ namespace ImageSharp.Formats /// The scanline to encode /// The previous scanline. /// The filtered scanline result. - /// The number of bytes per scanline [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result, int bytesPerScanline) + public static void Encode(BufferSpan scanline, BufferSpan previousScanline, BufferSpan result) { + Guard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); + Guard.MustBeSizedAtLeast(result, scanline, nameof(result)); + ref byte scanBaseRef = ref scanline.DangerousGetPinnableReference(); ref byte prevBaseRef = ref previousScanline.DangerousGetPinnableReference(); ref byte resultBaseRef = ref result.DangerousGetPinnableReference(); @@ -52,7 +55,7 @@ namespace ImageSharp.Formats // Up(x) = Raw(x) - Prior(x) resultBaseRef = 2; - for (int x = 0; x < bytesPerScanline; x++) + for (int x = 0; x < scanline.Length; x++) { byte scan = Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x); diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 8153d61bb..13b4c1167 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -430,10 +430,7 @@ namespace ImageSharp.Formats } this.currentRowBytesRead = 0; - - BufferSpan scanSpan = this.scanline.Span; - BufferSpan prevSpan = this.previousScanline.Span; - var filterType = (FilterType)scanSpan[0]; + var filterType = (FilterType)this.scanline[0]; switch (filterType) { @@ -442,22 +439,22 @@ namespace ImageSharp.Formats case FilterType.Sub: - SubFilter.Decode(scanSpan, this.bytesPerScanline, this.bytesPerPixel); + SubFilter.Decode(this.scanline, this.bytesPerPixel); break; case FilterType.Up: - UpFilter.Decode(scanSpan, prevSpan, this.bytesPerScanline); + UpFilter.Decode(this.scanline, this.previousScanline); break; case FilterType.Average: - AverageFilter.Decode(scanSpan, prevSpan, this.bytesPerScanline, this.bytesPerPixel); + AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel); break; case FilterType.Paeth: - PaethFilter.Decode(scanSpan, prevSpan, this.bytesPerScanline, this.bytesPerPixel); + PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerPixel); break; default: @@ -506,8 +503,8 @@ namespace ImageSharp.Formats this.currentRowBytesRead = 0; - BufferSpan scanSpan = this.scanline.Span; - BufferSpan prevSpan = this.previousScanline.Span; + BufferSpan scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline); + BufferSpan prevSpan = this.previousScanline.Span.Slice(0, bytesPerInterlaceScanline); var filterType = (FilterType)scanSpan[0]; switch (filterType) @@ -517,22 +514,22 @@ namespace ImageSharp.Formats case FilterType.Sub: - SubFilter.Decode(scanSpan, bytesPerInterlaceScanline, this.bytesPerPixel); + SubFilter.Decode(scanSpan, this.bytesPerPixel); break; case FilterType.Up: - UpFilter.Decode(scanSpan, prevSpan, bytesPerInterlaceScanline); + UpFilter.Decode(scanSpan, prevSpan); break; case FilterType.Average: - AverageFilter.Decode(scanSpan, prevSpan, bytesPerInterlaceScanline, this.bytesPerPixel); + AverageFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; case FilterType.Paeth: - PaethFilter.Decode(scanSpan, prevSpan, bytesPerInterlaceScanline, this.bytesPerPixel); + PaethFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; default: diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index e7ec7d243..44f1513ee 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -399,16 +399,14 @@ namespace ImageSharp.Formats // This order, while different to the enumerated order is more likely to produce a smaller sum // early on which shaves a couple of milliseconds off the processing time. - BufferSpan upSpan = this.up.Span; - UpFilter.Encode(scanSpan, prevSpan, upSpan, this.bytesPerScanline); + UpFilter.Encode(scanSpan, prevSpan, this.up); - int currentSum = this.CalculateTotalVariation(upSpan, int.MaxValue); + int currentSum = this.CalculateTotalVariation(this.up, int.MaxValue); int lowestSum = currentSum; Buffer actualResult = this.up; - BufferSpan paethSpan = this.paeth.Span; - PaethFilter.Encode(scanSpan, prevSpan, paethSpan, this.bytesPerScanline, this.bytesPerPixel); - currentSum = this.CalculateTotalVariation(paethSpan, currentSum); + PaethFilter.Encode(scanSpan, prevSpan, this.paeth, this.bytesPerPixel); + currentSum = this.CalculateTotalVariation(this.paeth, currentSum); if (currentSum < lowestSum) { @@ -416,9 +414,8 @@ namespace ImageSharp.Formats actualResult = this.paeth; } - BufferSpan subSpan = this.sub.Span; - SubFilter.Encode(scanSpan, subSpan, this.bytesPerScanline, this.bytesPerPixel); - currentSum = this.CalculateTotalVariation(subSpan, int.MaxValue); + SubFilter.Encode(scanSpan, this.sub, this.bytesPerPixel); + currentSum = this.CalculateTotalVariation(this.sub, int.MaxValue); if (currentSum < lowestSum) { @@ -426,9 +423,8 @@ namespace ImageSharp.Formats actualResult = this.sub; } - BufferSpan averageSpan = this.average.Span; - AverageFilter.Encode(scanSpan, prevSpan, averageSpan, this.bytesPerScanline, this.bytesPerPixel); - currentSum = this.CalculateTotalVariation(averageSpan, currentSum); + AverageFilter.Encode(scanSpan, prevSpan, this.average, this.bytesPerPixel); + currentSum = this.CalculateTotalVariation(this.average, currentSum); if (currentSum < lowestSum) {