Browse Source

Make GifGraphicsControlExtension a struct

af/merge-core
Jason Nelson 8 years ago
parent
commit
149a0ccffc
  1. 30
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 38
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  3. 84
      src/ImageSharp/Formats/Gif/Sections/GifGraphicsControlExtension.cs

30
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -241,13 +241,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
byte packed = this.buffer[1];
this.graphicsControlExtension = new GifGraphicsControlExtension
{
DelayTime = BitConverter.ToInt16(this.buffer, 2),
TransparencyIndex = this.buffer[4],
TransparencyFlag = (packed & 0x01) == 1,
DisposalMethod = (DisposalMethod)((packed & 0x1C) >> 2)
};
this.graphicsControlExtension = GifGraphicsControlExtension.Parse(this.buffer);
}
/// <summary>
@ -430,8 +424,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious)
{
prevFrame = previousFrame;
}
@ -494,8 +487,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
int index = Unsafe.Add(ref indicesRef, i);
if (this.graphicsControlExtension == null ||
this.graphicsControlExtension.TransparencyFlag == false ||
if (this.graphicsControlExtension.TransparencyFlag == false ||
this.graphicsControlExtension.TransparencyIndex != index)
{
int indexOffset = index * 3;
@ -518,8 +510,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
previousFrame = currentFrame ?? image.Frames.RootFrame;
if (this.graphicsControlExtension != null &&
this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground)
{
this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height);
}
@ -550,16 +541,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="meta">The meta data.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetFrameMetaData(ImageFrameMetaData meta)
{
if (this.graphicsControlExtension != null)
{
if (this.graphicsControlExtension.DelayTime > 0)
{
if (this.graphicsControlExtension.DelayTime > 0)
{
meta.FrameDelay = this.graphicsControlExtension.DelayTime;
}
meta.DisposalMethod = this.graphicsControlExtension.DisposalMethod;
meta.FrameDelay = this.graphicsControlExtension.DelayTime;
}
meta.DisposalMethod = this.graphicsControlExtension.DisposalMethod;
}
/// <summary>

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

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
}
this.WriteGraphicalControlExtension(frame.MetaData, writer, this.GetTransparentIndex(quantized));
this.WriteGraphicalControlExtension(frame.MetaData, stream, this.GetTransparentIndex(quantized));
this.WriteImageDescriptor(frame, writer);
this.WriteColorTable(quantized, writer);
this.WriteImageData(quantized, writer);
@ -261,35 +261,21 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Writes the graphics control extension to the stream.
/// </summary>
/// <param name="metaData">The metadata of the image or frame.</param>
/// <param name="writer">The stream to write to.</param>
/// <param name="stream">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(ImageFrameMetaData metaData, EndianBinaryWriter writer, int transparencyIndex)
private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, Stream stream, int transparencyIndex)
{
var extension = new GifGraphicsControlExtension
{
DisposalMethod = metaData.DisposalMethod,
TransparencyFlag = transparencyIndex > -1,
TransparencyIndex = unchecked((byte)transparencyIndex),
DelayTime = metaData.FrameDelay
};
// Write the intro.
this.buffer[0] = GifConstants.ExtensionIntroducer;
this.buffer[1] = GifConstants.GraphicControlLabel;
this.buffer[2] = 4;
writer.Write(this.buffer, 0, 3);
var field = default(PackedField);
field.SetBits(3, 3, (int)extension.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal
var extension = new GifGraphicsControlExtension(
disposalMethod: metaData.DisposalMethod,
transparencyFlag: transparencyIndex > -1,
transparencyIndex: unchecked((byte)transparencyIndex),
delayTime: (ushort)metaData.FrameDelay
);
// TODO: Allow this as an option.
field.SetBit(6, false); // 7 : User input - 0 = none
field.SetBit(7, extension.TransparencyFlag); // 8: Has transparent.
extension.WriteTo(this.buffer);
writer.Write(field.Byte);
writer.Write((ushort)extension.DelayTime);
writer.Write(extension.TransparencyIndex);
writer.Write(GifConstants.Terminator);
stream.Write(this.buffer, 0, GifGraphicsControlExtension.Size);
}
/// <summary>

84
src/ImageSharp/Formats/Gif/Sections/GifGraphicsControlExtension.cs

@ -1,40 +1,94 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
namespace SixLabors.ImageSharp.Formats.Gif
{
/// <summary>
/// The Graphic Control Extension contains parameters used when
/// processing a graphic rendering block.
/// </summary>
internal sealed class GifGraphicsControlExtension
internal readonly struct GifGraphicsControlExtension
{
public const int Size = 8;
public GifGraphicsControlExtension(
DisposalMethod disposalMethod,
bool transparencyFlag,
ushort delayTime,
byte transparencyIndex)
{
this.DisposalMethod = disposalMethod;
this.TransparencyFlag = transparencyFlag;
this.DelayTime = delayTime;
this.TransparencyIndex = transparencyIndex;
}
/// <summary>
/// Gets or sets the disposal method which indicates the way in which the
/// Gets the disposal method which indicates the way in which the
/// graphic is to be treated after being displayed.
/// </summary>
public DisposalMethod DisposalMethod { get; set; }
public DisposalMethod DisposalMethod { get; }
/// <summary>
/// Gets or sets a value indicating whether transparency flag is to be set.
/// Gets a value indicating whether transparency flag is to be set.
/// This indicates whether a transparency index is given in the Transparent Index field.
/// (This field is the least significant bit of the byte.)
/// </summary>
public bool TransparencyFlag { get; set; }
/// <summary>
/// Gets or sets the transparency index.
/// The Transparency Index is such that when encountered, the corresponding pixel
/// of the display device is not modified and processing goes on to the next pixel.
/// </summary>
public byte TransparencyIndex { get; set; }
public bool TransparencyFlag { get; }
/// <summary>
/// Gets or sets the delay time.
/// Gets the delay time.
/// If not 0, this field specifies the number of hundredths (1/100) of a second to
/// wait before continuing with the processing of the Data Stream.
/// The clock starts ticking immediately after the graphic is rendered.
/// </summary>
public int DelayTime { get; set; }
public ushort DelayTime { get; }
/// <summary>
/// Gets the transparency index.
/// The Transparency Index is such that when encountered, the corresponding pixel
/// of the display device is not modified and processing goes on to the next pixel.
/// </summary>
public byte TransparencyIndex { get; }
public byte PackField()
{
PackedField field = default;
field.SetBits(3, 3, (int)this.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal
// TODO: Allow this as an option.
field.SetBit(6, false); // 7 : User input - 0 = none
field.SetBit(7, this.TransparencyFlag); // 8: Has transparent.
return field.Byte;
}
public void WriteTo(Span<byte> buffer)
{
buffer[0] = GifConstants.ExtensionIntroducer;
buffer[1] = GifConstants.GraphicControlLabel;
buffer[2] = 4; // Block Size
buffer[3] = this.PackField(); // Packed Field
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(4, 2), this.DelayTime); // Delay Time
buffer[6] = this.TransparencyIndex;
buffer[7] = GifConstants.Terminator;
}
public static GifGraphicsControlExtension Parse(ReadOnlySpan<byte> buffer)
{
// We've already read the Extension Introducer introducer & Graphic Control Label
// Start from the block size (0)
byte packed = buffer[1];
return new GifGraphicsControlExtension(
disposalMethod: (DisposalMethod)((packed & 0x1C) >> 2),
delayTime: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(2, 2)),
transparencyIndex: buffer[4],
transparencyFlag: (packed & 0x01) == 1);
}
}
}
}
Loading…
Cancel
Save