Esempio n. 1
0
        // Determine if an image only has indexed frames in it and
        // that all frames have the same pixel format.
        public static bool IsGifEncodable(PortableImage image)
        {
            int         index;
            Frame       frame;
            PixelFormat format = (PixelFormat)(-1);

            if (image.NumFrames == 0)
            {
                return(false);
            }
            for (index = 0; index < image.NumFrames; ++index)
            {
                frame = image.GetFrame(index);
                if ((frame.PixelFormat & PixelFormat.Indexed) == 0)
                {
                    return(false);
                }
                if (format != (PixelFormat)(-1) &&
                    format != frame.PixelFormat)
                {
                    return(false);
                }
                format = frame.PixelFormat;
            }
            return(true);
        }
Esempio n. 2
0
 public PortableImage Reformat(PixelFormat newFormat)
 {
     PortableImage newImage = new PortableImage(this, newFormat);
     for (int i = 0; i < frames.Length; i++)
         newImage.AddFrame(frames[i].Reformat(newFormat));
     return newImage;
 }
Esempio n. 3
0
        private PortableImage(PortableImage image, PixelFormat format)
        {
            Width = image.Width;
            Height = image.Height;
            pixelFormat = image.pixelFormat;
            LoadFormat = image.LoadFormat;
            if (image.Palette != null)
            {
                Palette = (int[]) (image.Palette.Clone());
            }

            TransparentPixel = image.TransparentPixel;
        }
Esempio n. 4
0
        public static void Load(Stream stream, PortableImage image)
        {
            // This just reads enough headers to set size.

            var ms = new MemoryStream();

            stream.CopyTo(ms);
            var data = new ReadOnlySequence <byte>(ms.ToArray());

            var decoder = new JpegDecoder();

            decoder.SetInput(data);
            decoder.Identify();

            if (decoder.NumberOfComponents != 1 && decoder.NumberOfComponents != 3)
            {
                // We only support Grayscale and YCbCr.
                throw new NotSupportedException("This color space is not supported");
            }

            image.Width      = decoder.Width;
            image.Height     = decoder.Height;
            image.LoadFormat = PortableImage.Jpeg;
            image.imageFlags = decoder.NumberOfComponents == 1 ? ImageFlags.ColorSpaceGray : ImageFlags.ColorSpaceRgb;

            /*
             * // TODO: bring in the huge complexity that is the JPEG read/write format.
             * // The PDF stuff doesn't need to read frames, so it would be neat to have this 'lazy'
             * // Add a frame to the image object.
             * Frame frame = image.AddFrame(image.Width, image.Height, PixelFormat.Format24bppRgb);
             *
             * if (decoder.Precision == 8)
             * {
             *  // This is the most common case for JPEG, and we have an optimised implementation.
             *  decoder.SetOutputWriter(new JpegBufferOutputWriter8Bit(image.Width, image.Height, 3, frame.data));
             * }
             * else if (decoder.Precision < 8)
             * {
             *  decoder.SetOutputWriter(new JpegBufferOutputWriterLessThan8Bit(image.Width, image.Height, decoder.Precision, 3, frame.data));
             * }
             * else
             * {
             *  decoder.SetOutputWriter(new JpegBufferOutputWriterGreaterThan8Bit(image.Width, image.Height, decoder.Precision, 3, frame.data));
             * }
             *
             * decoder.Decode();
             * // TODO: our frame buffer should now be populated with Y,Cr,Cb data. It should get converted to RGB.
             */
        }
Esempio n. 5
0
        // Stretch this image to a new size.
        public PortableImage Stretch(int width, int height)
        {
            Width = width;
            Height = height;
            PortableImage newImage = null;
            for (int i = 0; i < frames.Length; i++)
            {
                if (i == 0)
                    newImage = new PortableImage(this, frames[0].Scale(width, height));
                else
                    newImage.AddFrame(frames[i].Scale(width, height));
            }

            return newImage;
        }
