Browse Source

Write GifImageDescriptor directly

af/merge-core
Jason Nelson 8 years ago
parent
commit
a9cf1d32bd
  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) private void WriteImageDescriptor<TPixel>(ImageFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> 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( var descriptor = new GifImageDescriptor(
left: 0, left: 0,
top: 0, top: 0,
width: (ushort)image.Width, width: (ushort)image.Width,
height: (ushort)image.Height, height: (ushort)image.Height,
localColorTableFlag: true, packed: packedValue);
localColorTableSize: this.bitDepth); // Note: we subtract 1 from the colorTableSize writing
descriptor.WriteTo(this.buffer); descriptor.WriteTo(this.buffer);

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

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