diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs
index 7654c17014..1b251a5748 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 c446184d80..9ffac5e626 100644
--- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs
@@ -197,7 +197,7 @@ 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;
@@ -306,9 +306,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset)
- {
- return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
- }
+ => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
///
/// Attempts to convert a byte array to a new array where each value in the original array is represented by the
diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
index 532e6f7471..8a31aaf51b 100644
--- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs
+++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs
@@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (pngMetaData.HasTrans)
{
- this.WriteTransparencyMarkers(stream, pngMetaData);
+ this.WriteTransparencyChunk(stream, pngMetaData);
}
this.WritePhysicalChunk(stream, metaData);
@@ -305,52 +305,6 @@ namespace SixLabors.ImageSharp.Formats.Png
quantized?.Dispose();
}
- ///
- /// Writes the transparency markers to the stream
- ///
- /// The containing image data.
- /// The image meta data.
- private void WriteTransparencyMarkers(Stream stream, PngMetaData pngMetaData)
- {
- if (pngMetaData.ColorType == PngColorType.Rgb)
- {
- if (pngMetaData.TransparentRgb48 != null)
- {
- var r = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R);
- var g = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.R);
- var b = BitConverter.GetBytes(pngMetaData.TransparentRgb48.Value.B);
-
- var alphaArray = r.Concat(g).Concat(b).ToArray();
-
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length);
- }
- else if (pngMetaData.TransparentRgb24 != null)
- {
- var alphaArray = new byte[6];
- alphaArray[1] = pngMetaData.TransparentRgb24.Value.R;
- alphaArray[3] = pngMetaData.TransparentRgb24.Value.G;
- alphaArray[5] = pngMetaData.TransparentRgb24.Value.B;
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length);
- }
- }
- else if (pngMetaData.ColorType == PngColorType.Grayscale)
- {
- if (pngMetaData.TransparentGray16 != null)
- {
- var alphaArray = BitConverter.GetBytes(pngMetaData.TransparentGray16.Value.PackedValue);
-
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length);
- }
- else if (pngMetaData.TransparentGray8 != null)
- {
- var alphaArray = new byte[2];
- alphaArray[1] = pngMetaData.TransparentGray8.Value.PackedValue;
-
- this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaArray, 0, alphaArray.Length);
- }
- }
- }
-
///
public void Dispose()
{
@@ -377,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
@@ -752,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);
}
}
}
@@ -800,6 +753,52 @@ 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)
+ {
+ if (pngMetaData.ColorType.Equals(PngColorType.Rgb))
+ {
+ Span alpha = this.buffer.AsSpan();
+ 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.buffer, 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.buffer, 0, 6);
+ }
+ }
+ else if (pngMetaData.ColorType.Equals(PngColorType.Grayscale))
+ {
+ Span alpha = this.buffer.AsSpan();
+ if (pngMetaData.TransparentGray16.HasValue && this.bitDepth == 16)
+ {
+ BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetaData.TransparentGray16.Value.PackedValue);
+ this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2);
+ }
+ else if (pngMetaData.TransparentGray8.HasValue)
+ {
+ alpha.Clear();
+ alpha[1] = pngMetaData.TransparentGray8.Value.PackedValue;
+ this.WriteChunk(stream, PngChunkType.Transparency, this.buffer, 0, 2);
+ }
+ }
+ }
+
///
/// Writes the pixel information to the stream.
///
@@ -894,10 +893,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// Writes the chunk end to the stream.
///
/// The containing image data.
- private void WriteEndChunk(Stream stream)
- {
- this.WriteChunk(stream, PngChunkType.End, null);
- }
+ private void WriteEndChunk(Stream stream) => this.WriteChunk(stream, PngChunkType.End, null);
///
/// Writes a chunk to the stream.
@@ -905,10 +901,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// The to write to.
/// The type of chunk to write.
/// The containing data.
- private void WriteChunk(Stream stream, PngChunkType type, byte[] data)
- {
- this.WriteChunk(stream, type, data, 0, data?.Length ?? 0);
- }
+ private void WriteChunk(Stream stream, PngChunkType type, byte[] data) => this.WriteChunk(stream, type, data, 0, data?.Length ?? 0);
///
/// Writes a chunk of a specified length to the stream at the given offset.
diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs
index e4cd06ab1b..894d902b78 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 2a7d696164..6a0119f0f1 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)