diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs
index 7654c1701..1b251a574 100644
--- a/src/ImageSharp/Formats/Png/PngChunkType.cs
+++ b/src/ImageSharp/Formats/Png/PngChunkType.cs
@@ -56,10 +56,10 @@ namespace SixLabors.ImageSharp.Formats.Png
Text = 0x74455874U,
///
- /// This chunk specifies that the image uses simple transparency:
+ /// The tRNS chunk specifies that the image uses simple transparency:
/// either alpha values associated with palette entries (for indexed-color images)
/// or a single transparent color (for grayscale and true color images).
///
- PaletteAlpha = 0x74524E53U
+ Transparency = 0x74524E53U
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
index 11c4d831b..9ffac5e62 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -124,31 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png
///
private PngColorType pngColorType;
- ///
- /// Represents any color in an 8 bit Rgb24 encoded png that should be transparent
- ///
- private Rgb24 rgb24Trans;
-
- ///
- /// Represents any color in a 16 bit Rgb24 encoded png that should be transparent
- ///
- private Rgb48 rgb48Trans;
-
- ///
- /// Represents any color in an 8 bit grayscale encoded png that should be transparent
- ///
- private byte luminanceTrans;
-
- ///
- /// Represents any color in a 16 bit grayscale encoded png that should be transparent
- ///
- private ushort luminance16Trans;
-
- ///
- /// Whether the image has transparency chunk and markers were decoded
- ///
- private bool hasTrans;
-
///
/// The next chunk of data to return
///
@@ -213,7 +188,7 @@ namespace SixLabors.ImageSharp.Formats.Png
using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk))
{
deframeStream.AllocateNewBytes(chunk.Length);
- this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame);
+ this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame, pngMetaData);
}
break;
@@ -222,11 +197,11 @@ namespace SixLabors.ImageSharp.Formats.Png
Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length);
this.palette = pal;
break;
- case PngChunkType.PaletteAlpha:
+ case PngChunkType.Transparency:
byte[] alpha = new byte[chunk.Length];
Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length);
this.paletteAlpha = alpha;
- this.AssignTransparentMarkers(alpha);
+ this.AssignTransparentMarkers(alpha, pngMetaData);
break;
case PngChunkType.Text:
this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length));
@@ -496,16 +471,17 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The containing data.
/// The pixel data.
- private void ReadScanlines(Stream dataStream, ImageFrame image)
+ /// The png meta data
+ private void ReadScanlines(Stream dataStream, ImageFrame image, PngMetaData pngMetaData)
where TPixel : struct, IPixel
{
if (this.header.InterlaceMethod == PngInterlaceMode.Adam7)
{
- this.DecodeInterlacedPixelData(dataStream, image);
+ this.DecodeInterlacedPixelData(dataStream, image, pngMetaData);
}
else
{
- this.DecodePixelData(dataStream, image);
+ this.DecodePixelData(dataStream, image, pngMetaData);
}
}
@@ -515,7 +491,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The compressed pixel data stream.
/// The image to decode to.
- private void DecodePixelData(Stream compressedStream, ImageFrame image)
+ /// The png meta data
+ private void DecodePixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData)
where TPixel : struct, IPixel
{
while (this.currentRow < this.header.Height)
@@ -555,7 +532,7 @@ namespace SixLabors.ImageSharp.Formats.Png
throw new ImageFormatException("Unknown filter type.");
}
- this.ProcessDefilteredScanline(scanlineSpan, image);
+ this.ProcessDefilteredScanline(scanlineSpan, image, pngMetaData);
this.SwapBuffers();
this.currentRow++;
@@ -569,7 +546,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The compressed pixel data stream.
/// The current image.
- private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image)
+ /// The png meta data
+ private void DecodeInterlacedPixelData(Stream compressedStream, ImageFrame image, PngMetaData pngMetaData)
where TPixel : struct, IPixel
{
while (true)
@@ -626,7 +604,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
Span rowSpan = image.GetPixelRowSpan(this.currentRow);
- this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]);
+ this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, pngMetaData, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]);
this.SwapBuffers();
@@ -654,7 +632,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The de-filtered scanline
/// The image
- private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels)
+ /// The png meta data
+ private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels, PngMetaData pngMetaData)
where TPixel : struct, IPixel
{
Span rowSpan = pixels.GetPixelRowSpan(this.currentRow);
@@ -674,9 +653,9 @@ namespace SixLabors.ImageSharp.Formats.Png
this.header,
scanlineSpan,
rowSpan,
- this.hasTrans,
- this.luminance16Trans,
- this.luminanceTrans);
+ pngMetaData.HasTrans,
+ pngMetaData.TransparentGray16.GetValueOrDefault(),
+ pngMetaData.TransparentGray8.GetValueOrDefault());
break;
@@ -708,9 +687,9 @@ namespace SixLabors.ImageSharp.Formats.Png
rowSpan,
this.bytesPerPixel,
this.bytesPerSample,
- this.hasTrans,
- this.rgb48Trans,
- this.rgb24Trans);
+ pngMetaData.HasTrans,
+ pngMetaData.TransparentRgb48.GetValueOrDefault(),
+ pngMetaData.TransparentRgb24.GetValueOrDefault());
break;
@@ -735,9 +714,10 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The pixel format.
/// The de-filtered scanline
/// The current image row.
+ /// The png meta data
/// The column start index. Always 0 for none interlaced images.
/// The column increment. Always 1 for none interlaced images.
- private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1)
+ private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, PngMetaData pngMetaData, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel
{
// Trim the first marker byte from the buffer
@@ -757,9 +737,9 @@ namespace SixLabors.ImageSharp.Formats.Png
rowSpan,
pixelOffset,
increment,
- this.hasTrans,
- this.luminance16Trans,
- this.luminanceTrans);
+ pngMetaData.HasTrans,
+ pngMetaData.TransparentGray16.GetValueOrDefault(),
+ pngMetaData.TransparentGray8.GetValueOrDefault());
break;
@@ -796,9 +776,9 @@ namespace SixLabors.ImageSharp.Formats.Png
increment,
this.bytesPerPixel,
this.bytesPerSample,
- this.hasTrans,
- this.rgb48Trans,
- this.rgb24Trans);
+ pngMetaData.HasTrans,
+ pngMetaData.TransparentRgb48.GetValueOrDefault(),
+ pngMetaData.TransparentRgb24.GetValueOrDefault());
break;
@@ -822,7 +802,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Decodes and assigns marker colors that identify transparent pixels in non indexed images
///
/// The alpha tRNS array
- private void AssignTransparentMarkers(ReadOnlySpan alpha)
+ /// The png meta data
+ private void AssignTransparentMarkers(ReadOnlySpan alpha, PngMetaData pngMetaData)
{
if (this.pngColorType == PngColorType.Rgb)
{
@@ -834,16 +815,16 @@ namespace SixLabors.ImageSharp.Formats.Png
ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2));
ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2));
- this.rgb48Trans = new Rgb48(rc, gc, bc);
- this.hasTrans = true;
+ pngMetaData.TransparentRgb48 = new Rgb48(rc, gc, bc);
+ pngMetaData.HasTrans = true;
return;
}
byte r = ReadByteLittleEndian(alpha, 0);
byte g = ReadByteLittleEndian(alpha, 2);
byte b = ReadByteLittleEndian(alpha, 4);
- this.rgb24Trans = new Rgb24(r, g, b);
- this.hasTrans = true;
+ pngMetaData.TransparentRgb24 = new Rgb24(r, g, b);
+ pngMetaData.HasTrans = true;
}
}
else if (this.pngColorType == PngColorType.Grayscale)
@@ -852,14 +833,14 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (this.header.BitDepth == 16)
{
- this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2));
+ pngMetaData.TransparentGray16 = new Gray16(BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)));
}
else
{
- this.luminanceTrans = ReadByteLittleEndian(alpha, 0);
+ pngMetaData.TransparentGray8 = new Gray8(ReadByteLittleEndian(alpha, 0));
}
- this.hasTrans = true;
+ pngMetaData.HasTrans = true;
}
}
}
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 468f619b9..292de007c 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -290,6 +290,11 @@ namespace SixLabors.ImageSharp.Formats.Png
this.WritePaletteChunk(stream, quantized);
}
+ if (pngMetaData.HasTrans)
+ {
+ this.WriteTransparencyChunk(stream, pngMetaData);
+ }
+
this.WritePhysicalChunk(stream, metaData);
this.WriteGammaChunk(stream);
this.WriteExifChunk(stream, metaData);
@@ -326,7 +331,6 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.pngColorType.Equals(PngColorType.Grayscale))
{
- // TODO: Research and add support for grayscale plus tRNS
if (this.use16Bit)
{
// 16 bit grayscale
@@ -701,7 +705,7 @@ namespace SixLabors.ImageSharp.Formats.Png
// Write the transparency data
if (anyAlpha)
{
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength);
+ this.WriteChunk(stream, PngChunkType.Transparency, alphaTable.Array, 0, paletteLength);
}
}
}
@@ -749,6 +753,51 @@ namespace SixLabors.ImageSharp.Formats.Png
}
}
+ ///
+ /// Writes the transparency chunk to the stream
+ ///
+ /// The containing image data.
+ /// The image meta data.
+ private void WriteTransparencyChunk(Stream stream, PngMetaData pngMetaData)
+ {
+ Span alpha = this.chunkDataBuffer.AsSpan();
+ if (pngMetaData.ColorType.Equals(PngColorType.Rgb))
+ {
+ if (pngMetaData.TransparentRgb48.HasValue && this.use16Bit)
+ {
+ Rgb48 rgb = pngMetaData.TransparentRgb48.Value;
+ BinaryPrimitives.WriteUInt16LittleEndian(alpha, rgb.R);
+ BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G);
+ BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B);
+
+ this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6);
+ }
+ else if (pngMetaData.TransparentRgb24.HasValue)
+ {
+ alpha.Clear();
+ Rgb24 rgb = pngMetaData.TransparentRgb24.Value;
+ alpha[1] = rgb.R;
+ alpha[3] = rgb.G;
+ alpha[5] = rgb.B;
+ this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6);
+ }
+ }
+ else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale))
+ {
+ if (pngMetaData.TransparentGray16.HasValue && this.use16Bit)
+ {
+ BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue);
+ 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.chunkDataBuffer, 0, 2);
+ }
+ }
+ }
+
///
/// Writes the pixel information to the stream.
///
@@ -947,4 +996,4 @@ namespace SixLabors.ImageSharp.Formats.Png
return scanlineLength / mod;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs
index 9c7676514..d5ab3d255 100644
--- a/src/ImageSharp/Formats/Png/PngMetaData.cs
+++ b/src/ImageSharp/Formats/Png/PngMetaData.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using SixLabors.ImageSharp.PixelFormats;
+
namespace SixLabors.ImageSharp.Formats.Png
{
///
@@ -24,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;
}
///
@@ -42,6 +49,31 @@ namespace SixLabors.ImageSharp.Formats.Png
///
public float Gamma { get; set; }
+ ///
+ /// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent
+ ///
+ public Rgb24? TransparentRgb24 { get; set; }
+
+ ///
+ /// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent
+ ///
+ public Rgb48? TransparentRgb48 { get; set; }
+
+ ///
+ /// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent
+ ///
+ public Gray8? TransparentGray8 { get; set; }
+
+ ///
+ /// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent
+ ///
+ public Gray16? TransparentGray16 { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded
+ ///
+ public bool HasTrans { get; set; }
+
///
public IDeepCloneable DeepClone() => new PngMetaData(this);
}
diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
index 420775eca..4242b2d55 100644
--- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
+++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
@@ -20,8 +20,8 @@ namespace SixLabors.ImageSharp.Formats.Png
ReadOnlySpan scanlineSpan,
Span rowSpan,
bool hasTrans,
- ushort luminance16Trans,
- byte luminanceTrans)
+ Gray16 luminance16Trans,
+ Gray8 luminanceTrans)
where TPixel : struct, IPixel
{
TPixel pixel = default;
@@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Formats.Png
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
- rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue;
+ rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
pixel.FromRgba64(rgba64);
Unsafe.Add(ref rowSpanRef, x) = pixel;
@@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
- byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor);
+ byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
Rgba32 rgba32 = default;
for (int x = 0; x < header.Width; x++)
{
@@ -93,8 +93,8 @@ namespace SixLabors.ImageSharp.Formats.Png
int pixelOffset,
int increment,
bool hasTrans,
- ushort luminance16Trans,
- byte luminanceTrans)
+ Gray16 luminance16Trans,
+ Gray8 luminanceTrans)
where TPixel : struct, IPixel
{
TPixel pixel = default;
@@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp.Formats.Png
rgba64.R = luminance;
rgba64.G = luminance;
rgba64.B = luminance;
- rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue;
+ rgba64.A = luminance.Equals(luminance16Trans.PackedValue) ? ushort.MinValue : ushort.MaxValue;
pixel.FromRgba64(rgba64);
Unsafe.Add(ref rowSpanRef, x) = pixel;
@@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
- byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor);
+ byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
Rgba32 rgba32 = default;
for (int x = pixelOffset; x < header.Width; x += increment)
{
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
index e4cd06ab1..894d902b7 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
@@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
Assert.Equal(PngChunkType.Palette, GetType("PLTE"));
Assert.Equal(PngChunkType.Data, GetType("IDAT"));
Assert.Equal(PngChunkType.End, GetType("IEND"));
- Assert.Equal(PngChunkType.PaletteAlpha, GetType("tRNS"));
+ Assert.Equal(PngChunkType.Transparency, GetType("tRNS"));
Assert.Equal(PngChunkType.Text, GetType("tEXt"));
Assert.Equal(PngChunkType.Gamma, GetType("gAMA"));
Assert.Equal(PngChunkType.Physical, GetType("pHYs"));
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
index 2a7d69616..6a0119f0f 100644
--- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
+++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs
@@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png
[Theory]
[InlineData((uint)PngChunkType.Gamma)] // gAMA
- [InlineData((uint)PngChunkType.PaletteAlpha)] // tRNS
+ [InlineData((uint)PngChunkType.Transparency)] // tRNS
[InlineData((uint)PngChunkType.Physical)] // pHYs: It's ok to test physical as we don't throw for duplicate chunks.
//[InlineData(PngChunkTypes.Text)] //TODO: Figure out how to test this
public void Decode_IncorrectCRCForNonCriticalChunk_ExceptionIsThrown(uint chunkType)
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..8e04cb502
Binary files /dev/null and b/tests/Images/Input/Png/gray-2-tRNS.png differ
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..14c4f1fb3
Binary files /dev/null and b/tests/Images/Input/Png/gray-4-tRNS.png differ
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..842245f1d
Binary files /dev/null and b/tests/Images/Input/Png/gray-8-tRNS.png differ