diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 0738602914..95f50cf276 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -60,6 +60,26 @@ namespace ImageSharp.Formats
///
private int bytesPerPixel;
+ ///
+ /// The buffer for the sub filter
+ ///
+ private byte[] sub;
+
+ ///
+ /// The buffer for the up filter
+ ///
+ private byte[] up;
+
+ ///
+ /// The buffer for the average filter
+ ///
+ private byte[] average;
+
+ ///
+ /// The buffer for the paeth filter
+ ///
+ private byte[] paeth;
+
///
/// Gets or sets the quality of output for images.
///
@@ -356,54 +376,39 @@ namespace ImageSharp.Formats
return result;
}
- byte[] sub = ArrayPool.Shared.Rent(bytesPerScanline + 1);
- byte[] up = ArrayPool.Shared.Rent(bytesPerScanline + 1);
- byte[] average = ArrayPool.Shared.Rent(bytesPerScanline + 1);
- byte[] paeth = ArrayPool.Shared.Rent(bytesPerScanline + 1);
+ SubFilter.Encode(rawScanline, this.sub, this.bytesPerPixel, bytesPerScanline);
+ int currentTotalVariation = this.CalculateTotalVariation(this.sub, bytesPerScanline);
+ int lowestTotalVariation = currentTotalVariation;
- try
- {
- SubFilter.Encode(rawScanline, sub, this.bytesPerPixel, bytesPerScanline);
- int currentTotalVariation = this.CalculateTotalVariation(sub, bytesPerScanline);
- int lowestTotalVariation = currentTotalVariation;
+ result = this.sub;
- result = sub;
-
- UpFilter.Encode(rawScanline, previousScanline, up, bytesPerScanline);
- currentTotalVariation = this.CalculateTotalVariation(up, bytesPerScanline);
-
- if (currentTotalVariation < lowestTotalVariation)
- {
- lowestTotalVariation = currentTotalVariation;
- result = up;
- }
+ UpFilter.Encode(rawScanline, previousScanline, this.up, bytesPerScanline);
+ currentTotalVariation = this.CalculateTotalVariation(this.up, bytesPerScanline);
- AverageFilter.Encode(rawScanline, previousScanline, average, this.bytesPerPixel, bytesPerScanline);
- currentTotalVariation = this.CalculateTotalVariation(average, bytesPerScanline);
+ if (currentTotalVariation < lowestTotalVariation)
+ {
+ lowestTotalVariation = currentTotalVariation;
+ result = this.up;
+ }
- if (currentTotalVariation < lowestTotalVariation)
- {
- lowestTotalVariation = currentTotalVariation;
- result = average;
- }
+ AverageFilter.Encode(rawScanline, previousScanline, this.average, this.bytesPerPixel, bytesPerScanline);
+ currentTotalVariation = this.CalculateTotalVariation(this.average, bytesPerScanline);
- PaethFilter.Encode(rawScanline, previousScanline, paeth, this.bytesPerPixel, bytesPerScanline);
- currentTotalVariation = this.CalculateTotalVariation(paeth, bytesPerScanline);
+ if (currentTotalVariation < lowestTotalVariation)
+ {
+ lowestTotalVariation = currentTotalVariation;
+ result = this.average;
+ }
- if (currentTotalVariation < lowestTotalVariation)
- {
- result = paeth;
- }
+ PaethFilter.Encode(rawScanline, previousScanline, this.paeth, this.bytesPerPixel, bytesPerScanline);
+ currentTotalVariation = this.CalculateTotalVariation(this.paeth, bytesPerScanline);
- return result;
- }
- finally
+ if (currentTotalVariation < lowestTotalVariation)
{
- ArrayPool.Shared.Return(sub);
- ArrayPool.Shared.Return(up);
- ArrayPool.Shared.Return(average);
- ArrayPool.Shared.Return(paeth);
+ result = this.paeth;
}
+
+ return result;
}
///
@@ -618,6 +623,14 @@ namespace ImageSharp.Formats
int resultLength = bytesPerScanline + 1;
byte[] result = ArrayPool.Shared.Rent(resultLength);
+ if (this.PngColorType != PngColorType.Palette)
+ {
+ this.sub = ArrayPool.Shared.Rent(resultLength);
+ this.up = ArrayPool.Shared.Rent(resultLength);
+ this.average = ArrayPool.Shared.Rent(resultLength);
+ this.paeth = ArrayPool.Shared.Rent(resultLength);
+ }
+
byte[] buffer;
int bufferLength;
MemoryStream memoryStream = null;
@@ -643,6 +656,14 @@ namespace ImageSharp.Formats
ArrayPool.Shared.Return(previousScanline);
ArrayPool.Shared.Return(rawScanline);
ArrayPool.Shared.Return(result);
+
+ if (this.PngColorType != PngColorType.Palette)
+ {
+ ArrayPool.Shared.Return(this.sub);
+ ArrayPool.Shared.Return(this.up);
+ ArrayPool.Shared.Return(this.average);
+ ArrayPool.Shared.Return(this.paeth);
+ }
}
// Store the chunks in repeated 64k blocks.
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngTests.cs
index c442b71c97..04e28192aa 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngTests.cs
@@ -6,6 +6,7 @@
namespace ImageSharp.Tests
{
using System.IO;
+ using System.Threading.Tasks;
using Formats;
@@ -29,5 +30,23 @@ namespace ImageSharp.Tests
}
}
}
+
+ [Fact]
+ public void ImageCanSavePngInParallel()
+ {
+ string path = this.CreateOutputDirectory("Png");
+
+ Parallel.ForEach(
+ Files,
+ file =>
+ {
+ Image image = file.CreateImage();
+
+ using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
+ {
+ image.Save(output, new PngFormat());
+ }
+ });
+ }
}
}
\ No newline at end of file