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)
{