Esempio n. 6
0
        // Save a BMP image to the specified stream.
        public static void Save(Stream stream, PortableImage image)
        {
            byte[] buffer = new byte [1024];
            int    bitCount;
            int    offset;
            int    size;

            // We can only save the first frame in BMP formats.
            Frame frame = image.GetFrame(0);

            if (frame == null)
            {
                return;
            }

            // Determine the size of the bitmap and the offset to it.
            bitCount = Utils.FormatToBitCount(frame.pixelFormat);
            size     = frame.Stride * frame.Height;
            offset   = 14 + 40;
            if (bitCount <= 8)
            {
                offset += (1 << bitCount) * 4;
            }

            // Build and write the BITMAPFILEHEADER structure.
            buffer[0] = (byte)'B';
            buffer[1] = (byte)'M';
            Utils.WriteInt32(buffer, 2, offset + size);
            buffer[6] = (byte)0;
            buffer[7] = (byte)0;
            buffer[8] = (byte)0;
            buffer[9] = (byte)0;
            Utils.WriteInt32(buffer, 10, offset);
            stream.Write(buffer, 0, 14);

            // Build and write the BITMAPINFO details.
            SaveBitmapInfo(stream, frame, bitCount, size, buffer,
                           frame.Height);

            // Write the bitmap data in the frame to the stream.
            SaveBitmapData(stream, frame, false, false);
        }
Esempio n. 7
0
 private PortableImage(PortableImage image, Frame thisFrameOnly) :
     this(image, image.PixelFormat)
 {
     if (thisFrameOnly != null)
     {
         NumFrames = 1;
         frames = new Frame [1];
         frames[0] = thisFrameOnly.CloneFrame(this);
     }
     else
     {
         NumFrames = image.NumFrames;
         if (image.frames != null)
         {
             int frame;
             frames = new Frame [NumFrames];
             for (frame = 0; frame < NumFrames; ++frame)
             {
                 frames[frame] =
                     image.frames[frame].CloneFrame(this);
             }
         }
     }
 }
Esempio n. 8
0
        // Save a GIF image to the specified stream.  This uses the "ungif"
        // approach of writing uncompressed code samples to avoid infringing
        // on the LZW patent.  The patent may have expired already, but we
        // aren't taking any chances.  Use PNG instead - it compresses better.
        public static void Save(Stream stream, PortableImage image)
        {
            byte[] buffer = new byte [1024];
            Frame  frame0, frame;
            int    bitCount, index;

            int[] palette;

            // Get the first frame in the image and the image's bit depth.
            frame0   = image.GetFrame(0);
            bitCount = Utils.FormatToBitCount(frame0.PixelFormat);

            // Write the GIF file header.
            buffer[0] = (byte)'G';
            buffer[1] = (byte)'I';
            buffer[2] = (byte)'F';
            buffer[3] = (byte)'8';
            buffer[4] = (byte)'9';
            buffer[5] = (byte)'a';
            Utils.WriteUInt16(buffer, 6, image.Width);
            Utils.WriteUInt16(buffer, 8, image.Height);
            buffer[10] = (byte)((bitCount - 1) |
                                ((bitCount - 1) << 4) | 0x80);
            if (frame0.TransparentPixel != -1)
            {
                // Use the transparent pixel as the background color.
                buffer[11] = (byte)(frame0.TransparentPixel);
            }
            else
            {
                // Assume that index zero is the background color.
                buffer[11] = (byte)0x00;
            }
            buffer[12] = (byte)0x00;                            // No aspect ratio specified.
            stream.Write(buffer, 0, 13);

            // Write the global color table, which is the palette
            // for the first frame.  We use local color tables only
            // if the palette changes for subsequent frames.
            palette = frame0.Palette;
            WriteGifPalette(stream, palette, bitCount, buffer);

            // Write out the frames.
            for (index = 0; index < image.NumFrames; ++index)
            {
                // Get the object for this frame.
                frame = image.GetFrame(index);

                // Write a graphics control extension for transparencies.
                if (frame.TransparentPixel != -1)
                {
                    buffer[0] = (byte)0x21;
                    buffer[1] = (byte)0xF9;
                    buffer[2] = (byte)0x04;
                    buffer[3] = (byte)0x01;
                    buffer[4] = (byte)0x00;
                    buffer[5] = (byte)0x00;
                    buffer[6] = (byte)(frame.TransparentPixel);
                    buffer[7] = (byte)0x00;
                    stream.Write(buffer, 0, 8);
                }

                // Write the image descriptor header.
                buffer[0] = (byte)0x2C;
                Utils.WriteUInt16(buffer, 1, frame.OffsetX);
                Utils.WriteUInt16(buffer, 3, frame.OffsetY);
                Utils.WriteUInt16(buffer, 5, frame.Width);
                Utils.WriteUInt16(buffer, 7, frame.Height);
                if (frame.Palette != palette)
                {
                    buffer[9] = (byte)((bitCount - 1) | 0x80);
                }
                else
                {
                    buffer[9] = (byte)0x00;
                }
                stream.Write(buffer, 0, 10);

                // Write the local color table if necessary.
                if (frame.Palette != palette)
                {
                    WriteGifPalette
                        (stream, frame.Palette, bitCount, buffer);
                }

                // Compress and output the frame's contents.
                Compress(stream, buffer, bitCount, frame);
            }

            // Write the GIF file terminator.
            buffer[0] = (byte)0x3B;
            stream.Write(buffer, 0, 1);
        }
