diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index 6fe2175d9b..f5df67e0b8 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -52,10 +52,9 @@ namespace ImageSharp.Formats /// The bytes per pixel. /// The number of bytes per scanline /// The - public static byte[] Encode(byte[] scanline, byte[] previousScanline, int bytesPerPixel, int bytesPerScanline) + public static byte[] Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel, int bytesPerScanline) { // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) - byte[] result = new byte[bytesPerScanline + 1]; fixed (byte* scan = scanline) fixed (byte* prev = previousScanline) fixed (byte* res = result) diff --git a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs index 068e57ad07..bceaec0fda 100644 --- a/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/NoneFilter.cs @@ -30,15 +30,11 @@ namespace ImageSharp.Formats /// /// The scanline to encode /// The number of bytes per scanline - /// The - public static byte[] Encode(byte[] scanline, int bytesPerScanline) + public static void Encode(byte[] scanline, byte[] result, int bytesPerScanline) { // Insert a byte before the data. - byte[] result = new byte[bytesPerScanline + 1]; result[0] = 0; Buffer.BlockCopy(scanline, 0, result, 1, bytesPerScanline); - - return result; } } } diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 55f7a36b03..c8aa95f66a 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -52,11 +52,9 @@ namespace ImageSharp.Formats /// The bytes per pixel. /// The number of bytes per scanline /// The - public static byte[] Encode(byte[] scanline, byte[] previousScanline, int bytesPerPixel, int bytesPerScanline) + public static byte[] Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerPixel, int bytesPerScanline) { // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) - byte[] result = new byte[bytesPerScanline + 1]; - fixed (byte* scan = scanline) fixed (byte* prev = previousScanline) fixed (byte* res = result) diff --git a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs index 7f162fae1c..8bbde4ef42 100644 --- a/src/ImageSharp/Formats/Png/Filters/UpFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/UpFilter.cs @@ -45,11 +45,9 @@ namespace ImageSharp.Formats /// The number of bytes per scanline /// The previous scanline. /// The - public static byte[] Encode(byte[] scanline, int bytesPerScanline, byte[] previousScanline) + public static byte[] Encode(byte[] scanline, byte[] previousScanline, byte[] result, int bytesPerScanline) { // Up(x) = Raw(x) - Prior(x) - byte[] result = new byte[bytesPerScanline + 1]; - fixed (byte* scan = scanline) fixed (byte* prev = previousScanline) fixed (byte* res = result) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index c4b234147a..2a4683e70a 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -313,9 +313,9 @@ namespace ImageSharp.Formats /// The row. /// The previous scanline. /// The raw scanline. + /// The resultant filtered scanline. /// The number of bytes per scanline. - /// The - private byte[] EncodePixelRow(PixelAccessor pixels, int row, byte[] previousScanline, byte[] rawScanline, int bytesPerScanline) + private void EncodePixelRow(PixelAccessor pixels, int row, byte[] previousScanline, byte[] rawScanline, byte[] result, int bytesPerScanline) where TColor : struct, IPackedPixel where TPacked : struct { @@ -333,9 +333,7 @@ namespace ImageSharp.Formats break; } - byte[] filteredScanline = this.GetOptimalFilteredScanline(rawScanline, previousScanline, bytesPerScanline, this.bytesPerPixel); - - return filteredScanline; + this.GetOptimalFilteredScanline(rawScanline, previousScanline, result, bytesPerScanline); } /// @@ -344,37 +342,30 @@ namespace ImageSharp.Formats /// /// The raw scanline /// The previous scanline + /// The filtered scanline result /// The number of bytes per scanline - /// The number of bytes per pixel - /// The - private byte[] GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, int bytesPerScanline, int bytesPerPixel) + private void GetOptimalFilteredScanline(byte[] rawScanline, byte[] previousScanline, byte[] result, int bytesPerScanline) { - Tuple[] candidates; - // Palette images don't compress well with adaptive filtering. if (this.PngColorType == PngColorType.Palette) { - candidates = new Tuple[1]; - - byte[] none = NoneFilter.Encode(rawScanline, bytesPerScanline); - candidates[0] = new Tuple(none, this.CalculateTotalVariation(none)); + NoneFilter.Encode(rawScanline, result, bytesPerScanline); + return; } - else - { - candidates = new Tuple[4]; - byte[] sub = SubFilter.Encode(rawScanline, bytesPerPixel, bytesPerScanline); - candidates[0] = new Tuple(sub, this.CalculateTotalVariation(sub)); + Tuple[] candidates = new Tuple[4]; - byte[] up = UpFilter.Encode(rawScanline, bytesPerScanline, previousScanline); - candidates[1] = new Tuple(up, this.CalculateTotalVariation(up)); + byte[] sub = SubFilter.Encode(rawScanline, this.bytesPerPixel, bytesPerScanline); + candidates[0] = new Tuple(sub, this.CalculateTotalVariation(sub)); - byte[] average = AverageFilter.Encode(rawScanline, previousScanline, bytesPerPixel, bytesPerScanline); - candidates[2] = new Tuple(average, this.CalculateTotalVariation(average)); + byte[] up = UpFilter.Encode(rawScanline, previousScanline, result, bytesPerScanline); + candidates[1] = new Tuple(up, this.CalculateTotalVariation(up)); - byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, bytesPerPixel, bytesPerScanline); - candidates[3] = new Tuple(paeth, this.CalculateTotalVariation(paeth)); - } + byte[] average = AverageFilter.Encode(rawScanline, previousScanline, result, this.bytesPerPixel, bytesPerScanline); + candidates[2] = new Tuple(average, this.CalculateTotalVariation(average)); + + byte[] paeth = PaethFilter.Encode(rawScanline, previousScanline, result, this.bytesPerPixel, bytesPerScanline); + candidates[3] = new Tuple(paeth, this.CalculateTotalVariation(paeth)); int lowestTotalVariation = int.MaxValue; int lowestTotalVariationIndex = 0; @@ -388,7 +379,8 @@ namespace ImageSharp.Formats } } - return candidates[lowestTotalVariationIndex].Item1; + // ReSharper disable once RedundantAssignment + result = candidates[lowestTotalVariationIndex].Item1; } /// @@ -599,6 +591,7 @@ namespace ImageSharp.Formats int bytesPerScanline = this.width * this.bytesPerPixel; byte[] previousScanline = ArrayPool.Shared.Rent(bytesPerScanline); byte[] rawScanline = ArrayPool.Shared.Rent(bytesPerScanline); + byte[] result = ArrayPool.Shared.Rent(bytesPerScanline + 1); byte[] buffer; int bufferLength; @@ -610,8 +603,8 @@ namespace ImageSharp.Formats { for (int y = 0; y < this.height; y++) { - byte[] data = this.EncodePixelRow(pixels, y, previousScanline, rawScanline, bytesPerScanline); - deflateStream.Write(data, 0, data.Length); + this.EncodePixelRow(pixels, y, previousScanline, rawScanline, result, bytesPerScanline); + deflateStream.Write(result, 0, bytesPerScanline + 1); deflateStream.Flush(); // Do a bit of shuffling; @@ -628,6 +621,7 @@ namespace ImageSharp.Formats { ArrayPool.Shared.Return(previousScanline); ArrayPool.Shared.Return(rawScanline); + ArrayPool.Shared.Return(result); memoryStream?.Dispose(); }