Browse Source

Make GifImageDescriptor a struct

af/merge-core
Jason Nelson 8 years ago
parent
commit
3c4466ea5a
  1. 15
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 29
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  3. 98
      src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs

15
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);
}
/// <summary>

29
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);
}
/// <summary>
@ -283,25 +282,21 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to be encoded.</param>
/// <param name="writer">The stream to write to.</param>
private void WriteImageDescriptor<TPixel>(ImageFrame<TPixel> image, EndianBinaryWriter writer)
/// <param name="stream">The stream to write to.</param>
private void WriteImageDescriptor<TPixel>(ImageFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
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);
}
/// <summary>

98
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
{
/// <summary>
@ -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.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
public short Left { get; set; }
public ushort Left { get; }
/// <summary>
/// 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.
/// </summary>
public short Top { get; set; }
public ushort Top { get; }
/// <summary>
/// Gets or sets the width of the image in pixels.
/// Gets the width of the image in pixels.
/// </summary>
public short Width { get; set; }
public ushort Width { get; }
/// <summary>
/// Gets or sets the height of the image in pixels.
/// Gets the height of the image in pixels.
/// </summary>
public short Height { get; set; }
public ushort Height { get; }
/// <summary>
/// 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.
/// </summary>
public bool LocalColorTableFlag { get; set; }
public bool LocalColorTableFlag { get; }
/// <summary>
/// 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.
/// </summary>
public int LocalColorTableSize { get; set; }
public int LocalColorTableSize { get; }
/// <summary>
/// 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.
/// </summary>
public bool InterlaceFlag { get; set; }
public bool InterlaceFlag { get; }
/// <summary>
/// Gets a value indicating whether the Global Color Table is sorted.
/// </summary>
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<byte> 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<byte> 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);
}
}
}
}
Loading…
Cancel
Save