Browse Source

Introduce IGifExtension interface

af/merge-core
Jason Nelson 8 years ago
parent
commit
29d31733d3
  1. 26
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  2. 81
      src/ImageSharp/Formats/Gif/Sections/GifGraphicsControlExtension.cs
  3. 22
      src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs

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

@ -254,15 +254,33 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <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(ImageFrameMetaData metaData, Stream stream, int transparencyIndex) private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, Stream stream, int transparencyIndex)
{ {
var extension = new GifGraphicsControlExtension( byte packedValue = GifGraphicsControlExtension.GetPackedValue(
disposalMethod: metaData.DisposalMethod, disposalMethod: metaData.DisposalMethod,
transparencyFlag: transparencyIndex > -1, transparencyFlag: transparencyIndex > -1);
var extension = new GifGraphicsControlExtension(
packed: packedValue,
transparencyIndex: unchecked((byte)transparencyIndex), transparencyIndex: unchecked((byte)transparencyIndex),
delayTime: (ushort)metaData.FrameDelay); delayTime: (ushort)metaData.FrameDelay);
extension.WriteTo(this.buffer); this.WriteExtension(extension, stream);
}
/// <summary>
/// Writes the provided extension to the stream.
/// </summary>
/// <param name="extension">The extension to write to the stream.</param>
/// <param name="stream">The stream to write to.</param>
public void WriteExtension(IGifExtension extension, Stream stream)
{
this.buffer[0] = GifConstants.ExtensionIntroducer;
this.buffer[1] = extension.Label;
int extensionSize = extension.WriteTo(this.buffer.AsSpan(2));
this.buffer[extensionSize + 2] = GifConstants.Terminator;
stream.Write(this.buffer, 0, GifGraphicsControlExtension.Size); stream.Write(this.buffer, 0, 8);
} }
/// <summary> /// <summary>

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

@ -3,6 +3,8 @@
using System; using System;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Gif namespace SixLabors.ImageSharp.Formats.Gif
{ {
@ -10,34 +12,31 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The Graphic Control Extension contains parameters used when /// The Graphic Control Extension contains parameters used when
/// processing a graphic rendering block. /// processing a graphic rendering block.
/// </summary> /// </summary>
internal readonly struct GifGraphicsControlExtension [StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct GifGraphicsControlExtension : IGifExtension
{ {
public const int Size = 8; public const int Size = 4;
public GifGraphicsControlExtension( public GifGraphicsControlExtension(
DisposalMethod disposalMethod, byte packed,
bool transparencyFlag,
ushort delayTime, ushort delayTime,
byte transparencyIndex) byte transparencyIndex)
{ {
this.DisposalMethod = disposalMethod; this.BlockSize = 4;
this.TransparencyFlag = transparencyFlag; this.Packed = packed;
this.DelayTime = delayTime; this.DelayTime = delayTime;
this.TransparencyIndex = transparencyIndex; this.TransparencyIndex = transparencyIndex;
} }
/// <summary> /// <summary>
/// Gets the disposal method which indicates the way in which the /// Gets the size of the block.
/// graphic is to be treated after being displayed.
/// </summary> /// </summary>
public DisposalMethod DisposalMethod { get; } public int BlockSize { get; }
/// <summary> /// <summary>
/// Gets a value indicating whether transparency flag is to be set. /// Gets the packed disposalMethod and transparencyFlag value.
/// This indicates whether a transparency index is given in the Transparent Index field.
/// (This field is the least significant bit of the byte.)
/// </summary> /// </summary>
public bool TransparencyFlag { get; } public byte Packed { get; }
/// <summary> /// <summary>
/// Gets the delay time. /// Gets the delay time.
@ -54,41 +53,45 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary> /// </summary>
public byte TransparencyIndex { get; } public byte TransparencyIndex { get; }
public byte PackField() /// <summary>
{ /// Gets the disposal method which indicates the way in which the
PackedField field = default; /// graphic is to be treated after being displayed.
/// </summary>
public DisposalMethod DisposalMethod => (DisposalMethod)((this.Packed & 0x1C) >> 2);
/// <summary>
/// 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 => (this.Packed & 0x01) == 1;
field.SetBits(3, 3, (int)this.DisposalMethod); // 1-3 : Reserved, 4-6 : Disposal byte IGifExtension.Label => GifConstants.GraphicControlLabel;
// TODO: Allow this as an option. public int WriteTo(Span<byte> buffer)
field.SetBit(6, false); // 7 : User input - 0 = none {
field.SetBit(7, this.TransparencyFlag); // 8: Has transparent. ref GifGraphicsControlExtension dest = ref Unsafe.As<byte, GifGraphicsControlExtension>(ref MemoryMarshal.GetReference(buffer));
return field.Byte; dest = this;
return 5;
} }
public void WriteTo(Span<byte> buffer) public static GifGraphicsControlExtension Parse(ReadOnlySpan<byte> buffer)
{ {
buffer[0] = GifConstants.ExtensionIntroducer; return MemoryMarshal.Cast<byte, GifGraphicsControlExtension>(buffer)[0];
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) public static byte GetPackedValue(DisposalMethod disposalMethod, bool userInputFlag = false, bool transparencyFlag = false)
{ {
// We've already read the Extension Introducer introducer & Graphic Control Label PackedField field = default;
// Start from the block size (0)
byte packed = buffer[1]; // --------------------------------------- // Reserved | 3 bits
field.SetBits(3, 3, (int)disposalMethod); // Disposal Method | 3 bits
return new GifGraphicsControlExtension( field.SetBit(6, userInputFlag); // User Input Flag | 1 bit
disposalMethod: (DisposalMethod)((packed & 0x1C) >> 2), field.SetBit(7, transparencyFlag); // Transparent Color Flag | 1 bit
delayTime: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(2, 2)),
transparencyIndex: buffer[4], return field.Byte;
transparencyFlag: (packed & 0x01) == 1);
} }
} }
} }

22
src/ImageSharp/Formats/Gif/Sections/IGifExtension.cs

@ -0,0 +1,22 @@
using System;
namespace SixLabors.ImageSharp.Formats.Gif
{
/// <summary>
/// A base interface for GIF extensions.
/// </summary>
public interface IGifExtension
{
/// <summary>
/// Gets the label identifying the extensions.
/// </summary>
byte Label { get; }
/// <summary>
/// Writes the extension data to the buffer.
/// </summary>
/// <param name="buffer">The buffer to write the extension to.</param>
/// <returns>The number of bytes written to the buffer.</returns>
int WriteTo(Span<byte> buffer);
}
}
Loading…
Cancel
Save