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