Esempio n. 9
0
        // Save a PNG image to the specified stream.
        public static void Save(Stream stream, PortableImage image)
        {
            Frame frame = image.GetFrame(0);

            byte[]      buffer = new byte [1024];
            ChunkWriter writer = new ChunkWriter(stream);
            int         colorType, bitDepth;
            int         sigRed, sigGreen, sigBlue, sigAlpha;
            int         paletteSize, posn;

            int[]          palette;
            ZlibCompressor compressor;
            ScanlineWriter scanlineWriter;
            OutputFunc     func;
            int            y;

            // Determine the color type and bit depth for the image.
            sigRed      = -1;
            sigGreen    = -1;
            sigBlue     = -1;
            sigAlpha    = -1;
            paletteSize = 0;
            switch (frame.PixelFormat)
            {
            case PixelFormat.Format16bppRgb555:
            {
                sigRed    = 5;
                sigGreen  = 5;
                sigBlue   = 5;
                colorType = 2;
                bitDepth  = 8;
            }
            break;

            case PixelFormat.Format16bppRgb565:
            {
                sigRed    = 5;
                sigGreen  = 6;
                sigBlue   = 5;
                colorType = 2;
                bitDepth  = 8;
            }
            break;

            case PixelFormat.Format24bppRgb:
            case PixelFormat.Format32bppRgb:
            {
                colorType = 2;
                bitDepth  = 8;
            }
            break;

            case PixelFormat.Format1bppIndexed:
            {
                colorType   = 3;
                bitDepth    = 1;
                paletteSize = 2;
            }
            break;

            case PixelFormat.Format4bppIndexed:
            {
                colorType   = 3;
                bitDepth    = 4;
                paletteSize = 16;
            }
            break;

            case PixelFormat.Format8bppIndexed:
            {
                colorType   = 3;
                bitDepth    = 8;
                paletteSize = 256;
            }
            break;

            case PixelFormat.Format16bppArgb1555:
            {
                sigRed    = 5;
                sigGreen  = 5;
                sigBlue   = 5;
                sigAlpha  = 1;
                colorType = 6;
                bitDepth  = 8;
            }
            break;

            case PixelFormat.Format32bppPArgb:
            case PixelFormat.Format32bppArgb:
            {
                colorType = 6;
                bitDepth  = 8;
            }
            break;

            case PixelFormat.Format16bppGrayScale:
            {
                colorType = 0;
                bitDepth  = 16;
            }
            break;

            case PixelFormat.Format48bppRgb:
            {
                colorType = 2;
                bitDepth  = 16;
            }
            break;

            case PixelFormat.Format64bppPArgb:
            case PixelFormat.Format64bppArgb:
            {
                colorType = 6;
                bitDepth  = 16;
            }
            break;

            default: throw new FormatException("unknown format");
            }

            // Write out the PNG magic number.
            stream.Write(magic, 0, magic.Length);

            // Write the header chunk.
            Utils.WriteInt32B(buffer, 0, frame.Width);
            Utils.WriteInt32B(buffer, 4, frame.Height);
            buffer[8]  = (byte)bitDepth;
            buffer[9]  = (byte)colorType;
            buffer[10] = (byte)0;                                       // Compression method.
            buffer[11] = (byte)0;                                       // Filter method.
            buffer[12] = (byte)0;                                       // Interlace method.
            writer.Write(PngReader.IHDR, buffer, 0, 13);

            // Write the significant bits chunk if necessary.
            if (sigAlpha != -1)
            {
                buffer[0] = (byte)sigRed;
                buffer[1] = (byte)sigGreen;
                buffer[2] = (byte)sigBlue;
                buffer[3] = (byte)sigAlpha;
                writer.Write(PngReader.sBIT, buffer, 0, 4);
            }
            else if (sigRed != -1)
            {
                buffer[0] = (byte)sigRed;
                buffer[1] = (byte)sigGreen;
                buffer[2] = (byte)sigBlue;
                writer.Write(PngReader.sBIT, buffer, 0, 3);
            }

            // Write the palette and transparency chunks.
            if (paletteSize > 0)
            {
                Array.Clear(buffer, 0, buffer.Length);
                palette = frame.Palette;
                if (palette != null)
                {
                    for (posn = 0; posn < palette.Length &&
                         posn < paletteSize; ++posn)
                    {
                        buffer[posn * 3]     = (byte)(palette[posn] >> 16);
                        buffer[posn * 2 + 1] = (byte)(palette[posn] >> 8);
                        buffer[posn * 2 + 2] = (byte)(palette[posn]);
                    }
                }
                writer.Write(PngReader.PLTE, buffer, 0, paletteSize * 3);
                if (frame.TransparentPixel >= 0 &&
                    frame.TransparentPixel < paletteSize)
                {
                    for (posn = 0; posn < paletteSize; ++posn)
                    {
                        buffer[posn] = (byte)0xFF;
                    }
                    buffer[frame.TransparentPixel] = (byte)0x00;
                    writer.Write(PngReader.tRNS, buffer, 0,
                                 frame.TransparentPixel + 1);
                }
            }

            // Compress and write the scanlines to the output stream.
            compressor     = new ZlibCompressor(writer);
            scanlineWriter = new ScanlineWriter
                                 (compressor, frame.Width, frame.PixelFormat);
            func = GetOutputFunc(frame.PixelFormat);
            for (y = 0; y < frame.Height; ++y)
            {
                func(frame, y, scanlineWriter.Buffer);
                scanlineWriter.FlushScanline();
            }
            compressor.Finish();

            // Write the end chunk.
            writer.Write(PngReader.IEND, buffer, 0, 0);
        }
