diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index ad5c6a2dc..f0f209a0c 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -2,6 +2,7 @@ // Copyright (c) James Jackson-South and contributors. // Licensed under the Apache License, Version 2.0. // + namespace ImageSharp.Formats { using System; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index f7e79a52c..b1517299b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -174,6 +174,7 @@ namespace ImageSharp.Formats this.WriteHeaderChunk(stream, header); // Collect the pixel data + // TODO: Avoid doing this all at once and try row by row. if (this.PngColorType == PngColorType.Palette) { this.CollectIndexedBytes(image, stream, header); @@ -328,38 +329,17 @@ namespace ImageSharp.Formats /// Encodes the pixel data line by line. /// Each scanline is encoded in the most optimal manner to improve compression. /// + /// The row. + /// The previous scanline. + /// The raw scanline. + /// The number of bytes per scanline. /// The - private byte[] EncodePixelData() + private byte[] EncodePixelRow(int row, byte[] previousScanline, byte[] rawScanline, int bytesPerScanline) { - byte[][] filteredScanlines = new byte[this.height][]; - int bytesPerScanline = this.width * 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); - } + Buffer.BlockCopy(this.pixelData, row * bytesPerScanline, rawScanline, 0, bytesPerScanline); + byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, bytesPerScanline, this.bytesPerPixel); - return result; + return filteredScanline; } /// @@ -590,28 +570,39 @@ namespace ImageSharp.Formats /// /// Writes the pixel information to the stream. - /// TODO: This is WHACK! We should be able to do this without creating yet another array. /// /// The 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; int bufferLength; - MemoryStream memoryStream = null; try { memoryStream = new MemoryStream(); - 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; - buffer = memoryStream.ToArray(); + bufferLength = (int)memoryStream.Length; + buffer = memoryStream.ToArray(); + } } finally { diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs index 3fa61ff56..2deb7dcf0 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibDeflateStream.cs @@ -37,7 +37,9 @@ namespace ImageSharp.Formats /// private bool isDisposed; - // The stream responsible for decompressing the input stream. + /// + /// The stream responsible for compressing the input stream. + /// private DeflateStream deflateStream; ///