Browse Source

Use Unsafe.Add + Bufferspan for Png decode filters

af/merge-core
James Jackson-South 9 years ago
parent
commit
9b4bc472a1
  1. 21
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  2. 12
      src/ImageSharp/Formats/Png/Filters/NoneFilter.cs
  3. 26
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  4. 16
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  5. 14
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  6. 58
      src/ImageSharp/Formats/Png/PngDecoderCore.cs

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

@ -22,18 +22,23 @@ namespace ImageSharp.Formats
/// <param name="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param> /// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) public static void Decode(ref byte scanline, ref byte previousScanline, int bytesPerScanline, int bytesPerPixel)
{ {
// Average(x) + floor((Raw(x-bpp)+Prior(x))/2) // Average(x) + floor((Raw(x-bpp)+Prior(x))/2)
fixed (byte* scan = scanline) for (int x = 1; x < bytesPerScanline; x++)
fixed (byte* prev = previousScanline)
{ {
for (int x = 1; x < bytesPerScanline; x++) if (x - bytesPerPixel < 1)
{ {
byte left = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel]; ref byte scan = ref Unsafe.Add(ref scanline, x);
byte above = prev[x]; ref byte above = ref Unsafe.Add(ref previousScanline, x);
scan = (byte)((scan + (above >> 1)) % 256);
scan[x] = (byte)((scan[x] + Average(left, above)) % 256); }
else
{
ref byte scan = ref Unsafe.Add(ref scanline, x);
ref byte left = ref Unsafe.Add(ref scanline, x - bytesPerPixel);
ref byte above = ref Unsafe.Add(ref previousScanline, x);
scan = (byte)((scan + Average(left, above)) % 256);
} }
} }
} }

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

@ -15,18 +15,6 @@ namespace ImageSharp.Formats
/// </summary> /// </summary>
internal static class NoneFilter internal static class NoneFilter
{ {
/// <summary>
/// Decodes the scanline
/// </summary>
/// <param name="scanline">The scanline to decode</param>
/// <returns>The <see cref="T:byte[]"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte[] Decode(byte[] scanline)
{
// No change required.
return scanline;
}
/// <summary> /// <summary>
/// Encodes the scanline /// Encodes the scanline
/// </summary> /// </summary>

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

@ -5,7 +5,6 @@
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
/// <summary> /// <summary>
@ -24,19 +23,24 @@ namespace ImageSharp.Formats
/// <param name="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param> /// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) public static void Decode(ref byte scanline, ref byte previousScanline, int bytesPerScanline, int bytesPerPixel)
{ {
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
fixed (byte* scan = scanline) for (int x = 1; x < bytesPerScanline; x++)
fixed (byte* prev = previousScanline)
{ {
for (int x = 1; x < bytesPerScanline; x++) if (x - bytesPerPixel < 1)
{ {
byte left = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel]; ref byte scan = ref Unsafe.Add(ref scanline, x);
byte above = prev[x]; ref byte above = ref Unsafe.Add(ref previousScanline, x);
byte upperLeft = (x - bytesPerPixel < 1) ? (byte)0 : prev[x - bytesPerPixel]; scan = (byte)((scan + PaethPredicator(0, above, 0)) % 256);
}
scan[x] = (byte)((scan[x] + PaethPredicator(left, above, upperLeft)) % 256); else
{
ref byte scan = ref Unsafe.Add(ref scanline, x);
ref byte left = ref Unsafe.Add(ref scanline, x - bytesPerPixel);
ref byte above = ref Unsafe.Add(ref previousScanline, x);
ref byte upperLeft = ref Unsafe.Add(ref previousScanline, x - bytesPerPixel);
scan = (byte)((scan + PaethPredicator(left, above, upperLeft)) % 256);
} }
} }
} }
@ -100,4 +104,4 @@ namespace ImageSharp.Formats
return upperLeft; return upperLeft;
} }
} }
} }

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