Esempio n. 10
0
        // Load a Windows icon image from the specified stream.  The first
        // 4 bytes have already been read and discarded.  If "hotspots" is
        // "true", then the image is actually a Windows cursor with hotspots.
        public static void Load(Stream stream, PortableImage image, bool hotspots)
        {
            byte[]      buffer = new byte [1024];
            int         offset = 4;
            int         numImages, index;
            int         width, height, bpp;
            PixelFormat format;
            Frame       frame;

            int[] palette;
            int   paletteCount;
            int   paletteIndex;

            // Read the number of images in the file.
            if (stream.Read(buffer, 0, 2) != 2)
            {
                throw new FormatException();
            }
            numImages = Utils.ReadUInt16(buffer, 0);
            offset   += 2;

            // Read the resource directory.
            int[] offsetList = new int [numImages];
            int[] hotspotX   = null;
            int[] hotspotY   = null;
            if (hotspots)
            {
                hotspotX = new int[numImages];
                hotspotY = new int[numImages];
            }
            for (index = 0; index < numImages; ++index)
            {
                if (stream.Read(buffer, 0, 16) != 16)
                {
                    throw new FormatException();
                }
                offset += 16;
                if (hotspots)
                {
                    hotspotX[index] = Utils.ReadUInt16(buffer, 4);
                    hotspotY[index] = Utils.ReadUInt16(buffer, 6);
                }
                offsetList[index] = Utils.ReadInt32(buffer, 12);
            }

            // Read the contents of the images in the stream.
            for (index = 0; index < numImages; ++index)
            {
                // Seek to the start of the image.
                Utils.Seek(stream, offset, offsetList[index]);
                offset = offsetList[index];

                // Read the DIB header.
                if (stream.Read(buffer, 0, 40) != 40)
                {
                    throw new FormatException();
                }
                offset += 40;
                width   = Utils.ReadUInt16(buffer, 4);
                // The DIB height is the mask and the bitmap.
                height = Utils.ReadUInt16(buffer, 8) / 2;
                bpp    = Utils.ReadUInt16(buffer, 14);
                if (bpp == 1)
                {
                    format = PixelFormat.Format1bppIndexed;
                }
                else if (bpp == 4)
                {
                    format = PixelFormat.Format4bppIndexed;
                }
                else if (bpp == 8)
                {
                    format = PixelFormat.Format8bppIndexed;
                }
                else if (bpp == 24)
                {
                    format = PixelFormat.Format24bppRgb;
                }
                else if (bpp == 32)
                {
                    format = PixelFormat.Format32bppArgb;
                }
                else
                {
                    throw new FormatException();
                }

                // Create a new frame for this icon.
                frame = new Frame(image, width, height, format);
                image.AddFrame(frame);
                if (hotspots)
                {
                    frame.HotspotX = hotspotX[index];
                    frame.HotspotY = hotspotY[index];
                }

                // Copy some of the format information up to the image.
                if (frame.Width > image.Width)
                {
                    image.Width = frame.Width;
                }
                if (frame.Height > image.Height)
                {
                    image.Height = frame.Height;
                }
                if (image.NumFrames == 1)
                {
                    image.PixelFormat = format;
                }

                // If indexed, get the palette.
                if ((frame.pixelFormat & PixelFormat.Indexed) != 0)
                {
                    paletteCount =
                        (1 << Utils.FormatToBitCount(frame.pixelFormat));
                    if (stream.Read(buffer, 0, paletteCount * 4)
                        != paletteCount * 4)
                    {
                        throw new FormatException();
                    }
                    offset += paletteCount * 4;
                    palette = new int [paletteCount];
                    for (paletteIndex = 0; paletteIndex < paletteCount;
                         ++paletteIndex)
                    {
                        palette[paletteIndex] = Utils.ReadBGR
                                                    (buffer, paletteIndex * 4);
                    }
                    frame.Palette = palette;
                }

                // Read the main part of the icon or cursor.
                BmpReader.LoadBitmapData(stream, frame, false, true);
                offset += frame.Height * frame.Stride;

                // Read the mask.
                BmpReader.LoadBitmapData(stream, frame, true, true);
                offset += frame.Height * frame.MaskStride;

                // Invert the mask, because we want 1 to mean "active".
                InvertMask(frame);
            }

            // Set the appropriate load format.
            if (hotspots)
            {
                image.LoadFormat = PortableImage.Cursor;
            }
            else
            {
                image.LoadFormat = PortableImage.Icon;
            }
        }
