Browse Source

Compress image data line by line.

pull/23/head
James Jackson-South 10 years ago
parent
commit
52cddd328e
  1. 1
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 65
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  3. 4
      src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs

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

@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
using System; using System;

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

@ -174,6 +174,7 @@ namespace ImageSharp.Formats
this.WriteHeaderChunk(stream, header); this.WriteHeaderChunk(stream, header);
// Collect the pixel data // Collect the pixel data
// TODO: Avoid doing this all at once and try row by row.
if (this.PngColorType == PngColorType.Palette) if (this.PngColorType == PngColorType.Palette)
{ {
this.CollectIndexedBytes(image, stream, header); this.CollectIndexedBytes(image, stream, header);
@ -328,38 +329,17 @@ namespace ImageSharp.Formats
/// Encodes the pixel data line by line. /// Encodes the pixel data line by line.
/// Each scanline is encoded in the most optimal manner to improve compression. /// Each scanline is encoded in the most optimal manner to improve compression.
/// </summary> /// </summary>
/// <param name="row">The row.</param>
/// <param name="previousScanline">The previous scanline.</param>
/// <param name="rawScanline">The raw scanline.</param>
/// <param name="bytesPerScanline">The number of bytes per scanline.</param>
/// <returns>The <see cref="T:byte[]"/></returns> /// <returns>The <see cref="T:byte[]"/></returns>
private byte[] EncodePixelData() private byte[] EncodePixelRow(int row, byte[] previousScanline, byte[] rawScanline, int bytesPerScanline)
{ {
byte[][] filteredScanlines = new byte[this.height][]; Buffer.BlockCopy(this.pixelData, row * bytesPerScanline, rawScanline, 0, bytesPerScanline);
int bytesPerScanline = this.width * this.bytesPerPixel; byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, bytesPerScanline, this.bytesPerPixel);
int length = 0;
byte[] previousScanline = new byte[bytesPerScanline];
byte[] rawScanline = new byte[bytesPerScanline];
for (int y = 0; y < this.height; y++)
{
Buffer.BlockCopy(this.pixelData, y * bytesPerScanline, rawScanline, 0, bytesPerScanline);
byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, bytesPerScanline, this.bytesPerPixel);
length += filteredScanline.Length;
filteredScanlines[y] = filteredScanline;
// Do a bit of shuffling;
byte[] tmp = rawScanline;
rawScanline = previousScanline;
previousScanline = tmp;
}
// Flatten the jagged array
byte[] result = new byte[length];
for (int i = 0; i < this.height; i++)
{
int len = filteredScanlines[i].Length;
Buffer.BlockCopy(filteredScanlines[i], 0, result, i * len, len);
}
return result; return filteredScanline;
} }
/// <summary> /// <summary>
@ -590,28 +570,39 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the pixel information to the stream. /// Writes the pixel information to the stream.
/// TODO: This is WHACK! We should be able to do this without creating yet another array.
/// </summary> /// </summary>
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
private void WriteDataChunks(Stream stream) private void WriteDataChunks(Stream stream)
{ {
byte[] data = this.EncodePixelData(); int bytesPerScanline = this.width * this.bytesPerPixel;
// TODO: These could be rented
byte[] previousScanline = new byte[bytesPerScanline];
byte[] rawScanline = new byte[bytesPerScanline];
byte[] buffer; byte[] buffer;
int bufferLength; int bufferLength;
MemoryStream memoryStream = null; MemoryStream memoryStream = null;
try try
{ {
memoryStream = new MemoryStream(); memoryStream = new MemoryStream();
using (ZlibDeflateStream deflateStream = new ZlibDeflateStream(memoryStream, this.CompressionLevel)) using (ZlibDeflateStream deflateStream = new ZlibDeflateStream(memoryStream, this.CompressionLevel))
{ {
deflateStream.Write(data, 0, data.Length); for (int y = 0; y < this.height; y++)
} {
byte[] data = this.EncodePixelRow(y, previousScanline, rawScanline, bytesPerScanline);
deflateStream.Write(data, 0, data.Length);
deflateStream.Flush();
// Do a bit of shuffling;
byte[] tmp = rawScanline;
rawScanline = previousScanline;
previousScanline = tmp;
}
bufferLength = (int)memoryStream.Length; bufferLength = (int)memoryStream.Length;
buffer = memoryStream.ToArray(); buffer = memoryStream.ToArray();
}
} }
finally finally
{ {

4
src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs

@ -37,7 +37,9 @@ namespace ImageSharp.Formats
/// </remarks> /// </remarks>
private bool isDisposed; private bool isDisposed;
// The stream responsible for decompressing the input stream. /// <summary>
/// The stream responsible for compressing the input stream.
/// </summary>
private DeflateStream deflateStream; private DeflateStream deflateStream;
/// <summary> /// <summary>

Loading…
Cancel
Save