@ -21,15 +21,21 @@ namespace ImageSharp.Formats
/// <param name="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param>
/// <param name="bytesPerPixel">The bytes per pixel.</param> /// <param name="bytesPerPixel">The bytes per pixel.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, int bytesPerScanline, int bytesPerPixel) public static void Decode(ref byte scanline, int bytesPerScanline, int bytesPerPixel)
{ {
// Sub(x) + Raw(x-bpp) // Sub(x) + Raw(x-bpp)
fixed (byte* scan = scanline) for (int x = 1; x < bytesPerScanline; x++)
{ {
for (int x = 1; x < bytesPerScanline; x++) if (x - bytesPerPixel < 1)
{
ref byte scan = ref Unsafe.Add(ref scanline, x);
scan = (byte)(scan % 256);
}
else
{ {
byte priorRawByte = (x - bytesPerPixel < 1) ? (byte)0 : scan[x - bytesPerPixel]; ref byte scan = ref Unsafe.Add(ref scanline, x);
scan[x] = (byte)((scan[x] + priorRawByte) % 256); ref byte prev = ref Unsafe.Add(ref scanline, x - bytesPerPixel);
scan = (byte)((scan + prev) % 256);
} }
} }
} }

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

@ -21,18 +21,14 @@ namespace ImageSharp.Formats
/// <param name="previousScanline">The previous scanline.</param> /// <param name="previousScanline">The previous scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline</param> /// <param name="bytesPerScanline">The number of bytes per scanline</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Decode(byte[] scanline, byte[] previousScanline, int bytesPerScanline) public static void Decode(ref byte scanline, ref byte previousScanline, int bytesPerScanline)
{ {
// Up(x) + Prior(x) // Up(x) + Prior(x)
fixed (byte* scan = scanline) for (int x = 1; x < bytesPerScanline; x++)
fixed (byte* prev = previousScanline)
{ {
for (int x = 1; x < bytesPerScanline; x++) ref byte scan = ref Unsafe.Add(ref scanline, x);
{ ref byte above = ref Unsafe.Add(ref previousScanline, x);
byte above = prev[x]; scan = (byte)((scan + above) % 256);
scan[x] = (byte)((scan[x] + above) % 256);
}
} }
} }

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

