Browse Source

Write GifImageDescriptor directly

pull/533/head
Jason Nelson 8 years ago
parent
commit
d51e7ea6d9
  1. 9
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  2. 78
      src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs

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

@ -275,13 +275,18 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteImageDescriptor<TPixel>(ImageFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
byte packedValue = GifImageDescriptor.GetPackedValue(
localColorTableFlag: true,
interfaceFlag: false,
sortFlag: false,
localColorTableSize: this.bitDepth); // Note: we subtract 1 from the colorTableSize writing
var descriptor = new GifImageDescriptor(
left: 0,
top: 0,
width: (ushort)image.Width,
height: (ushort)image.Height,
localColorTableFlag: true,
localColorTableSize: this.bitDepth); // Note: we subtract 1 from the colorTableSize writing
packed: packedValue);
descriptor.WriteTo(this.buffer);

78
src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs

@ -2,7 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Gif
{
@ -12,6 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// Each image must fit within the boundaries of the
/// Logical Screen, as defined in the Logical Screen Descriptor.
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct GifImageDescriptor
{
public const int Size = 10;
@ -21,19 +23,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
ushort top,
ushort width,
ushort height,
bool localColorTableFlag,
int localColorTableSize,
bool interlaceFlag = false,
bool sortFlag = false)
byte packed)
{
this.Left = left;
this.Top = top;
this.Width = width;
this.Height = height;
this.LocalColorTableFlag = localColorTableFlag;
this.LocalColorTableSize = localColorTableSize;
this.InterlaceFlag = interlaceFlag;
this.SortFlag = sortFlag;
this.Packed = packed;
}
/// <summary>
@ -61,63 +57,41 @@ namespace SixLabors.ImageSharp.Formats.Gif
public ushort Height { get; }
/// <summary>
/// Gets a value indicating whether the presence of a Local Color Table immediately
/// follows this Image Descriptor.
/// Gets the packed value of localColorTableFlag, interlaceFlag, sortFlag, and localColorTableSize.
/// </summary>
public bool LocalColorTableFlag { get; }
public byte Packed { get; }
/// <summary>
/// Gets the local color table size.
/// If the Local Color Table Flag is set to 1, the value in this field
/// is used to calculate the number of bytes contained in the Local Color Table.
/// </summary>
public int LocalColorTableSize { get; }
public bool LocalColorTableFlag => ((this.Packed & 0x80) >> 7) == 1;
/// <summary>
/// Gets a value indicating whether the image is to be interlaced.
/// An image is interlaced in a four-pass interlace pattern.
/// </summary>
public bool InterlaceFlag { get; }
public int LocalColorTableSize => 2 << (this.Packed & 0x07);
/// <summary>
/// Gets a value indicating whether the Global Color Table is sorted.
/// </summary>
public bool SortFlag { get; }
public bool InterlaceFlag => ((this.Packed & 0x40) >> 6) == 1;
public byte PackFields()
public void WriteTo(Span<byte> buffer)
{
var field = default(PackedField);
buffer[0] = GifConstants.ImageDescriptorLabel;
field.SetBit(0, this.LocalColorTableFlag); // 0: Local color table flag = 1 (LCT used)
field.SetBit(1, this.InterlaceFlag); // 1: Interlace flag 0
field.SetBit(2, this.SortFlag); // 2: Sort flag 0
field.SetBits(5, 3, this.LocalColorTableSize - 1); // 3-4: Reserved, 5-7 : LCT size. 2^(N+1)
ref GifImageDescriptor dest = ref Unsafe.As<byte, GifImageDescriptor>(ref MemoryMarshal.GetReference(buffer.Slice(1)));
return field.Byte;
dest = this;
}
public void WriteTo(Span<byte> buffer)
public static GifImageDescriptor Parse(ReadOnlySpan<byte> buffer)
{
buffer[0] = GifConstants.ImageDescriptorLabel; // Image Separator (0x2C)
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(1, 2), this.Left); // Image Left Position
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(3, 2), this.Top); // Image Top Position
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(5, 2), this.Width); // Image Width
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(7, 2), this.Height); // Image Height
buffer[9] = this.PackFields(); // Packed Fields
return MemoryMarshal.Cast<byte, GifImageDescriptor>(buffer)[0];
}
public static GifImageDescriptor Parse(ReadOnlySpan<byte> buffer)
public static byte GetPackedValue(bool localColorTableFlag, bool interfaceFlag, bool sortFlag, int localColorTableSize)
{
byte packed = buffer[8];
return new GifImageDescriptor(
left: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(0, 2)),
top: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(2, 2)),
width: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(4, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(6, 2)),
localColorTableFlag: ((packed & 0x80) >> 7) == 1,
localColorTableSize: 2 << (packed & 0x07),
interlaceFlag: ((packed & 0x40) >> 6) == 1);
var field = default(PackedField);
field.SetBit(0, localColorTableFlag); // 0: Local color table flag = 1 (LCT used)
field.SetBit(1, interfaceFlag); // 1: Interlace flag 0
field.SetBit(2, sortFlag); // 2: Sort flag 0
field.SetBits(5, 3, localColorTableSize - 1); // 3-4: Reserved, 5-7 : LCT size. 2^(N+1)
return field.Byte;
}
}
}
Loading…
Cancel
Save