예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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;
            }
        }
예제 #7
0
        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);
        }
예제 #8
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);
        }