From d4b3ab4c708df59d16a5a6bd87b3969fc2edded8 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Wed, 18 Apr 2018 10:18:10 -0700 Subject: [PATCH] Write the LogicalScreenDescriptor struct directly to the buffer --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 7 +- .../Sections/GifLogicalScreenDescriptor.cs | 81 +++++++++---------- 2 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 9651cf440..e93e23f70 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -168,13 +168,12 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteLogicalScreenDescriptor(Image image, Stream stream, int transparencyIndex) where TPixel : struct, IPixel { + 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); diff --git a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs index 4f2a17ddf..35056c6e7 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifLogicalScreenDescriptor.cs +++ b/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 /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] internal readonly struct GifLogicalScreenDescriptor { - /// - /// The size of the written structure. - /// 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; } /// @@ -49,9 +44,10 @@ namespace SixLabors.ImageSharp.Formats.Gif public ushort Height { get; } /// - /// Gets the color depth, in number of bits per pixel. + /// Gets the packed value consisting of: + /// globalColorTableFlag, colorResolution, sortFlag, and sizeOfGlobalColorTable. /// - public int BitsPerPixel { get; } + public byte Packed { get; } /// /// 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; } /// - /// Gets the pixel aspect ratio. Default to 0. + /// Gets the pixel aspect ratio. /// public byte PixelAspectRatio { get; } /// /// 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. /// - public bool GlobalColorTableFlag { get; } + public bool GlobalColorTableFlag => ((this.Packed & 0x80) >> 7) == 1; /// /// 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. /// - 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; - } + /// + /// Gets the color depth, in number of bits per pixel. + /// The lowest 3 packed bits represent the bit depth minus 1. + /// + public int BitsPerPixel => (this.Packed & 0x07) + 1; public void WriteTo(Span 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(ref MemoryMarshal.GetReference(buffer)); + + dest = this; } public static GifLogicalScreenDescriptor Parse(ReadOnlySpan 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(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; + } } } \ No newline at end of file