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();
}