Browse Source

Write the LogicalScreenDescriptor struct directly to the buffer

pull/536/head
Jason Nelson 8 years ago
parent
commit
d4b3ab4c70
  1. 7
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  2. 81
      src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs

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

@ -168,13 +168,12 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteLogicalScreenDescriptor<TPixel>(Image<TPixel> image, Stream stream, int transparencyIndex)
where TPixel : struct, IPixel<TPixel>
{
byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(false, this.bitDepth - 1, false, this.bitDepth - 1);
var descriptor = new GifLogicalScreenDescriptor(
width: (ushort)image.Width,
height: (ushort)image.Height,
bitsPerPixel: 0,
pixelAspectRatio: 0,
globalColorTableFlag: false, // TODO: Always false for now.
globalColorTableSize: this.bitDepth - 1,
packed: packedValue,
backgroundColorIndex: unchecked((byte)transparencyIndex));
descriptor.WriteTo(this.buffer);

81
src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.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
{
@ -11,29 +12,23 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// necessary to define the area of the display device
/// within which the images will be rendered
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal readonly struct GifLogicalScreenDescriptor
{
/// <summary>
/// The size of the written structure.
/// </summary>
public const int Size = 7;
public GifLogicalScreenDescriptor(
ushort width,
ushort height,
int bitsPerPixel,
byte packed,
byte backgroundColorIndex,
byte pixelAspectRatio,
bool globalColorTableFlag,
int globalColorTableSize)
byte pixelAspectRatio = 0)
{
this.Width = width;
this.Height = height;
this.BitsPerPixel = bitsPerPixel;
this.Packed = packed;
this.BackgroundColorIndex = backgroundColorIndex;
this.PixelAspectRatio = pixelAspectRatio;
this.GlobalColorTableFlag = globalColorTableFlag;
this.GlobalColorTableSize = globalColorTableSize;
}
/// <summary>
@ -49,9 +44,10 @@ namespace SixLabors.ImageSharp.Formats.Gif
public ushort Height { get; }
/// <summary>
/// Gets the color depth, in number of bits per pixel.
/// Gets the packed value consisting of:
/// globalColorTableFlag, colorResolution, sortFlag, and sizeOfGlobalColorTable.
/// </summary>
public int BitsPerPixel { get; }
public byte Packed { get; }
/// <summary>
/// Gets the index at the Global Color Table for the Background Color.
@ -61,59 +57,42 @@ namespace SixLabors.ImageSharp.Formats.Gif
public byte BackgroundColorIndex { get; }
/// <summary>
/// Gets the pixel aspect ratio. Default to 0.
/// Gets the pixel aspect ratio.
/// </summary>
public byte PixelAspectRatio { get; }
/// <summary>
/// Gets a value indicating whether a flag denoting the presence of a Global Color Table
/// should be set.
/// If the flag is set, the Global Color Table will immediately
/// follow the Logical Screen Descriptor.
/// If the flag is set, the Global Color Table will included after
/// the Logical Screen Descriptor.
/// </summary>
public bool GlobalColorTableFlag { get; }
public bool GlobalColorTableFlag => ((this.Packed & 0x80) >> 7) == 1;
/// <summary>
/// Gets the global color table size.
/// If the Global Color Table Flag is set to 1,
/// If the Global Color Table Flag is set,
/// the value in this field is used to calculate the number of
/// bytes contained in the Global Color Table.
/// </summary>
public int GlobalColorTableSize { get; }
public byte PackFields()
{
PackedField field = default;
public int GlobalColorTableSize => 2 << (this.Packed & 0x07);
field.SetBit(0, this.GlobalColorTableFlag); // 0 : Global Color Table Flag | 1 bit
field.SetBits(1, 3, this.GlobalColorTableSize); // 1-3 : Color Resolution | 3 bits
field.SetBit(4, false); // 4 : Sort Flag | 1 bits
field.SetBits(5, 3, this.GlobalColorTableSize); // 5-7 : Size of Global Color Table | 3 bits
return field.Byte;
}
/// <summary>
/// Gets the color depth, in number of bits per pixel.
/// The lowest 3 packed bits represent the bit depth minus 1.
/// </summary>
public int BitsPerPixel => (this.Packed & 0x07) + 1;
public void WriteTo(Span<byte> buffer)
{
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(0, 2), this.Width); // Logical Screen Width
BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(2, 2), this.Height); // Logical Screen Height
buffer[4] = this.PackFields(); // Packed Fields
buffer[5] = this.BackgroundColorIndex; // Background Color Index
buffer[6] = this.PixelAspectRatio; // Pixel Aspect Ratio
ref GifLogicalScreenDescriptor dest = ref Unsafe.As<byte, GifLogicalScreenDescriptor>(ref MemoryMarshal.GetReference(buffer));
dest = this;
}
public static GifLogicalScreenDescriptor Parse(ReadOnlySpan<byte> buffer)
{
byte packed = buffer[4];
var result = new GifLogicalScreenDescriptor(
width: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(0, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(2, 2)),
bitsPerPixel: (buffer[4] & 0x07) + 1, // The lowest 3 bits represent the bit depth minus 1
backgroundColorIndex: buffer[5],
pixelAspectRatio: buffer[6],
globalColorTableFlag: ((packed & 0x80) >> 7) == 1,
globalColorTableSize: 2 << (packed & 0x07));
GifLogicalScreenDescriptor result = MemoryMarshal.Cast<byte, GifLogicalScreenDescriptor>(buffer)[0];
if (result.GlobalColorTableSize > 255 * 4)
{
@ -122,5 +101,17 @@ namespace SixLabors.ImageSharp.Formats.Gif
return result;
}
public static byte GetPackedValue(bool globalColorTableFlag, int colorResolution, bool sortFlag, int globalColorTableSize)
{
PackedField field = default;
field.SetBit(0, globalColorTableFlag); // 0 : Global Color Table Flag | 1 bit
field.SetBits(1, 3, globalColorTableSize); // 1-3 : Color Resolution | 3 bits
field.SetBit(4, sortFlag); // 4 : Sort Flag | 1 bits
field.SetBits(5, 3, globalColorTableSize); // 5-7 : Size of Global Color Table | 3 bits
return field.Byte;
}
}
}
Loading…
Cancel
Save