示例#1
0
        /// <summary>
        /// Parses a OS/2 version 2 bitmap header (64 bytes). Only the first 40 bytes are parsed which are
        /// very similar to the Bitmap v3 header. The other 24 bytes are ignored, but they do not hold any
        /// useful information for decoding the image.
        /// </summary>
        /// <param name="data">The data to parse.</param>
        /// <returns>The parsed header.</returns>
        /// <seealso href="https://www.fileformat.info/format/os2bmp/egff.htm"/>
        public static BmpInfoHeader ParseOs2Version2(ReadOnlySpan <byte> data)
        {
            var infoHeader = new BmpInfoHeader(
                headerSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(0, 4)),
                width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
                height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
                planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
                bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));

            int compression = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4));

            // The compression value in OS/2 bitmap has a different meaning than in windows bitmaps.
            // Map the OS/2 value to the windows values.
            switch (compression)
            {
            case 0:
                infoHeader.Compression = BmpCompression.RGB;
                break;

            case 1:
                infoHeader.Compression = BmpCompression.RLE8;
                break;

            case 2:
                infoHeader.Compression = BmpCompression.RLE4;
                break;

            case 4:
                infoHeader.Compression = BmpCompression.RLE24;
                break;

            default:
                // Compression type 3 (1DHuffman) is not supported.
                BmpThrowHelper.ThrowImageFormatException("Compression type is not supported. ImageSharp only supports uncompressed, RLE4, RLE8 and RLE24.");
                break;
            }

            infoHeader.ImageSize     = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4));
            infoHeader.XPelsPerMeter = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4));
            infoHeader.YPelsPerMeter = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(28, 4));
            infoHeader.ClrUsed       = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(32, 4));
            infoHeader.ClrImportant  = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(36, 4));

            // The following 24 bytes of the header are omitted.
            return(infoHeader);
        }
示例#2
0
        /// <summary>
        /// Produce uncompressed bitmap data from a RLE8 stream.
        /// </summary>
        /// <remarks>
        /// RLE8 is a 2-byte run-length encoding.
        /// <br/>If first byte is 0, the second byte may have special meaning.
        /// <br/>Otherwise, the first byte is the length of the run and second byte is the color for the run.
        /// </remarks>
        /// <param name="w">The width of the bitmap.</param>
        /// <param name="buffer">Buffer for uncompressed data.</param>
        private void UncompressRle8(int w, Span <byte> buffer)
        {
#if NETCOREAPP2_1
            Span <byte> cmd = stackalloc byte[2];
#else
            byte[] cmd = new byte[2];
#endif
            int count = 0;

            while (count < buffer.Length)
            {
                if (this.stream.Read(cmd, 0, cmd.Length) != 2)
                {
                    BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from stream while uncompressing RLE8 bitmap.");
                }

                if (cmd[0] == RleCommand)
                {
                    switch (cmd[1])
                    {
                    case RleEndOfBitmap:
                        return;

                    case RleEndOfLine:
                        int extra = count % w;
                        if (extra > 0)
                        {
                            count += w - extra;
                        }

                        break;

                    case RleDelta:
                        int dx = this.stream.ReadByte();
                        int dy = this.stream.ReadByte();
                        count += (w * dy) + dx;

                        break;

                    default:
                        // If the second byte > 2, we are in 'absolute mode'
                        // Take this number of bytes from the stream as uncompressed data
                        int length = cmd[1];

                        byte[] run = new byte[length];

                        this.stream.Read(run, 0, run.Length);

                        run.AsSpan().CopyTo(buffer.Slice(count));

                        count += run.Length;

                        // Absolute mode data is aligned to two-byte word-boundary
                        int padding = length & 1;

                        this.stream.Skip(padding);

                        break;
                    }
                }
                else
                {
                    int  max  = count + cmd[0]; // as we start at the current count in the following loop, max is count + cmd[0]
                    byte cmd1 = cmd[1];         // store the value to avoid the repeated indexer access inside the loop

                    for (; count < max; count++)
                    {
                        buffer[count] = cmd1;
                    }
                }
            }
        }
示例#3
0
        /// <summary>
        /// Produce uncompressed bitmap data from a RLE4 stream.
        /// </summary>
        /// <remarks>
        /// RLE4 is a 2-byte run-length encoding.
        /// <br/>If first byte is 0, the second byte may have special meaning.
        /// <br/>Otherwise, the first byte is the length of the run and second byte contains two color indexes.
        /// </remarks>
        /// <param name="w">The width of the bitmap.</param>
        /// <param name="buffer">Buffer for uncompressed data.</param>
        private void UncompressRle4(int w, Span <byte> buffer)
        {
#if NETCOREAPP2_1
            Span <byte> cmd = stackalloc byte[2];
#else
            byte[] cmd = new byte[2];
#endif
            int count = 0;

            while (count < buffer.Length)
            {
                if (this.stream.Read(cmd, 0, cmd.Length) != 2)
                {
                    BmpThrowHelper.ThrowImageFormatException("Failed to read 2 bytes from the stream while uncompressing RLE4 bitmap.");
                }

                if (cmd[0] == RleCommand)
                {
                    switch (cmd[1])
                    {
                    case RleEndOfBitmap:
                        return;

                    case RleEndOfLine:
                        int extra = count % w;
                        if (extra > 0)
                        {
                            count += w - extra;
                        }

                        break;

                    case RleDelta:
                        int dx = this.stream.ReadByte();
                        int dy = this.stream.ReadByte();
                        count += (w * dy) + dx;

                        break;

                    default:
                        // If the second byte > 2, we are in 'absolute mode'.
                        // The second byte contains the number of color indexes that follow.
                        int max         = cmd[1];
                        int bytesToRead = (max + 1) / 2;

                        byte[] run = new byte[bytesToRead];

                        this.stream.Read(run, 0, run.Length);

                        int idx = 0;
                        for (int i = 0; i < max; i++)
                        {
                            byte twoPixels = run[idx];
                            if (i % 2 == 0)
                            {
                                byte leftPixel = (byte)((twoPixels >> 4) & 0xF);
                                buffer[count++] = leftPixel;
                            }
                            else
                            {
                                byte rightPixel = (byte)(twoPixels & 0xF);
                                buffer[count++] = rightPixel;
                                idx++;
                            }
                        }

                        // Absolute mode data is aligned to two-byte word-boundary
                        int padding = bytesToRead & 1;

                        this.stream.Skip(padding);

                        break;
                    }
                }
                else
                {
                    int max = cmd[0];

                    // The second byte contains two color indexes, one in its high-order 4 bits and one in its low-order 4 bits.
                    byte twoPixels  = cmd[1];
                    byte rightPixel = (byte)(twoPixels & 0xF);
                    byte leftPixel  = (byte)((twoPixels >> 4) & 0xF);

                    for (int idx = 0; idx < max; idx++)
                    {
                        if (idx % 2 == 0)
                        {
                            buffer[count] = leftPixel;
                        }
                        else
                        {
                            buffer[count] = rightPixel;
                        }

                        count++;
                    }
                }
            }
        }