From 3235ce41b82afba33cc4fabc5675f609b6c2e2fb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 23 Nov 2018 12:25:05 +0000 Subject: [PATCH] Fix trns preservation and add tests --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 11 ++- src/ImageSharp/Formats/Png/PngMetaData.cs | 5 ++ .../Formats/Png/PngEncoderTests.cs | 67 +++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 + tests/Images/Input/Png/gray-2-tRNS.png | 3 + tests/Images/Input/Png/gray-4-tRNS.png | 3 + tests/Images/Input/Png/gray-8-tRNS.png | 3 + 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Png/gray-2-tRNS.png create mode 100644 tests/Images/Input/Png/gray-4-tRNS.png create mode 100644 tests/Images/Input/Png/gray-8-tRNS.png diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index bb800c8a4..292de007c 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -760,9 +760,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image meta data. private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData) { + Span alpha = this.chunkDataBuffer.AsSpan(); if (pngMetaData.ColorType.Equals(PngColorType.Rgb)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit) { Rgb48 rgb = pngMetaData.TransparentRgb48.Value; @@ -770,7 +770,7 @@ namespace SixLabors.ImageSharp.Formats.Png BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } else if (pngMetaData.TransparentRgb24.HasValue) { @@ -779,22 +779,21 @@ namespace SixLabors.ImageSharp.Formats.Png alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 6); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); } } else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale)) { - Span alpha = this.buffer.AsSpan(); if (pngMetaData.TransparentGray16.HasValue && this.use16Bit) { BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue); - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } else if (pngMetaData.TransparentGray8.HasValue) { alpha.Clear(); alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue; - this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2); + this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); } } } diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 6a293f770..d5ab3d255 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Png this.BitDepth = other.BitDepth; this.ColorType = other.ColorType; this.Gamma = other.Gamma; + this.HasTrans = other.HasTrans; + this.TransparentGray8 = other.TransparentGray8; + this.TransparentGray16 = other.TransparentGray16; + this.TransparentRgb24 = other.TransparentRgb24; + this.TransparentRgb48 = other.TransparentRgb48; } /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 5d328db36..9079b15fb 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -25,6 +25,18 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { TestImages.Png.Bpp1, PngBitDepth.Bit1 } }; + public static readonly TheoryData PngTrnsFiles = + new TheoryData + { + { TestImages.Png.Gray1BitTrans, PngBitDepth.Bit1, PngColorType.Grayscale }, + { TestImages.Png.Gray2BitTrans, PngBitDepth.Bit2, PngColorType.Grayscale }, + { TestImages.Png.Gray4BitTrans, PngBitDepth.Bit4, PngColorType.Grayscale }, + { TestImages.Png.Gray8BitTrans, PngBitDepth.Bit8, PngColorType.Grayscale }, + { TestImages.Png.GrayTrns16BitInterlaced, PngBitDepth.Bit16, PngColorType.Grayscale }, + { TestImages.Png.Rgb24BppTrans, PngBitDepth.Bit8, PngColorType.Rgb }, + { TestImages.Png.Rgb48BppTrans, PngBitDepth.Bit16, PngColorType.Rgb } + }; + /// /// All types except Palette /// @@ -249,6 +261,61 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } + [Theory] + [MemberData(nameof(PngTrnsFiles))] + public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) + { + var options = new PngEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + PngMetaData inMeta = input.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(inMeta.HasTrans); + + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PngMetaData outMeta = output.MetaData.GetFormatMetaData(PngFormat.Instance); + Assert.True(outMeta.HasTrans); + + switch (pngColorType) + { + case PngColorType.Grayscale: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentGray16.HasValue); + Assert.Equal(inMeta.TransparentGray16, outMeta.TransparentGray16); + } + else + { + Assert.True(outMeta.TransparentGray8.HasValue); + Assert.Equal(inMeta.TransparentGray8, outMeta.TransparentGray8); + } + + break; + case PngColorType.Rgb: + if (pngBitDepth.Equals(PngBitDepth.Bit16)) + { + Assert.True(outMeta.TransparentRgb48.HasValue); + Assert.Equal(inMeta.TransparentRgb48, outMeta.TransparentRgb48); + } + else + { + Assert.True(outMeta.TransparentRgb24.HasValue); + Assert.Equal(inMeta.TransparentRgb24, outMeta.TransparentRgb24); + } + + break; + } + } + } + } + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8da458e52..1144a3f7c 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -46,6 +46,9 @@ namespace SixLabors.ImageSharp.Tests public const string PDSrc = "Png/pd-source.png"; public const string PDDest = "Png/pd-dest.png"; public const string Gray1BitTrans = "Png/gray-1-trns.png"; + public const string Gray2BitTrans = "Png/gray-2-tRNS.png"; + public const string Gray4BitTrans = "Png/gray-4-tRNS.png"; + public const string Gray8BitTrans = "Png/gray-8-tRNS.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/gray-2-tRNS.png b/tests/Images/Input/Png/gray-2-tRNS.png new file mode 100644 index 000000000..d5657ac34 --- /dev/null +++ b/tests/Images/Input/Png/gray-2-tRNS.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c36d10c8498bbe148bc44d41e0243137e47b07402dfb8e58978d1a9b5029cabc +size 265 diff --git a/tests/Images/Input/Png/gray-4-tRNS.png b/tests/Images/Input/Png/gray-4-tRNS.png new file mode 100644 index 000000000..01c1b6992 --- /dev/null +++ b/tests/Images/Input/Png/gray-4-tRNS.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:217248c079a0ed7896803a2bf5d9719b6060ef898314a5f6ab898c6c4349f341 +size 267 diff --git a/tests/Images/Input/Png/gray-8-tRNS.png b/tests/Images/Input/Png/gray-8-tRNS.png new file mode 100644 index 000000000..9b0b78ce5 --- /dev/null +++ b/tests/Images/Input/Png/gray-8-tRNS.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6e14dce9350fc40f7ee542d1dc788fbf6c1c0178515ea8b76ffa0b18bcf54e8a +size 267