Esempio n. 11
0
        // Save a Windows icon image to the specified stream.  If "hotspots"
        // is "true", then the image is actually a Windows cursor with hotspots.
        public static void Save(Stream stream, PortableImage image, bool hotspots)
        {
            byte[] buffer = new byte [1024];
            int    numImages = image.NumFrames;
            int    offset, index, size, bitCount;

            int[] offsetList;
            int[] sizeList;
            Frame frame;

            // Write the image header.
            buffer[0] = 0;
            buffer[1] = 0;
            buffer[2] = (byte)(hotspots ? 2 : 1);
            buffer[3] = 0;
            Utils.WriteUInt16(buffer, 4, numImages);
            stream.Write(buffer, 0, 6);

            // Infer the starting offsets and sizes for each of the images.
            offset     = 6 + numImages * 16;
            offsetList = new int [numImages];
            sizeList   = new int [numImages];
            for (index = 0; index < numImages; ++index)
            {
                frame = image.GetFrame(index);
                size  = 40;
                if ((frame.pixelFormat & PixelFormat.Indexed) != 0)
                {
                    size +=
                        4 * (1 << Utils.FormatToBitCount(frame.pixelFormat));
                }
                size += frame.Height * (frame.Stride + frame.MaskStride);
                offsetList[index] = offset;
                sizeList[index]   = size;
                offset           += size;
            }

            // Write the contents of the resource directory.
            for (index = 0; index < image.NumFrames; ++index)
            {
                frame     = image.GetFrame(index);
                bitCount  = Utils.FormatToBitCount(frame.pixelFormat);
                buffer[0] = (byte)(frame.Width);
                buffer[1] = (byte)(frame.Height);
                buffer[2] = (byte)(1 << bitCount);
                buffer[3] = 0;
                if (hotspots)
                {
                    Utils.WriteUInt16(buffer, 4, frame.HotspotX);
                    Utils.WriteUInt16(buffer, 6, frame.HotspotY);
                }
                else
                {
                    Utils.WriteUInt16(buffer, 4, 0);
                    Utils.WriteUInt16(buffer, 6, 0);
                }
                Utils.WriteInt32(buffer, 8, sizeList[index]);
                Utils.WriteInt32(buffer, 12, offsetList[index]);
                stream.Write(buffer, 0, 16);
            }

            // Write each of the images.
            for (index = 0; index < image.NumFrames; ++index)
            {
                frame    = image.GetFrame(index);
                bitCount = Utils.FormatToBitCount(frame.pixelFormat);
                BmpWriter.SaveBitmapInfo
                    (stream, frame, bitCount,
                    (frame.Stride + frame.MaskStride) * frame.Height,
                    buffer, frame.Height * 2);
                BmpWriter.SaveBitmapData(stream, frame, false, false);
                BmpWriter.SaveBitmapData(stream, frame, true, true);
            }
        }