@ -184,14 +184,14 @@ namespace ImageSharp.Formats
public Image<TPixel> Decode<TPixel>(Stream stream) public Image<TPixel> Decode<TPixel>(Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
ImageMetaData metadata = new ImageMetaData(); var metadata = new ImageMetaData();
this.currentStream = stream; this.currentStream = stream;
this.currentStream.Skip(8); this.currentStream.Skip(8);
Image<TPixel> image = null; Image<TPixel> image = null;
PixelAccessor<TPixel> pixels = null; PixelAccessor<TPixel> pixels = null;
try try
{ {
using (ZlibInflateStream deframeStream = new ZlibInflateStream(this.currentStream)) using (var deframeStream = new ZlibInflateStream(this.currentStream))
{ {
PngChunk currentChunk; PngChunk currentChunk;
while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null) while (!this.isEndChunkReached && (currentChunk = this.ReadChunk()) != null)
@ -437,38 +437,36 @@ namespace ImageSharp.Formats
} }
this.currentRowBytesRead = 0; this.currentRowBytesRead = 0;
FilterType filterType = (FilterType)this.scanline[0];
var filterType = (FilterType)this.scanline[0];
var scanBuffer = new BufferSpan<byte>(this.scanline);
ref byte scanPoint = ref scanBuffer.DangerousGetPinnableReference();
var prevBuffer = new BufferSpan<byte>(this.previousScanline);
ref byte prevPoint = ref prevBuffer.DangerousGetPinnableReference();
switch (filterType) switch (filterType)
{ {
case FilterType.None: case FilterType.None:
NoneFilter.Decode(this.scanline);
break; break;
case FilterType.Sub: case FilterType.Sub:
SubFilter.Decode(this.scanline, this.bytesPerScanline, this.bytesPerPixel); SubFilter.Decode(ref scanPoint, this.bytesPerScanline, this.bytesPerPixel);
break; break;
case FilterType.Up: case FilterType.Up:
UpFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline); UpFilter.Decode(ref scanPoint, ref prevPoint, this.bytesPerScanline);
break; break;
case FilterType.Average: case FilterType.Average:
AverageFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel); AverageFilter.Decode(ref scanPoint, ref prevPoint, this.bytesPerScanline, this.bytesPerPixel);
break; break;
case FilterType.Paeth: case FilterType.Paeth:
PaethFilter.Decode(this.scanline, this.previousScanline, this.bytesPerScanline, this.bytesPerPixel); PaethFilter.Decode(ref scanPoint, ref prevPoint, this.bytesPerScanline, this.bytesPerPixel);
break; break;
default: default:
@ -517,38 +515,35 @@ namespace ImageSharp.Formats
this.currentRowBytesRead = 0; this.currentRowBytesRead = 0;
FilterType filterType = (FilterType)this.scanline[0]; var filterType = (FilterType)this.scanline[0];
var scanBuffer = new BufferSpan<byte>(this.scanline);
ref byte scanPointer = ref scanBuffer.DangerousGetPinnableReference();
var prevBuffer = new BufferSpan<byte>(this.previousScanline);
ref byte prevPointer = ref prevBuffer.DangerousGetPinnableReference();
switch (filterType) switch (filterType)
{ {
case FilterType.None: case FilterType.None:
NoneFilter.Decode(this.scanline);
break; break;
case FilterType.Sub: case FilterType.Sub:
SubFilter.Decode(this.scanline, bytesPerInterlaceScanline, this.bytesPerPixel); SubFilter.Decode(ref scanPointer, bytesPerInterlaceScanline, this.bytesPerPixel);
break; break;
case FilterType.Up: case FilterType.Up:
UpFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline); UpFilter.Decode(ref scanPointer, ref prevPointer, bytesPerInterlaceScanline);
break; break;
case FilterType.Average: case FilterType.Average:
AverageFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline, this.bytesPerPixel); AverageFilter.Decode(ref scanPointer, ref prevPointer, bytesPerInterlaceScanline, this.bytesPerPixel);
break; break;
case FilterType.Paeth: case FilterType.Paeth:
PaethFilter.Decode(this.scanline, this.previousScanline, bytesPerInterlaceScanline, this.bytesPerPixel); PaethFilter.Decode(ref scanPointer, ref prevPointer, bytesPerInterlaceScanline, this.bytesPerPixel);
break; break;
default: default:
@ -583,9 +578,10 @@ namespace ImageSharp.Formats
private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, PixelAccessor<TPixel> pixels) private void ProcessDefilteredScanline<TPixel>(byte[] defilteredScanline, PixelAccessor<TPixel> pixels)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel color = default(TPixel); var color = default(TPixel);
BufferSpan<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow); BufferSpan<TPixel> pixelBuffer = pixels.GetRowSpan(this.currentRow);
BufferSpan<byte> scanlineBuffer = new BufferSpan<byte>(defilteredScanline, 1); var scanlineBuffer = new BufferSpan<byte>(defilteredScanline, 1);
switch (this.PngColorType) switch (this.PngColorType)
{ {
case PngColorType.Grayscale: case PngColorType.Grayscale:
@ -646,7 +642,7 @@ namespace ImageSharp.Formats
{ {
byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth); byte[] newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
byte[] palette = this.palette; byte[] palette = this.palette;
TPixel color = default(TPixel); var color = default(TPixel);
if (this.paletteAlpha != null && this.paletteAlpha.Length > 0) if (this.paletteAlpha != null && this.paletteAlpha.Length > 0)
{ {
@ -703,7 +699,7 @@ namespace ImageSharp.Formats
private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, int row, PixelAccessor<TPixel> pixels, int pixelOffset = 0, int increment = 1) private void ProcessInterlacedDefilteredScanline<TPixel>(byte[] defilteredScanline, int row, PixelAccessor<TPixel> pixels, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel color = default(TPixel); var color = default(TPixel);
switch (this.PngColorType) switch (this.PngColorType)
{ {
@ -901,7 +897,7 @@ namespace ImageSharp.Formats
/// </returns> /// </returns>
private PngChunk ReadChunk() private PngChunk ReadChunk()
{ {
PngChunk chunk = new PngChunk(); var chunk = new PngChunk();
this.ReadChunkLength(chunk); this.ReadChunkLength(chunk);
if (chunk.Length < 0) if (chunk.Length < 0)
{ {

Loading…
Cancel
Save