Browse Source

removed bytesPerScanline parameters, added param checking

pull/212/head
Anton Firszov 9 years ago
parent
commit
8a3eb63eb7
  1. 38
      src/ImageSharp/Common/Helpers/Guard.cs
  2. 17
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  3. 15
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  4. 12
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  5. 15
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  6. 25
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  7. 20
      src/ImageSharp/Formats/Png/PngEncoderCore.cs

38
src/ImageSharp/Common/Helpers/Guard.cs

@ -230,5 +230,43 @@ namespace ImageSharp
throw new ArgumentException(message, parameterName);
}
}
/// <summary>
/// Verifies, that the target span is of same size than the 'other' span.
/// </summary>
/// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="target">The target span.</param>
/// <param name="other">The 'other' span to compare 'target' to.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
public static void MustBeSameSized<T>(BufferSpan<T> target, BufferSpan<T> other, string parameterName)
where T : struct
{
if (target.Length != other.Length)
{
throw new ArgumentException("Span-s must be the same size!", parameterName);
}
}
/// <summary>
/// Verifies, that the `target` span has the length of 'minSpan', or longer.
/// </summary>
/// <typeparam name="T">The element type of the spans</typeparam>
/// <param name="target">The target span.</param>
/// <param name="minSpan">The 'minSpan' span to compare 'target' to.</param>
/// <param name="parameterName">The name of the parameter that is to be checked.</param>
/// <exception cref="ArgumentException">
/// <paramref name="target"/> is true
/// </exception>
public static void MustBeSizedAtLeast<T>(BufferSpan<T> target, BufferSpan<T> 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);
}
}
}
}

17
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -12,23 +12,24 @@ namespace ImageSharp.Formats
/// the value of a pixel.
/// <see href="https://www.w3.org/TR/PNG-Filters.html"/>
/// </summary>
internal static unsafe class AverageFilter
internal static class AverageFilter
{
/// <summary>
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> 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
/// <param name="scanline">The scanline to encode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result, int bytesPerScanline, int bytesPerPixel)
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> 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)
{

15
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -20,16 +20,17 @@ namespace ImageSharp.Formats
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> 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
/// <param name="scanline">The scanline to encode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result, int bytesPerScanline, int bytesPerPixel)
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> 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)
{

12
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -18,15 +18,14 @@ namespace ImageSharp.Formats
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, int bytesPerScanline, int bytesPerPixel)
public static void Decode(BufferSpan<byte> 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
/// </summary>
/// <param name="scanline">The scanline to encode</param>
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> result, int bytesPerScanline, int bytesPerPixel)
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> 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)
{

15
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -19,15 +19,16 @@ namespace ImageSharp.Formats
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, int bytesPerScanline)
public static void Decode(BufferSpan<byte> scanline, BufferSpan<byte> 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
/// <param name="scanline">The scanline to encode</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="result">The filtered scanline result.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> result, int bytesPerScanline)
public static void Encode(BufferSpan<byte> scanline, BufferSpan<byte> previousScanline, BufferSpan<byte> 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);

25
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -430,10 +430,7 @@ namespace ImageSharp.Formats
}
this.currentRowBytesRead = 0;
BufferSpan<byte> scanSpan = this.scanline.Span;
BufferSpan<byte> 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<byte> scanSpan = this.scanline.Span;
BufferSpan<byte> prevSpan = this.previousScanline.Span;
BufferSpan<byte> scanSpan = this.scanline.Slice(0, bytesPerInterlaceScanline);
BufferSpan<byte> 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:

20
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<byte> 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<byte> actualResult = this.up;
BufferSpan<byte> 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<byte> 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<byte> 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)
{

Loading…
Cancel
Save