Browse Source

Factor out EndianBinaryWriter from GifEncoder

af/merge-core
Jason Nelson 8 years ago
parent
commit
898ebc952a
  1. 62
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers.Binary;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
@ -75,9 +76,6 @@ namespace SixLabors.ImageSharp.Formats.Gif
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
// Do not use IDisposable pattern here as we want to preserve the stream.
var writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Quantize the image returning a palette.
QuantizedFrame<TPixel> quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(image.Frames.RootFrame);
@ -87,18 +85,18 @@ namespace SixLabors.ImageSharp.Formats.Gif
int index = this.GetTransparentIndex(quantized);
// Write the header.
this.WriteHeader(writer);
this.WriteHeader(stream);
// Write the LSD. We'll use local color tables for now.
this.WriteLogicalScreenDescriptor(image, stream, index);
// Write the first frame.
this.WriteComments(image, writer);
this.WriteComments(image, stream);
// Write additional frames.
if (image.Frames.Count > 1)
{
this.WriteApplicationExtension(writer, image.MetaData.RepeatCount);
this.WriteApplicationExtension(stream, image.MetaData.RepeatCount);
}
foreach (ImageFrame<TPixel> frame in image.Frames)
@ -110,14 +108,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.WriteGraphicalControlExtension(frame.MetaData, stream, this.GetTransparentIndex(quantized));
this.WriteImageDescriptor(frame, stream);
this.WriteColorTable(quantized, writer);
this.WriteImageData(quantized, writer);
this.WriteColorTable(quantized, stream);
this.WriteImageData(quantized, stream);
quantized = null; // So next frame can regenerate it
}
// TODO: Write extension etc
writer.Write(GifConstants.EndIntroducer);
stream.WriteByte(GifConstants.EndIntroducer);
}
/// <summary>
@ -153,11 +151,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Writes the file header signature and version to the stream.
/// </summary>
/// <param name="writer">The writer to write to the stream with.</param>
/// <param name="stream">The stream to write to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteHeader(EndianBinaryWriter writer)
private void WriteHeader(Stream stream)
{
writer.Write(GifConstants.MagicNumber);
stream.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length);
}
/// <summary>
@ -189,9 +187,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Writes the application extension to the stream.
/// </summary>
/// <param name="writer">The writer to write to the stream with.</param>
/// <param name="stream">The stream to write to.</param>
/// <param name="repeatCount">The animated image repeat count.</param>
private void WriteApplicationExtension(EndianBinaryWriter writer, ushort repeatCount)
private void WriteApplicationExtension(Stream stream, ushort repeatCount)
{
// Application Extension Header
if (repeatCount != 1)
@ -200,17 +198,21 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.buffer[1] = GifConstants.ApplicationExtensionLabel;
this.buffer[2] = GifConstants.ApplicationBlockSize;
writer.Write(this.buffer, 0, 3);
stream.Write(this.buffer, 0, 3);
stream.Write(GifConstants.ApplicationIdentificationBytes, 0, 11); // NETSCAPE2.0
writer.Write(GifConstants.ApplicationIdentificationBytes); // NETSCAPE2.0
writer.Write((byte)3); // Application block length
writer.Write((byte)1); // Data sub-block index (always 1)
this.buffer[0] = 3; // Application block length
this.buffer[1] = 1; // Data sub-block index (always 1)
// 0 means loop indefinitely. Count is set as play n + 1 times.
repeatCount = (ushort)Math.Max(0, repeatCount - 1);
writer.Write(repeatCount); // Repeat count for images.
writer.Write(GifConstants.Terminator); // Terminator
BinaryPrimitives.WriteUInt16LittleEndian(this.buffer.AsSpan(2, 2), repeatCount); // Repeat count for images.
this.buffer[4] = GifConstants.Terminator; // Terminator
stream.Write(this.buffer, 0, 5);
}
}
@ -220,7 +222,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to be encoded.</param>
/// <param name="stream">The stream to write to.</param>
private void WriteComments<TPixel>(Image<TPixel> image, EndianBinaryWriter writer)
private void WriteComments<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
if (this.ignoreMetadata)
@ -242,9 +244,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.buffer[1] = GifConstants.CommentLabel;
this.buffer[2] = (byte)count;
writer.Write(this.buffer, 0, 3);
writer.Write(comments, 0, count);
writer.Write(GifConstants.Terminator);
stream.Write(this.buffer, 0, 3);
stream.Write(comments, 0, count);
stream.WriteByte(GifConstants.Terminator);
}
/// <summary>
@ -294,8 +296,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageFrame{TPixel}"/> to encode.</param>
/// <param name="writer">The writer to write to the stream with.</param>
private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, EndianBinaryWriter writer)
/// <param name="stream">The stream to write to.</param>
private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
// Grab the palette and write it to the stream.
@ -316,7 +318,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
Unsafe.Add(ref rgb24Ref, i) = rgb;
}
writer.Write(colorTable.Array, 0, colorTableLength);
stream.Write(colorTable.Array, 0, colorTableLength);
}
}
@ -325,13 +327,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="image">The <see cref="QuantizedFrame{TPixel}"/> containing indexed pixels.</param>
/// <param name="writer">The stream to write to.</param>
private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, EndianBinaryWriter writer)
/// <param name="stream">The stream to write to.</param>
private void WriteImageData<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
using (var encoder = new LzwEncoder(this.memoryManager, image.Pixels, (byte)this.bitDepth))
{
encoder.Encode(writer.BaseStream);
encoder.Encode(stream);
}
}
}

Loading…
Cancel
Save