Esempio n. 12
0
        // Load a GIF image from the specified stream.  The first 4 bytes
        // have already been read and discarded.  We always load GIF's
        // as 8bpp because that makes it easier to handle decompression.
        // GIF's with lower bit depths will be expanded appropriately.
        public static void Load(Stream stream, PortableImage image)
        {
            byte[] buffer = new byte [1024];
            int    logicalWidth, logicalHeight;
            int    flags, bitCount, numColors, tag;

            int[] palette;
            int   transparentPixel;
            int   imageWidth, imageHeight;
            Frame frame;

            // Read the rest of the GIF header and validate it.
            if (stream.Read(buffer, 0, 9) != 9)
            {
                throw new FormatException();
            }
            if ((buffer[0] != (byte)'7' && buffer[0] != (byte)'9') ||
                buffer[1] != (byte)'a')
            {
                throw new FormatException();
            }
            logicalWidth  = Utils.ReadUInt16(buffer, 2);
            logicalHeight = Utils.ReadUInt16(buffer, 4);
            flags         = buffer[6];
            // buffer[7] is the background index, which we ignore.
            // buffer[8] is the aspect ratio, which we ignore.
            if (logicalWidth == 0 || logicalHeight == 0)
            {
                throw new FormatException();
            }

            // Set the global image information.
            bitCount          = (flags & 0x07) + 1;
            numColors         = (1 << bitCount);
            image.Width       = logicalWidth;
            image.Height      = logicalHeight;
            image.PixelFormat = PixelFormat.Format8bppIndexed;
            image.LoadFormat  = PortableImage.Gif;

            // Read the global color table, if present.
            if ((flags & 0x80) != 0)
            {
                image.Palette = ReadGifPalette(stream, buffer, numColors);
            }

            // Process the image and extension blocks in the image.
            transparentPixel = -1;
            while (stream.Read(buffer, 0, 1) == 1)
            {
                tag = buffer[0];
                if (tag == 0x2C)
                {
                    // Read the image descriptor.
                    if (stream.Read(buffer, 0, 9) != 9)
                    {
                        throw new FormatException();
                    }
                    imageWidth  = Utils.ReadUInt16(buffer, 4);
                    imageHeight = Utils.ReadUInt16(buffer, 6);
                    flags       = buffer[8];
                    if (imageWidth == 0 || imageHeight == 0)
                    {
                        throw new FormatException();
                    }
                    frame = image.AddFrame(imageWidth, imageHeight,
                                           image.PixelFormat);
                    frame.TransparentPixel = transparentPixel;
                    frame.OffsetX          = Utils.ReadUInt16(buffer, 0);
                    frame.OffsetY          = Utils.ReadUInt16(buffer, 2);
                    transparentPixel       = -1;

                    // Read the local color table, if any.
                    if ((flags & 0x80) != 0)
                    {
                        tag           = (1 << ((flags & 0x07) + 1));
                        frame.Palette = ReadGifPalette
                                            (stream, buffer, tag);
                    }

                    // Decompress the image into the frame.
                    Decompress(stream, buffer, frame, (flags & 0x40) != 0);
                }
                else if (tag == 0x21)
                {
                    // Process an extension.
                    if (stream.Read(buffer, 0, 1) != 1)
                    {
                        throw new FormatException();
                    }
                    if (buffer[0] == (byte)0xF9)
                    {
                        // Graphic control extension sub-block.
                        if (stream.Read(buffer, 0, 1) != 1)
                        {
                            throw new FormatException();
                        }
                        tag = buffer[0];
                        if (stream.Read(buffer, 0, tag) != tag)
                        {
                            throw new FormatException();
                        }
                        if (tag >= 4)
                        {
                            if ((buffer[0] & 0x01) != 0)
                            {
                                transparentPixel = buffer[3];
                            }
                            else
                            {
                                transparentPixel = -1;
                            }
                        }
                    }

                    // Skip the remaining extension sub-blocks.
                    SkipSubBlocks(stream, buffer);
                }
                else if (tag == 0x3B)
                {
                    // End of the GIF file.
                    break;
                }
                else
                {
                    // Invalid GIF file.
                    throw new FormatException();
                }
            }
        }
