Browse Source

Work in progress preserving isTrans data

pull/764/head
Devedse 8 years ago
parent
commit
b798d8dc01
  1. 97
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  2. 5
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  3. 27
      src/ImageSharp/Formats/Png/PngMetaData.cs
  4. 1
      src/ImageSharp/MetaData/ImageMetaData.cs

97
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -124,31 +124,6 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary>
private PngColorType pngColorType;
/// <summary>
/// Represents any color in an 8 bit Rgb24 encoded png that should be transparent
/// </summary>
private Rgb24 rgb24Trans;
/// <summary>
/// Represents any color in a 16 bit Rgb24 encoded png that should be transparent
/// </summary>
private Rgb48 rgb48Trans;
/// <summary>
/// Represents any color in an 8 bit grayscale encoded png that should be transparent
/// </summary>
private byte luminanceTrans;
/// <summary>
/// Represents any color in a 16 bit grayscale encoded png that should be transparent
/// </summary>
private ushort luminance16Trans;
/// <summary>
/// Whether the image has transparency chunk and markers were decoded
/// </summary>
private bool hasTrans;
/// <summary>
/// The next chunk of data to return
/// </summary>
@ -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
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte ReadByteLittleEndian(ReadOnlySpan<byte> buffer, int offset)
=> (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
{
return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF));
}
/// <summary>
/// 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
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="dataStream">The <see cref="MemoryStream"/> containing data.</param>
/// <param name="image"> The pixel data.</param>
private void ReadScanlines<TPixel>(Stream dataStream, ImageFrame<TPixel> image)
/// <param name="pngMetaData">The png meta data</param>
private void ReadScanlines<TPixel>(Stream dataStream, ImageFrame<TPixel> image, PngMetaData pngMetaData)
where TPixel : struct, IPixel<TPixel>
{
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
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="compressedStream">The compressed pixel data stream.</param>
/// <param name="image">The image to decode to.</param>
private void DecodePixelData<TPixel>(Stream compressedStream, ImageFrame<TPixel> image)
/// <param name="pngMetaData">The png meta data</param>
private void DecodePixelData<TPixel>(Stream compressedStream, ImageFrame<TPixel> image, PngMetaData pngMetaData)
where TPixel : struct, IPixel<TPixel>
{
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
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="compressedStream">The compressed pixel data stream.</param>
/// <param name="image">The current image.</param>
private void DecodeInterlacedPixelData<TPixel>(Stream compressedStream, ImageFrame<TPixel> image)
/// <param name="pngMetaData">The png meta data</param>
private void DecodeInterlacedPixelData<TPixel>(Stream compressedStream, ImageFrame<TPixel> image, PngMetaData pngMetaData)
where TPixel : struct, IPixel<TPixel>
{
while (true)
@ -626,7 +606,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
Span<TPixel> 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
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="defilteredScanline">The de-filtered scanline</param>
/// <param name="pixels">The image</param>
private void ProcessDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, ImageFrame<TPixel> pixels)
/// <param name="pngMetaData">The png meta data</param>
private void ProcessDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, ImageFrame<TPixel> pixels, PngMetaData pngMetaData)
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> 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
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="defilteredScanline">The de-filtered scanline</param>
/// <param name="rowSpan">The current image row.</param>
/// <param name="pngMetaData">The png meta data</param>
/// <param name="pixelOffset">The column start index. Always 0 for none interlaced images.</param>
/// <param name="increment">The column increment. Always 1 for none interlaced images.</param>
private void ProcessInterlacedDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, Span<TPixel> rowSpan, int pixelOffset = 0, int increment = 1)
private void ProcessInterlacedDefilteredScanline<TPixel>(ReadOnlySpan<byte> defilteredScanline, Span<TPixel> rowSpan, PngMetaData pngMetaData, int pixelOffset = 0, int increment = 1)
where TPixel : struct, IPixel<TPixel>
{
// 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
/// </summary>
/// <param name="alpha">The alpha tRNS array</param>
private void AssignTransparentMarkers(ReadOnlySpan<byte> alpha)
/// <param name="pngMetaData">The png meta data</param>
private void AssignTransparentMarkers(ReadOnlySpan<byte> 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;
}
}
}

5
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);

27
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
{
/// <summary>
@ -42,6 +44,31 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary>
public float Gamma { get; set; }
/// <summary>
/// Gets or sets the Rgb 24 transparent color. This represents any color in an 8 bit Rgb24 encoded png that should be transparent
/// </summary>
public Rgb24 Rgb24Trans { get; set; }
/// <summary>
/// Gets or sets the Rgb 48 transparent color. This represents any color in a 16 bit Rgb24 encoded png that should be transparent
/// </summary>
public Rgb48 Rgb48Trans { get; set; }
/// <summary>
/// Gets or sets the 8 bit grayscale transparent color. This represents any color in an 8 bit grayscale encoded png that should be transparent
/// </summary>
public byte LuminanceTrans { get; set; }
/// <summary>
/// Gets or sets the 16 bit grayscale transparent color. This represents any color in a 16 bit grayscale encoded png that should be transparent
/// </summary>
public ushort Luminance16Trans { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the image has transparency chunk and markers were decoded
/// </summary>
public bool HasTrans { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new PngMetaData(this);
}

1
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
{

Loading…
Cancel
Save