diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 11c4d831b0..024bd62216 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; @@ -226,7 +201,7 @@ namespace SixLabors.ImageSharp.Formats.Png 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)); @@ -331,7 +306,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); + { + return (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 @@ -496,16 +473,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 +493,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 +534,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 +548,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 +606,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 +634,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 +655,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.header, scanlineSpan, rowSpan, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -708,9 +689,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -735,9 +716,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 +739,9 @@ namespace SixLabors.ImageSharp.Formats.Png rowSpan, pixelOffset, increment, - this.hasTrans, - this.luminance16Trans, - this.luminanceTrans); + pngMetaData.HasTrans, + pngMetaData.Luminance16Trans, + pngMetaData.LuminanceTrans); break; @@ -796,9 +778,9 @@ namespace SixLabors.ImageSharp.Formats.Png increment, this.bytesPerPixel, this.bytesPerSample, - this.hasTrans, - this.rgb48Trans, - this.rgb24Trans); + pngMetaData.HasTrans, + pngMetaData.Rgb48Trans, + pngMetaData.Rgb24Trans); break; @@ -822,7 +804,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 +817,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.Rgb48Trans = 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.Rgb24Trans = new Rgb24(r, g, b); + pngMetaData.HasTrans = true; } } else if (this.pngColorType == PngColorType.Grayscale) @@ -852,14 +835,14 @@ namespace SixLabors.ImageSharp.Formats.Png { if (this.header.BitDepth == 16) { - this.luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); + pngMetaData.Luminance16Trans = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); } else { - this.luminanceTrans = ReadByteLittleEndian(alpha, 0); + pngMetaData.LuminanceTrans = 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 7ae716aa05..411d5d69b2 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) + { + //Write transparency header + } + this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metaData); diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..0014defbb9 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 { /// @@ -42,6 +44,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 Rgb24Trans { 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 Rgb48Trans { 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 byte LuminanceTrans { 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 ushort Luminance16Trans { 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/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 73549d98aa..ec9037479b 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.MetaData {