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) private void WriteLogicalScreenDescriptor<TPixel>(Image<TPixel> image, Stream stream, int transparencyIndex)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(false, this.bitDepth - 1, false, this.bitDepth - 1);
var descriptor = new GifLogicalScreenDescriptor( var descriptor = new GifLogicalScreenDescriptor(
width: (ushort)image.Width, width: (ushort)image.Width,
height: (ushort)image.Height, height: (ushort)image.Height,
bitsPerPixel: 0, packed: packedValue,
pixelAspectRatio: 0,
globalColorTableFlag: false, // TODO: Always false for now.
globalColorTableSize: this.bitDepth - 1,
backgroundColorIndex: unchecked((byte)transparencyIndex)); backgroundColorIndex: unchecked((byte)transparencyIndex));
descriptor.WriteTo(this.buffer); descriptor.WriteTo(this.buffer);

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