Browse Source

Fix png to gif transparency

pull/230/head
James Jackson-South 9 years ago
parent
commit
631545a756
  1. 55
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs

55
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -69,7 +69,7 @@ namespace ImageSharp.Formats
this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer<TPixel>(); this.Quantizer = this.options.Quantizer ?? new OctreeQuantizer<TPixel>();
// Do not use IDisposable pattern here as we want to preserve the stream. // Do not use IDisposable pattern here as we want to preserve the stream.
EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that quality can be set but has a fallback. // Ensure that quality can be set but has a fallback.
int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality; int quality = this.options.Quality > 0 ? this.options.Quality : image.MetaData.Quality;
@ -82,7 +82,7 @@ namespace ImageSharp.Formats
this.hasFrames = image.Frames.Any(); this.hasFrames = image.Frames.Any();
// Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames. // Dithering when animating gifs is a bad idea as we introduce pixel tearing across frames.
IQuantizer<TPixel> ditheredQuantizer = (IQuantizer<TPixel>)this.Quantizer; var ditheredQuantizer = (IQuantizer<TPixel>)this.Quantizer;
ditheredQuantizer.Dither = !this.hasFrames; ditheredQuantizer.Dither = !this.hasFrames;
QuantizedImage<TPixel> quantized = ditheredQuantizer.Quantize(image, quality); QuantizedImage<TPixel> quantized = ditheredQuantizer.Quantize(image, quality);
@ -96,7 +96,7 @@ namespace ImageSharp.Formats
this.WriteLogicalScreenDescriptor(image, writer, index); this.WriteLogicalScreenDescriptor(image, writer, index);
// Write the first frame. // Write the first frame.
this.WriteGraphicalControlExtension(image, writer, index); this.WriteGraphicalControlExtension(image.MetaData, writer, index);
this.WriteComments(image, writer); this.WriteComments(image, writer);
this.WriteImageDescriptor(image, writer); this.WriteImageDescriptor(image, writer);
this.WriteColorTable(quantized, writer); this.WriteColorTable(quantized, writer);
@ -113,7 +113,7 @@ namespace ImageSharp.Formats
ImageFrame<TPixel> frame = image.Frames[i]; ImageFrame<TPixel> frame = image.Frames[i];
QuantizedImage<TPixel> quantizedFrame = ditheredQuantizer.Quantize(frame, quality); QuantizedImage<TPixel> quantizedFrame = ditheredQuantizer.Quantize(frame, quality);
this.WriteGraphicalControlExtension(frame, writer, this.GetTransparentIndex(quantizedFrame)); this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantizedFrame));
this.WriteImageDescriptor(frame, writer); this.WriteImageDescriptor(frame, writer);
this.WriteColorTable(quantizedFrame, writer); this.WriteColorTable(quantizedFrame, writer);
this.WriteImageData(quantizedFrame, writer); this.WriteImageData(quantizedFrame, writer);
@ -187,7 +187,7 @@ namespace ImageSharp.Formats
private void WriteLogicalScreenDescriptor<TPixel>(Image<TPixel> image, EndianBinaryWriter writer, int tranparencyIndex) private void WriteLogicalScreenDescriptor<TPixel>(Image<TPixel> image, EndianBinaryWriter writer, int tranparencyIndex)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor var descriptor = new GifLogicalScreenDescriptor
{ {
Width = (short)image.Width, Width = (short)image.Width,
Height = (short)image.Height, Height = (short)image.Height,
@ -199,7 +199,7 @@ namespace ImageSharp.Formats
writer.Write((ushort)descriptor.Width); writer.Write((ushort)descriptor.Width);
writer.Write((ushort)descriptor.Height); writer.Write((ushort)descriptor.Height);
PackedField field = default(PackedField); var field = default(PackedField);
field.SetBit(0, descriptor.GlobalColorTableFlag); // 1 : Global color table flag = 1 || 0 (GCT used/ not used) field.SetBit(0, descriptor.GlobalColorTableFlag); // 1 : Global color table flag = 1 || 0 (GCT used/ not used)
field.SetBits(1, 3, descriptor.GlobalColorTableSize); // 2-4 : color resolution field.SetBits(1, 3, descriptor.GlobalColorTableSize); // 2-4 : color resolution
field.SetBit(4, false); // 5 : GCT sort flag = 0 field.SetBit(4, false); // 5 : GCT sort flag = 0
@ -251,7 +251,7 @@ namespace ImageSharp.Formats
private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer) private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.options.IgnoreMetadata == true) if (this.options.IgnoreMetadata)
{ {
return; return;
} }
@ -278,44 +278,15 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the graphics control extension to the stream. /// Writes the graphics control extension to the stream.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="Image{TPixel}"/> to encode.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TPixel>(Image<TPixel> image, EndianBinaryWriter writer, int transparencyIndex)
where TPixel : struct, IPixel<TPixel>
{
this.WriteGraphicalControlExtension(image, image.MetaData, writer, transparencyIndex);
}
/// <summary>
/// Writes the graphics control extension to the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="imageFrame">The <see cref="ImageFrame{TPixel}"/> to encode.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TPixel>(ImageFrame<TPixel> imageFrame, EndianBinaryWriter writer, int transparencyIndex)
where TPixel : struct, IPixel<TPixel>
{
this.WriteGraphicalControlExtension(imageFrame, imageFrame.MetaData, writer, transparencyIndex);
}
/// <summary>
/// Writes the graphics control extension to the stream.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TPixel}"/> to encode.</param>
/// <param name="metaData">The metadata of the image or frame.</param> /// <param name="metaData">The metadata of the image or frame.</param>
/// <param name="writer">The stream to write to.</param> /// <param name="writer">The stream to write to.</param>
/// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param> /// <param name="transparencyIndex">The index of the color in the color palette to make transparent.</param>
private void WriteGraphicalControlExtension<TPixel>(ImageBase<TPixel> image, IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex) private void WriteGraphicalControlExtension(IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex)
where TPixel : struct, IPixel<TPixel>
{ {
GifGraphicsControlExtension extension = new GifGraphicsControlExtension() var extension = new GifGraphicsControlExtension
{ {
DisposalMethod = metaData.DisposalMethod, DisposalMethod = metaData.DisposalMethod,
TransparencyFlag = transparencyIndex < 255, TransparencyFlag = true, // TODO: The spec here is unclear. Can we get away with this?
TransparencyIndex = transparencyIndex, TransparencyIndex = transparencyIndex,
DelayTime = metaData.FrameDelay DelayTime = metaData.FrameDelay
}; };
@ -326,7 +297,7 @@ namespace ImageSharp.Formats
this.buffer[2] = 4; this.buffer[2] = 4;
writer.Write(this.buffer, 0, 3); writer.Write(this.buffer, 0, 3);
PackedField field = default(PackedField); var field = default(PackedField);
field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal
// TODO: Allow this as an option. // TODO: Allow this as an option.
@ -356,7 +327,7 @@ namespace ImageSharp.Formats
writer.Write((ushort)image.Width); writer.Write((ushort)image.Width);
writer.Write((ushort)image.Height); writer.Write((ushort)image.Height);
PackedField field = default(PackedField); var field = default(PackedField);
field.SetBit(0, true); // 1: Local color table flag = 1 (LCT used) field.SetBit(0, true); // 1: Local color table flag = 1 (LCT used)
field.SetBit(1, false); // 2: Interlace flag 0 field.SetBit(1, false); // 2: Interlace flag 0
field.SetBit(2, false); // 3: Sort flag 0 field.SetBit(2, false); // 3: Sort flag 0
@ -409,7 +380,7 @@ namespace ImageSharp.Formats
private void WriteImageData<TPixel>(QuantizedImage<TPixel> image, EndianBinaryWriter writer) private void WriteImageData<TPixel>(QuantizedImage<TPixel> image, EndianBinaryWriter writer)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
using (LzwEncoder encoder = new LzwEncoder(image.Pixels, (byte)this.bitDepth)) using (var encoder = new LzwEncoder(image.Pixels, (byte)this.bitDepth))
{ {
encoder.Encode(writer.BaseStream); encoder.Encode(writer.BaseStream);
} }

Loading…
Cancel
Save