public virtual void Encode(IRgb24BitmapBase bitmap, Stream stream) { if (bitmap == null) { throw new ArgumentNullException(nameof(bitmap)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } WriteHeader(stream); var context = new GifEncodingContext(bitmap, stream); context.Data = bitmap.GetPixels(); context.Colors = context.Data.Distinct().ToArray(); WriteLogicalScreenDescriptor(context); // Global color map WriteColorTable(context); WriteImageDescriptor(context); // Local color table: empty WriteImageData(context); // Trailer stream.WriteByte(0x3B); }
protected void WriteApplicationExtensionBlock(GifEncodingContext context) { context.Stream.WriteByte(0x21); context.Stream.WriteByte(0xFF); context.Stream.WriteByte(0x0B); // "NETSCAPE2.0" context.Stream.WriteByte(0x4E); context.Stream.WriteByte(0x45); context.Stream.WriteByte(0x54); context.Stream.WriteByte(0x53); context.Stream.WriteByte(0x43); context.Stream.WriteByte(0x41); context.Stream.WriteByte(0x50); context.Stream.WriteByte(0x45); context.Stream.WriteByte(0x32); context.Stream.WriteByte(0x2E); context.Stream.WriteByte(0x30); context.Stream.WriteByte(0x03); context.Stream.WriteByte(0x01); // Loop forever context.Stream.WriteByte(0x00); context.Stream.WriteByte(0x00); context.Stream.WriteByte(0x00); }
protected void WriteImageData(GifEncodingContext context) { int lzwMinCodeSize = context.ColorTableSize + 1; lzwMinCodeSize = lzwMinCodeSize < 2 ? 2 : lzwMinCodeSize; // LZW minimum code size context.Stream.WriteByte((byte)lzwMinCodeSize); byte[] raster = GetLzwRaster(context.Colors, context.Data, lzwMinCodeSize); int offset = 0; while (raster.Length - offset > 255) { // Number of bytes in sub-block context.Stream.WriteByte(255); // Sub-block context.Stream.Write(raster, offset, 255); offset += 255; } context.Stream.WriteByte((byte)(raster.Length - offset)); context.Stream.Write(raster, offset, raster.Length - offset); // Block terminator context.Stream.WriteByte(0x00); }
protected void WriteGraphicsControlExtension(GifEncodingContext context) { // Extension introducer context.Stream.WriteByte(0x21); // Graphic control label context.Stream.WriteByte(0xF9); // Block size context.Stream.WriteByte(0x04); // Packed field // Reserved // Disposal method: 1 // User input flag // Transparent color flag context.Stream.WriteByte(0x04); // Delay time context.Stream.WriteByte(0x0A); context.Stream.WriteByte(0x00); // Transparent color index context.Stream.WriteByte(0x00); // Block terminator context.Stream.WriteByte(0x00); }
public override void Encode(IRgb24BitmapBase bitmap, Stream stream) { if (bitmap == null) { throw new ArgumentNullException(nameof(bitmap)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } WriteHeader(stream); var context = new GifEncodingContext(bitmap, stream); var bmp = bitmap as IRgb24Bitmap; if (bmp != null && bmp.FrameCount > 1) { context.Colors = Enumerable.Range(0, bmp.FrameCount) .Select(i => bmp.GetFrame(i).GetPixels()) .SelectMany(l => l) .Distinct() .ToArray(); WriteLogicalScreenDescriptor(context); WriteColorTable(context); WriteApplicationExtensionBlock(context); WriteGraphicsControlExtension(context); for (var i = 0; i < bmp.FrameCount; i++) { var frame = bmp.GetFrame(i); var fContext = new GifEncodingContext(frame, stream); fContext.Data = frame.GetPixels(); fContext.Colors = context.Colors; WriteImageDescriptor(fContext); WriteImageData(fContext); } } else { context.Data = bitmap.GetPixels(); context.Colors = context.Data.Distinct().ToArray(); WriteLogicalScreenDescriptor(context); WriteColorTable(context); WriteImageDescriptor(context); WriteImageData(context); } // Trailer stream.WriteByte(0x3B); }
protected void WriteColorTable(GifEncodingContext context) { int colorCount = 1 << (context.ColorTableSize + 1); int count = 0; foreach (var color in context.Colors) { // RGB24 WriteInt24(context.Stream, color); count += 1; } while (count < colorCount) { context.Stream.WriteByte(0); context.Stream.WriteByte(0); context.Stream.WriteByte(0); count += 1; } }
protected void WriteImageDescriptor(GifEncodingContext context) { // Image separator context.Stream.WriteByte(0x2C); // Image left position WriteInt16(context.Stream, 0); // Image top position WriteInt16(context.Stream, 0); // Image width WriteInt16(context.Stream, context.Bitmap.Width, true); // Image height WriteInt16(context.Stream, context.Bitmap.Height, true); // Packed field // Local color table flag // Interlace flag // Sort flag // Reserved // Size of local color table context.Stream.WriteByte(0); }
protected void WriteLogicalScreenDescriptor(GifEncodingContext context) { // Canvas width WriteInt16(context.Stream, context.Bitmap.Width, true); // Canvas height WriteInt16(context.Stream, context.Bitmap.Height, true); context.ColorTableSize = GetGlobalColorTableSize(context.Colors.Length); // Packed field // Global color table flag: 1 // Color resolution: 111 (8 bits/pixel) // Sort flag: 0 // Size of global color table: 2^(N+1) context.Stream.WriteByte((byte)(0b1_111_0_000 | context.ColorTableSize & 0b111)); // Background color index context.Stream.WriteByte(0x00); // Pixel aspect ratio context.Stream.WriteByte(0x00); }