diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 1053a2548..a1fd559a3 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -181,7 +181,7 @@ namespace ImageSharp.Formats
}
else if (this.PngColorType == PngColorType.Grayscale || this.PngColorType == PngColorType.GrayscaleWithAlpha)
{
- this.CollectGrayscaleBytes(image);
+ //this.CollectGrayscaleBytes(image);
}
else
{
@@ -253,40 +253,38 @@ namespace ImageSharp.Formats
}
///
- /// Collects the grayscale pixel data.
+ /// Collects a row of grayscale pixels.
///
/// The pixel format.
/// The packed format. uint, long, float.
/// The image to encode.
- private void CollectGrayscaleBytes(ImageBase image)
+ /// The row index.
+ /// The raw scanline.
+ private void CollectGrayscaleBytes(ImageBase image, int row, byte[] rawScanline)
where TColor : struct, IPackedPixel
where TPacked : struct
{
// 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 pixels = image.Lock())
{
- for (int y = 0; y < this.height; y++)
+ for (int x = 0; x < this.width; x++)
{
- for (int x = 0; x < this.width; x++)
+ // Convert the color to YCbCr and store the luminance
+ // Optionally store the original color alpha.
+ int offset = x * this.bytesPerPixel;
+ pixels[x, row].ToBytes(bytes, 0, ComponentOrder.XYZW);
+ byte luminance = (byte)((0.299F * bytes[0]) + (0.587F * bytes[1]) + (0.114F * bytes[2]));
+
+ for (int i = 0; i < this.bytesPerPixel; i++)
{
- // 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)
+ {
+ rawScanline[offset] = luminance;
+ }
+ else
{
- if (i == 0)
- {
- this.pixelData[dataOffset] = (byte)luminance.Y;
- }
- else
- {
- this.pixelData[dataOffset + i] = bytes[3];
- }
+ rawScanline[offset + i] = bytes[3];
}
}
}
@@ -294,13 +292,13 @@ namespace ImageSharp.Formats
}
///
- /// Collects the true color pixel data.
+ /// Collects a row of true color pixel data.
///
/// The pixel format.
/// The packed format. uint, long, float.
/// The image to encode.
/// The row index.
- /// The raw Scanline.
+ /// The raw scanline.
private void CollectColorBytes(ImageBase image, int row, byte[] rawScanline)
where TColor : struct, IPackedPixel
where TPacked : struct
@@ -312,11 +310,6 @@ namespace ImageSharp.Formats
{
pixels[x, row].ToBytes(rawScanline, x * this.bytesPerPixel, bpp == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ);
}
-
- if (rawScanline.Any(x => x > 0))
- {
- var t = rawScanline;
- }
}
}
@@ -336,13 +329,18 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel
where TPacked : struct
{
- if (this.PngColorType == PngColorType.Palette || this.PngColorType == PngColorType.Grayscale || this.PngColorType == PngColorType.GrayscaleWithAlpha)
- {
- Buffer.BlockCopy(this.pixelData, row * bytesPerScanline, rawScanline, 0, bytesPerScanline);
- }
- else
+ switch (this.PngColorType)
{
- this.CollectColorBytes(image, row, rawScanline);
+ case PngColorType.Palette:
+ Buffer.BlockCopy(this.pixelData, row * bytesPerScanline, rawScanline, 0, bytesPerScanline);
+ break;
+ case PngColorType.Grayscale:
+ case PngColorType.GrayscaleWithAlpha:
+ this.CollectGrayscaleBytes(image, row, rawScanline);
+ break;
+ default:
+ this.CollectColorBytes(image, row, rawScanline);
+ break;
}
byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, bytesPerScanline, this.bytesPerPixel);
@@ -363,9 +361,10 @@ namespace ImageSharp.Formats
{
Tuple[] candidates;
+ // Palette images don't compress well with adaptive filtering.
if (this.PngColorType == PngColorType.Palette)
{
- candidates = new Tuple[4];
+ candidates = new Tuple[1];
byte[] none = NoneFilter.Encode(rawScanline);
candidates[0] = new Tuple(none, this.CalculateTotalVariation(none));
@@ -634,6 +633,8 @@ namespace ImageSharp.Formats
memoryStream?.Dispose();
}
+ // Store the chunks in repeated 64k blocks.
+ // This reduces the memory load for decoding the image for many decoders.
int numChunks = bufferLength / MaxBlockSize;
if (bufferLength % MaxBlockSize != 0)