From 3c4466ea5aab626eede5ada9be6ab4eb75aae8b1 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Tue, 17 Apr 2018 12:14:02 -0700 Subject: [PATCH] Make GifImageDescriptor a struct --- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 15 +-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 29 +++--- .../Gif/Sections/GifImageDescriptor.cs | 98 ++++++++++++++++--- 3 files changed, 95 insertions(+), 47 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 0ea71f3b2..eaf79671f 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -252,20 +252,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { this.currentStream.Read(this.buffer, 0, 9); - byte packed = this.buffer[8]; - - var imageDescriptor = new GifImageDescriptor - { - Left = BitConverter.ToInt16(this.buffer, 0), - Top = BitConverter.ToInt16(this.buffer, 2), - Width = BitConverter.ToInt16(this.buffer, 4), - Height = BitConverter.ToInt16(this.buffer, 6), - LocalColorTableFlag = ((packed & 0x80) >> 7) == 1, - LocalColorTableSize = 2 << (packed & 0x07), - InterlaceFlag = ((packed & 0x40) >> 6) == 1 - }; - - return imageDescriptor; + return GifImageDescriptor.Parse(this.buffer); } /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 915c86817..f0e95ed1d 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } this.WriteGraphicalControlExtension(frame.MetaData, stream, this.GetTransparentIndex(quantized)); - this.WriteImageDescriptor(frame, writer); + this.WriteImageDescriptor(frame, stream); this.WriteColorTable(quantized, writer); this.WriteImageData(quantized, writer); @@ -275,7 +275,6 @@ namespace SixLabors.ImageSharp.Formats.Gif extension.WriteTo(this.buffer); stream.Write(this.buffer, 0, GifGraphicsControlExtension.Size); - } /// @@ -283,25 +282,21 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The pixel format. /// The to be encoded. - /// The stream to write to. - private void WriteImageDescriptor(ImageFrame image, EndianBinaryWriter writer) + /// The stream to write to. + private void WriteImageDescriptor(ImageFrame image, Stream stream) where TPixel : struct, IPixel { - writer.Write(GifConstants.ImageDescriptorLabel); // 2c + 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 - // TODO: Can we capture this? - writer.Write((ushort)0); // Left position - writer.Write((ushort)0); // Top position - writer.Write((ushort)image.Width); - writer.Write((ushort)image.Height); - - var field = default(PackedField); - field.SetBit(0, true); // 1: Local color table flag = 1 (LCT used) - field.SetBit(1, false); // 2: Interlace flag 0 - field.SetBit(2, false); // 3: Sort flag 0 - field.SetBits(5, 3, this.bitDepth - 1); // 4-5: Reserved, 6-8 : LCT size. 2^(N+1) + descriptor.WriteTo(this.buffer); - writer.Write(field.Byte); + stream.Write(this.buffer, 0, GifImageDescriptor.Size); } /// diff --git a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs index 2ed9e4747..d17bc2039 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Buffers.Binary; + namespace SixLabors.ImageSharp.Formats.Gif { /// @@ -9,49 +12,112 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Each image must fit within the boundaries of the /// Logical Screen, as defined in the Logical Screen Descriptor. /// - internal sealed class GifImageDescriptor + internal readonly struct GifImageDescriptor { + public const int Size = 10; + + public GifImageDescriptor( + ushort left, + ushort top, + ushort width, + ushort height, + bool localColorTableFlag, + int localColorTableSize, + bool interlaceFlag = false, + bool sortFlag = false) + { + this.Left = left; + this.Top = top; + this.Width = width; + this.Height = height; + this.LocalColorTableFlag = localColorTableFlag; + this.LocalColorTableSize = localColorTableSize; + this.InterlaceFlag = interlaceFlag; + this.SortFlag = sortFlag; + } + /// - /// Gets or sets the column number, in pixels, of the left edge of the image, + /// Gets the column number, in pixels, of the left edge of the image, /// with respect to the left edge of the Logical Screen. /// Leftmost column of the Logical Screen is 0. /// - public short Left { get; set; } + public ushort Left { get; } /// - /// Gets or sets the row number, in pixels, of the top edge of the image with + /// Gets the row number, in pixels, of the top edge of the image with /// respect to the top edge of the Logical Screen. /// Top row of the Logical Screen is 0. /// - public short Top { get; set; } + public ushort Top { get; } /// - /// Gets or sets the width of the image in pixels. + /// Gets the width of the image in pixels. /// - public short Width { get; set; } + public ushort Width { get; } /// - /// Gets or sets the height of the image in pixels. + /// Gets the height of the image in pixels. /// - public short Height { get; set; } + public ushort Height { get; } /// - /// Gets or sets a value indicating whether the presence of a Local Color Table immediately + /// Gets a value indicating whether the presence of a Local Color Table immediately /// follows this Image Descriptor. /// - public bool LocalColorTableFlag { get; set; } + public bool LocalColorTableFlag { get; } /// - /// Gets or sets the local color table size. + /// 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. /// - public int LocalColorTableSize { get; set; } + public int LocalColorTableSize { get; } /// - /// Gets or sets a value indicating whether the image is to be interlaced. + /// Gets a value indicating whether the image is to be interlaced. /// An image is interlaced in a four-pass interlace pattern. /// - public bool InterlaceFlag { get; set; } + public bool InterlaceFlag { get; } + + /// + /// Gets a value indicating whether the Global Color Table is sorted. + /// + public bool SortFlag { get; } + + public byte PackFields() + { + var field = default(PackedField); + + 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) + + return field.Byte; + } + + public void WriteTo(Span 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 + } + + public static GifImageDescriptor Parse(ReadOnlySpan buffer) + { + 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); + } } -} +} \ No newline at end of file