Esempio n. 13
0
        // Load a BMP image from the specified stream.  The first 4 bytes
        // have already been read and discarded.
        public static void Load(Stream stream, PortableImage image)
        {
            byte[] buffer = new byte [1024];
            int    width, height, planes, bitCount;
            int    compression;
            bool   quads;

            // Read the rest of the BITMAPFILEHEADER.
            if (stream.Read(buffer, 0, 10) != 10)
            {
                throw new FormatException();
            }
            int bfOffBits = Utils.ReadInt32(buffer, 6);

            // The current file offset at the end of the BITMAPFILEHEADER.
            int offset = 14;

            // Get the size of the BITMAPINFOHEADER structure that follows,
            // and then read it into the buffer.
            if (stream.Read(buffer, 0, 4) != 4)
            {
                throw new FormatException();
            }
            int size = Utils.ReadInt32(buffer, 0);

            if (size <= 4 || size > 1024)
            {
                throw new FormatException();
            }
            if (stream.Read(buffer, 4, size - 4) != (size - 4))
            {
                throw new FormatException();
            }
            offset += size;
            if (size >= 40)
            {
                // This is a BITMAPINFOHEADER structure (Windows bitmaps).
                width       = Utils.ReadInt32(buffer, 4);
                height      = Utils.ReadInt32(buffer, 8);
                planes      = Utils.ReadUInt16(buffer, 12);
                bitCount    = Utils.ReadUInt16(buffer, 14);
                compression = Utils.ReadInt32(buffer, 16);
                quads       = true;
            }
            else if (size == 12)
            {
                // This is a BITMAPCOREHEADER structure (OS/2 bitmaps).
                width       = Utils.ReadUInt16(buffer, 4);
                height      = Utils.ReadUInt16(buffer, 6);
                planes      = Utils.ReadUInt16(buffer, 8);
                bitCount    = Utils.ReadUInt16(buffer, 10);
                compression = 0;                                // BI_RGB
                quads       = false;
            }
            else
            {
                throw new FormatException();
            }

            // Perform a sanity check on the header values.
            if (width <= 0 || planes != 1)
            {
                throw new FormatException();
            }
            if (bitCount != 1 && bitCount != 4 && bitCount != 16 &&
                bitCount != 8 && bitCount != 24)
            {
                // TODO: non-traditional BMP formats.
                throw new FormatException();
            }
            if (compression != 0 && compression != 3 /*BI_BITFIELDS*/)
            {
                // TODO: RLE bitmaps
                throw new FormatException();
            }

            // Set the basic image properties.
            image.Width       = width;
            image.Height      = height < 0 ? -height : height;
            image.PixelFormat = Utils.BitCountToFormat(bitCount);
            image.LoadFormat  = PortableImage.Bmp;

            // Do the unusual 16 bit formats.
            if (compression == 3)
            {
                if (stream.Read(buffer, 0, 3 * 4) != (3 * 4))
                {
                    throw new FormatException();
                }
                int redMask   = Utils.ReadInt32(buffer, 0);
                int greenMask = Utils.ReadInt32(buffer, 4);
                int blueMask  = Utils.ReadInt32(buffer, 8);

                if (blueMask == 0x001F && redMask == 0x7C00 && greenMask == 0x03E0)
                {
                    image.PixelFormat = PixelFormat.Format16bppRgb555;
                }
                else if (blueMask == 0x001F && redMask == 0xF800 && greenMask == 0x07E0)
                {
                    image.PixelFormat = PixelFormat.Format16bppRgb565;
                }
                else
                {
                    throw new FormatException();
                }
            }

            // Read the palette into memory and set it.
            if (bitCount <= 8)
            {
                int   colors = (1 << bitCount);
                int   index;
                int[] palette = new int [colors];
                if (quads)
                {
                    // The RGB values are specified as RGBQUAD's.
                    if (stream.Read(buffer, 0, colors * 4) != (colors * 4))
                    {
                        throw new FormatException();
                    }
                    offset += colors * 4;
                    for (index = 0; index < colors; ++index)
                    {
                        palette[index] = Utils.ReadBGR(buffer, index * 4);
                    }
                }
                else
                {
                    // The RGB values are specified as RGBTRIPLE's.
                    if (stream.Read(buffer, 0, colors * 3) != (colors * 3))
                    {
                        throw new FormatException();
                    }
                    offset += colors * 3;
                    for (index = 0; index < colors; ++index)
                    {
                        palette[index] = Utils.ReadBGR(buffer, index * 3);
                    }
                }
                image.Palette = palette;
            }

            // Seek to the start of the bitmap data.
            Utils.Seek(stream, offset, bfOffBits);

            // Add a frame to the image object.
            Frame frame = image.AddFrame();

            // Load the bitmap data from the stream into the frame.
            LoadBitmapData(stream, frame, false, height > 0);
        }