Browse Source

Introduce IGifExtension interface

pull/536/head
Jason Nelson 8 years ago
parent
commit
1db5fd9bb1
  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>
private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, Stream stream, int transparencyIndex)
{
var extension = new GifGraphicsControlExtension(
byte packedValue = GifGraphicsControlExtension.GetPackedValue(
disposalMethod: metaData.DisposalMethod,
transparencyFlag: transparencyIndex > -1,
transparencyFlag: transparencyIndex > -1);
var extension = new GifGraphicsControlExtension(
packed: packedValue,
transparencyIndex: unchecked((byte)transparencyIndex),
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>

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

@ -3,6 +3,8 @@
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -10,34 +12,31 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// The Graphic Control Extension contains parameters used when
/// processing a graphic rendering block.
/// </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(
DisposalMethod disposalMethod,
bool transparencyFlag,
byte packed,
ushort delayTime,
byte transparencyIndex)
{
this.DisposalMethod = disposalMethod;
this.TransparencyFlag = transparencyFlag;
this.BlockSize = 4;
this.Packed = packed;
this.DelayTime = delayTime;
this.TransparencyIndex = transparencyIndex;
}
/// <summary>
/// Gets the disposal method which indicates the way in which the
/// graphic is to be treated after being displayed.
/// Gets the size of the block.
/// </summary>
public DisposalMethod DisposalMethod { get; }
public int BlockSize { get; }
/// <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.)
/// Gets the packed disposalMethod and transparencyFlag value.
/// </summary>
public bool TransparencyFlag { get; }
public byte Packed { get; }
/// <summary>
/// Gets the delay time.
@ -54,41 +53,45 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
public byte TransparencyIndex { get; }
public byte PackField()
{
PackedField field = default;
/// <summary>
/// Gets the disposal method which indicates the way in which the
/// 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.
field.SetBit(6, false); // 7 : User input - 0 = none
field.SetBit(7, this.TransparencyFlag); // 8: Has transparent.
public int WriteTo(Span<byte> buffer)
{
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;
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;
return MemoryMarshal.Cast<byte, GifGraphicsControlExtension>(buffer)[0];
}
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
// 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);
PackedField field = default;
// --------------------------------------- // Reserved | 3 bits
field.SetBits(3, 3, (int)disposalMethod); // Disposal Method | 3 bits
field.SetBit(6, userInputFlag); // User Input Flag | 1 bit
field.SetBit(7, transparencyFlag); // Transparent Color Flag | 1 bit
return field.Byte;
}
}
}

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