diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 48eb54768b..04d4f057ce 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -341,25 +341,36 @@ namespace SixLabors.ImageSharp.Formats.Png
}
///
- /// Converts a byte array to a new array where each value in the original array is represented by the specified number of bits.
+ /// Reads the least significant bits from the byte pair with the others set to 0.
+ ///
+ /// The source buffer
+ /// THe offset
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset)
+ {
+ return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
+ }
+
+ ///
+ /// Attempts to convert a byte array to a new array where each value in the original array is represented by the
+ /// specified number of bits.
///
/// The bytes to convert from. Cannot be empty.
/// The number of bytes per scanline
/// The number of bits per value.
+ /// The new array.
/// The resulting array.
- /// is less than or equals than zero.
- private static ReadOnlySpan ToArrayByBitsLength(ReadOnlySpan source, int bytesPerScanline, int bits)
+ private bool TryScaleUpTo8BitArray(ReadOnlySpan source, int bytesPerScanline, int bits, out IManagedByteBuffer buffer)
{
- Guard.MustBeGreaterThan(source.Length, 0, nameof(source));
- Guard.MustBeGreaterThan(bits, 0, nameof(bits));
-
if (bits >= 8)
{
- return source;
+ buffer = null;
+ return false;
}
- // TODO: We should be pooling this.
- byte[] result = new byte[bytesPerScanline * 8 / bits];
+ buffer = this.MemoryAllocator.AllocateCleanManagedByteBuffer(bytesPerScanline * 8 / bits);
+ byte[] result = buffer.Array;
int mask = 0xFF >> (8 - bits);
int resultOffset = 0;
@@ -369,26 +380,13 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int shift = 0; shift < 8; shift += bits)
{
int colorIndex = (b >> (8 - bits - shift)) & mask;
-
result[resultOffset] = (byte)colorIndex;
resultOffset++;
}
}
- return result;
- }
-
- ///
- /// Reads the least significant bits from the byte pair with the others set to 0.
- ///
- /// The source buffer
- /// THe offset
- /// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset)
- {
- return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
+ return true;
}
///
@@ -669,11 +667,16 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels)
where TPixel : struct, IPixel
{
- var color = default(TPixel);
+ TPixel pixel = default;
Span rowSpan = pixels.GetPixelRowSpan(this.currentRow);
// Trim the first marker byte from the buffer
- ReadOnlySpan scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
+ ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
+
+ // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
+ ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline, this.header.BitDepth, out IManagedByteBuffer buffer)
+ ? buffer.GetSpan()
+ : trimmed;
switch (this.pngColorType)
{
@@ -681,9 +684,6 @@ namespace SixLabors.ImageSharp.Formats.Png
int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1);
- // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
-
if (!this.hasTrans)
{
if (this.header.BitDepth == 16)
@@ -691,12 +691,12 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgb48 rgb48 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 2)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance;
rgb48.G = luminance;
rgb48.B = luminance;
- color.PackFromRgb48(rgb48);
- rowSpan[x] = color;
+ pixel.PackFromRgb48(rgb48);
+ rowSpan[x] = pixel;
}
}
else
@@ -705,12 +705,12 @@ namespace SixLabors.ImageSharp.Formats.Png
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = 0; x < this.header.Width; x++)
{
- byte luminance = (byte)(scanline[x] * factor);
+ byte luminance = (byte)(scanlineSpan[x] * factor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
}
@@ -721,14 +721,14 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 2)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -736,14 +736,14 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba32 = default;
for (int x = 0; x < this.header.Width; x++)
{
- byte luminance = (byte)(scanline[x] * factor);
+ byte luminance = (byte)(scanlineSpan[x] * factor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
}
@@ -757,15 +757,15 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 4)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = alpha;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -774,16 +774,16 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0; x < this.header.Width; x++)
{
int offset = x * this.bytesPerPixel;
- byte luminance = scanlineBuffer[offset];
- byte alpha = scanlineBuffer[offset + this.bytesPerSample];
+ byte luminance = scanlineSpan[offset];
+ byte alpha = scanlineSpan[offset + this.bytesPerSample];
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = alpha;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
@@ -791,7 +791,7 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngColorType.Palette:
- this.ProcessScanlineFromPalette(scanlineBuffer, rowSpan);
+ this.ProcessScanlineFromPalette(scanlineSpan, rowSpan);
break;
@@ -804,16 +804,16 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgb48 rgb48 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 6)
{
- rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
- color.PackFromRgb48(rgb48);
- rowSpan[x] = color;
+ rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
+ pixel.PackFromRgb48(rgb48);
+ rowSpan[x] = pixel;
}
}
else
{
- PixelOperations.Instance.PackFromRgb24Bytes(scanlineBuffer, rowSpan, this.header.Width);
+ PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, this.header.Width);
}
}
else
@@ -824,20 +824,20 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 6)
{
- rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
+ rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
rgba64.Rgb = rgb48;
rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
{
- ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineBuffer);
+ ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan);
for (int x = 0; x < this.header.Width; x++)
{
ref readonly Rgb24 rgb24 = ref rgb24Span[x];
@@ -845,8 +845,8 @@ namespace SixLabors.ImageSharp.Formats.Png
rgba32.Rgb = rgb24;
rgba32.A = rgb24.Equals(this.rgb24Trans) ? byte.MinValue : byte.MaxValue;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
}
@@ -860,21 +860,23 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < this.header.Width; x++, o += 8)
{
- rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
- rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2));
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
+ rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2));
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
{
- PixelOperations.Instance.PackFromRgba32Bytes(scanlineBuffer, rowSpan, this.header.Width);
+ PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, this.header.Width);
}
break;
}
+
+ buffer?.Dispose();
}
///
@@ -888,10 +890,15 @@ namespace SixLabors.ImageSharp.Formats.Png
private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel
{
- var color = default(TPixel);
+ TPixel pixel = default;
// Trim the first marker byte from the buffer
- ReadOnlySpan scanlineBuffer = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
+ ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1);
+
+ // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
+ ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline, this.header.BitDepth, out IManagedByteBuffer buffer)
+ ? buffer.GetSpan()
+ : trimmed;
switch (this.pngColorType)
{
@@ -899,9 +906,6 @@ namespace SixLabors.ImageSharp.Formats.Png
int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1);
- // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent.
- ReadOnlySpan scanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
-
if (!this.hasTrans)
{
if (this.header.BitDepth == 16)
@@ -909,13 +913,13 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgb48 rgb48 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance;
rgb48.G = luminance;
rgb48.B = luminance;
- color.PackFromRgb48(rgb48);
- rowSpan[x] = color;
+ pixel.PackFromRgb48(rgb48);
+ rowSpan[x] = pixel;
}
}
else
@@ -924,13 +928,13 @@ namespace SixLabors.ImageSharp.Formats.Png
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{
- byte luminance = (byte)(scanline[o] * factor);
+ byte luminance = (byte)(scanlineSpan[o] * factor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
}
@@ -941,14 +945,14 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -956,14 +960,14 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba32 = default;
for (int x = pixelOffset; x < this.header.Width; x += increment)
{
- byte luminance = (byte)(scanline[x] * factor);
+ byte luminance = (byte)(scanlineSpan[x] * factor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
}
@@ -977,15 +981,15 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4)
{
- ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
+ ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
rgba64.A = alpha;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -994,15 +998,15 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = pixelOffset; x < this.header.Width; x += increment)
{
int offset = x * this.bytesPerPixel;
- byte luminance = scanlineBuffer[offset];
- byte alpha = scanlineBuffer[offset + this.bytesPerSample];
+ byte luminance = scanlineSpan[offset];
+ byte alpha = scanlineSpan[offset + this.bytesPerSample];
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
rgba32.A = alpha;
- color.PackFromRgba32(rgba32);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba32);
+ rowSpan[x] = pixel;
}
}
@@ -1010,8 +1014,7 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngColorType.Palette:
- ReadOnlySpan newScanline = ToArrayByBitsLength(scanlineBuffer, this.bytesPerScanline, this.header.BitDepth);
- Span pal = MemoryMarshal.Cast(this.palette);
+ Span palettePixels = MemoryMarshal.Cast(this.palette);
if (this.paletteAlpha?.Length > 0)
{
@@ -1020,12 +1023,12 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{
- int index = newScanline[o];
+ int index = scanlineSpan[o];
rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue;
- rgba.Rgb = pal[index];
+ rgba.Rgb = palettePixels[index];
- color.PackFromRgba32(rgba);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba);
+ rowSpan[x] = pixel;
}
}
else
@@ -1033,11 +1036,11 @@ namespace SixLabors.ImageSharp.Formats.Png
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++)
{
- int index = newScanline[o];
- rgba.Rgb = pal[index];
+ int index = scanlineSpan[o];
+ rgba.Rgb = palettePixels[index];
- color.PackFromRgba32(rgba);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba);
+ rowSpan[x] = pixel;
}
}
@@ -1053,15 +1056,15 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6)
{
- rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
+ rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
rgba64.Rgb = rgb48;
rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue;
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -1069,11 +1072,11 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgb48 rgb48 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6)
{
- rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
- color.PackFromRgb48(rgb48);
- rowSpan[x] = color;
+ rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
+ pixel.PackFromRgb48(rgb48);
+ rowSpan[x] = pixel;
}
}
}
@@ -1084,13 +1087,13 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel)
{
- rgba.R = scanlineBuffer[o];
- rgba.G = scanlineBuffer[o + this.bytesPerSample];
- rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)];
+ rgba.R = scanlineSpan[o];
+ rgba.G = scanlineSpan[o + this.bytesPerSample];
+ rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)];
rgba.A = this.rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue;
- color.PackFromRgba32(rgba);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba);
+ rowSpan[x] = pixel;
}
}
else
@@ -1098,12 +1101,12 @@ namespace SixLabors.ImageSharp.Formats.Png
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel)
{
- rgba.R = scanlineBuffer[o];
- rgba.G = scanlineBuffer[o + this.bytesPerSample];
- rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)];
+ rgba.R = scanlineSpan[o];
+ rgba.G = scanlineSpan[o + this.bytesPerSample];
+ rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)];
- color.PackFromRgba32(rgba);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba);
+ rowSpan[x] = pixel;
}
}
}
@@ -1117,12 +1120,12 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 8)
{
- rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o, 2));
- rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 2, 2));
- rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 4, 2));
- rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineBuffer.Slice(o + 6, 2));
- color.PackFromRgba64(rgba64);
- rowSpan[x] = color;
+ rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
+ rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
+ rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2));
+ rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2));
+ pixel.PackFromRgba64(rgba64);
+ rowSpan[x] = pixel;
}
}
else
@@ -1130,18 +1133,20 @@ namespace SixLabors.ImageSharp.Formats.Png
Rgba32 rgba = default;
for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel)
{
- rgba.R = scanlineBuffer[o];
- rgba.G = scanlineBuffer[o + this.bytesPerSample];
- rgba.B = scanlineBuffer[o + (2 * this.bytesPerSample)];
- rgba.A = scanlineBuffer[o + (3 * this.bytesPerSample)];
+ rgba.R = scanlineSpan[o];
+ rgba.G = scanlineSpan[o + this.bytesPerSample];
+ rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)];
+ rgba.A = scanlineSpan[o + (3 * this.bytesPerSample)];
- color.PackFromRgba32(rgba);
- rowSpan[x] = color;
+ pixel.PackFromRgba32(rgba);
+ rowSpan[x] = pixel;
}
}
break;
}
+
+ buffer?.Dispose();
}
///
@@ -1193,13 +1198,12 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Processes a scanline that uses a palette
///
/// The type of pixel we are expanding to
- /// The scanline
+ /// The defiltered scanline
/// Thecurrent output image row
- private void ProcessScanlineFromPalette(ReadOnlySpan defilteredScanline, Span row)
+ private void ProcessScanlineFromPalette(ReadOnlySpan scanline, Span row)
where TPixel : struct, IPixel
{
- ReadOnlySpan newScanline = ToArrayByBitsLength(defilteredScanline, this.bytesPerScanline, this.header.BitDepth);
- ReadOnlySpan pal = MemoryMarshal.Cast(this.palette);
+ ReadOnlySpan palettePixels = MemoryMarshal.Cast(this.palette);
var color = default(TPixel);
if (this.paletteAlpha?.Length > 0)
@@ -1210,9 +1214,9 @@ namespace SixLabors.ImageSharp.Formats.Png
// channel and we should try to read it.
for (int x = 0; x < this.header.Width; x++)
{
- int index = newScanline[x];
+ int index = scanline[x];
rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue;
- rgba.Rgb = pal[index];
+ rgba.Rgb = palettePixels[index];
color.PackFromRgba32(rgba);
row[x] = color;
@@ -1220,13 +1224,13 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
+ // TODO: We should have PackFromRgb24.
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
-
for (int x = 0; x < this.header.Width; x++)
{
- int index = newScanline[x];
+ int index = scanline[x];
- rgba.Rgb = pal[index];
+ rgba.Rgb = palettePixels[index];
color.PackFromRgba32(rgba);
row[x] = color;
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
index 348b3b1857..7286539f70 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
@@ -44,14 +44,14 @@ namespace SixLabors.ImageSharp.Tests
// IDAT
0x00, 0x00, 0x00, 0x0C, 0x49, 0x44, 0x41, 0x54, 0x18, 0x57, 0x63, 0x60, 0x60, 0x60, 0x00, 0x00,
0x00, 0x04, 0x00, 0x01,
-
+
// IDAT CRC
0x5C, 0xCD, 0xFF, 0x69,
// IEND
0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
0x4E, 0x44,
-
+
// IEND CRC
0xAE, 0x42, 0x60, 0x82
};
@@ -76,7 +76,6 @@ namespace SixLabors.ImageSharp.Tests
TestImages.Png.VimImage2,
};
-
public static readonly string[] TestImages48Bpp =
{
TestImages.Png.Rgb48Bpp,