Browse Source

Minor png codec perf improvements

pull/20/head
James Jackson-South 10 years ago
parent
commit
b477e795fb
  1. 13
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 66
      src/ImageSharp/Formats/Png/PngEncoderCore.cs

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

@ -8,7 +8,6 @@ namespace ImageSharp.Formats
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text;
/// <summary>
@ -336,7 +335,7 @@ namespace ImageSharp.Formats
byte intensity = defilteredScanline[offset];
TColor color = default(TColor);
color.PackFromVector4(new Vector4(intensity, intensity, intensity, 255) / 255F);
color.PackFromBytes(intensity, intensity, intensity, 255);
pixels[(row * this.header.Width) + x] = color;
}
@ -352,7 +351,7 @@ namespace ImageSharp.Formats
byte alpha = defilteredScanline[offset + this.bytesPerSample];
TColor color = default(TColor);
color.PackFromVector4(new Vector4(intensity, intensity, intensity, alpha) / 255F);
color.PackFromBytes(intensity, intensity, intensity, alpha);
pixels[(row * this.header.Width) + x] = color;
}
@ -379,7 +378,7 @@ namespace ImageSharp.Formats
byte r = this.palette[pixelOffset];
byte g = this.palette[pixelOffset + 1];
byte b = this.palette[pixelOffset + 2];
color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
color.PackFromBytes(r, g, b, a);
}
pixels[offset] = color;
@ -398,7 +397,7 @@ namespace ImageSharp.Formats
byte b = this.palette[pixelOffset + 2];
TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, 255) / 255F);
color.PackFromBytes(r, g, b, 255);
pixels[offset] = color;
}
}
@ -416,7 +415,7 @@ namespace ImageSharp.Formats
byte b = defilteredScanline[offset + (2 * this.bytesPerSample)];
TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, 255) / 255F);
color.PackFromBytes(r, g, b, 255);
pixels[(row * this.header.Width) + x] = color;
}
@ -434,7 +433,7 @@ namespace ImageSharp.Formats
byte a = defilteredScanline[offset + (3 * this.bytesPerSample)];
TColor color = default(TColor);
color.PackFromVector4(new Vector4(r, g, b, a) / 255F);
color.PackFromBytes(r, g, b, a);
pixels[(row * this.header.Width) + x] = color;
}

66
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -14,7 +14,7 @@ namespace ImageSharp.Formats
/// <summary>
/// Performs the png encoding operation.
/// TODO: Perf. There's lots of array parsing going on here. This should be unmanaged.
/// TODO: Perf. There's lots of array parsing and copying going on here. This should be unmanaged.
/// </summary>
internal sealed class PngEncoderCore
{
@ -254,34 +254,31 @@ namespace ImageSharp.Formats
// Copy the pixels across from the image.
this.pixelData = new byte[this.width * this.height * this.bytesPerPixel];
int stride = this.width * this.bytesPerPixel;
byte[] bytes = new byte[4];
using (PixelAccessor<TColor, TPacked> pixels = image.Lock())
{
Parallel.For(
0,
this.height,
Bootstrapper.Instance.ParallelOptions,
y =>
{
for (int x = 0; x < this.width; x++)
{
// Convert the color to YCbCr and store the luminance
// Optionally store the original color alpha.
int dataOffset = (y * stride) + (x * this.bytesPerPixel);
Color source = new Color(pixels[x, y].ToVector4());
YCbCr luminance = source;
for (int i = 0; i < this.bytesPerPixel; i++)
{
if (i == 0)
{
this.pixelData[dataOffset] = ((byte)luminance.Y).Clamp(0, 255);
}
else
{
this.pixelData[dataOffset + i] = source.A;
}
}
}
});
for (int y = 0; y < this.height; y++)
{
for (int x = 0; x < this.width; x++)
{
// Convert the color to YCbCr and store the luminance
// Optionally store the original color alpha.
int dataOffset = (y * stride) + (x * this.bytesPerPixel);
pixels[x, y].ToBytes(bytes, 0, ComponentOrder.XYZW);
YCbCr luminance = new Color(bytes[0], bytes[1], bytes[2], bytes[3]);
for (int i = 0; i < this.bytesPerPixel; i++)
{
if (i == 0)
{
this.pixelData[dataOffset] = (byte)luminance.Y;
}
else
{
this.pixelData[dataOffset + i] = bytes[3];
}
}
}
}
}
}
@ -296,10 +293,12 @@ namespace ImageSharp.Formats
where TPacked : struct
{
// Copy the pixels across from the image.
// TODO: This could be sped up more if we add a method to PixelAccessor that does this by row directly to a byte array.
this.pixelData = new byte[this.width * this.height * this.bytesPerPixel];
int stride = this.width * this.bytesPerPixel;
using (PixelAccessor<TColor, TPacked> pixels = image.Lock())
{
int bpp = this.bytesPerPixel;
Parallel.For(
0,
this.height,
@ -309,15 +308,7 @@ namespace ImageSharp.Formats
for (int x = 0; x < this.width; x++)
{
int dataOffset = (y * stride) + (x * this.bytesPerPixel);
Color source = new Color(pixels[x, y].ToVector4());
this.pixelData[dataOffset] = source.R;
this.pixelData[dataOffset + 1] = source.G;
this.pixelData[dataOffset + 2] = source.B;
if (this.bytesPerPixel == 4)
{
this.pixelData[dataOffset + 3] = source.A;
}
pixels[x, y].ToBytes(this.pixelData, dataOffset, bpp == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ);
}
});
}
@ -330,6 +321,7 @@ namespace ImageSharp.Formats
/// <returns>The <see cref="T:byte[]"/></returns>
private byte[] EncodePixelData()
{
// TODO: Use pointers
List<byte[]> filteredScanlines = new List<byte[]>();
byte[] previousScanline = new byte[this.width * this.bytesPerPixel];
@ -344,6 +336,7 @@ namespace ImageSharp.Formats
previousScanline = rawScanline;
}
// TODO: We should be able to use a byte array when not using interlaced encoding.
List<byte> result = new List<byte>();
foreach (byte[] encodedScanline in filteredScanlines)
@ -516,6 +509,7 @@ namespace ImageSharp.Formats
int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3;
byte[] colorTable = new byte[colorTableLength];
// TODO: Optimize this.
Parallel.For(
0,
pixelCount,

Loading…
Cancel
Save