namespace ImageProcessor.Formats { using System; using System.IO; public class GifEncoder : IImageEncoder { /// /// The quality. /// private int quality = 256; /// /// Gets or sets the quality of output for images. /// /// For gifs the value ranges from 1 to 256. public int Quality { get { return this.quality; } set { this.quality = value.Clamp(1, 256); } } /// /// Gets the default file extension for this encoder. /// public string Extension => "GIF"; /// /// Returns a value indicating whether the supports the specified /// file header. /// /// The containing the file extension. /// /// True if the decoder supports the file extension; otherwise, false. /// public bool IsSupportedFileExtension(string extension) { Guard.NotNullOrEmpty(extension, "extension"); extension = extension.StartsWith(".") ? extension.Substring(1) : extension; return extension.Equals("GIF", StringComparison.OrdinalIgnoreCase); } /// /// Encodes the image to the specified stream from the . /// /// The to encode from. /// The to encode the image data to. public void Encode(ImageBase image, Stream stream) { Guard.NotNull(image, "image"); Guard.NotNull(stream, "stream"); // Write the header. // File Header signature and version. this.WriteString(stream, "GIF"); this.WriteString(stream, "89a"); GifLogicalScreenDescriptor descriptor = new GifLogicalScreenDescriptor { Width = (short)image.Width, Height = (short)image.Height, GlobalColorTableFlag = true, GlobalColorTableSize = this.Quality }; this.WriteGlobalLogicalScreenDescriptor(stream, descriptor); throw new System.NotImplementedException(); } private void WriteGlobalLogicalScreenDescriptor(Stream stream, GifLogicalScreenDescriptor descriptor) { this.WriteShort(stream, descriptor.Width); this.WriteShort(stream, descriptor.Width); int size = descriptor.GlobalColorTableSize; int bitdepth = this.GetBitsNeededForColorDepth(size) - 1; int packed = 0x80 | // 1 : Global color table flag = 1 (GCT used) 0x70 | // 2-4 : color resolution 0x00 | // 5 : GCT sort flag = 0 bitdepth; // 6-8 : GCT size assume 1:1 this.WriteByte(stream, packed); this.WriteByte(stream, descriptor.BackgroundColorIndex); // Background Color Index this.WriteByte(stream, descriptor.PixelAspectRatio); // Pixel aspect ratio // Write the global color table. this.WriteColorTable(stream, size); } private void WriteColorTable(Stream stream, int size) { } /// /// Writes a short to the given stream. /// /// The containing image data. /// The value to write. private void WriteShort(Stream stream, int value) { // Leave only one significant byte. stream.WriteByte(Convert.ToByte(value & 0xff)); stream.WriteByte(Convert.ToByte((value >> 8) & 0xff)); } /// /// Writes a short to the given stream. /// /// The containing image data. /// The value to write. private void WriteByte(Stream stream, int value) { stream.WriteByte(Convert.ToByte(value)); } /// /// Writes a string to the given stream. /// /// The containing image data. /// The value to write. private void WriteString(Stream stream, string value) { char[] chars = value.ToCharArray(); foreach (char c in chars) { stream.WriteByte((byte)c); } } /// /// Returns how many bits are required to store the specified number of colors. /// Performs a Log2() on the value. /// private int GetBitsNeededForColorDepth(int colors) { return (int)Math.Ceiling(Math.Log(colors, 2)); } } }