Stores general information about the Bitmap file.
The first two bytes of the Bitmap file format (thus the Bitmap header) are stored in big-endian order. All of the other integer values are stored in little-endian format (i.e. least-significant byte first).
Exemplo n.º 1
0
        /// <summary>
        /// Encodes the provided BGRA pixel data to a 24bit BMP image.
        /// </summary>
        /// <param name="pixelData">The date to encode.</param>
        /// <param name="width">The width of the image in the data.</param>
        /// <param name="height">The height of the image in the data.</param>
        /// <returns>A 24bit BMP image as bytes.</returns>
        public static byte[] Encode(byte[] pixelData, int width, int height)
        {
            int rowWidth = width;
            int amount   = width * 3 % 4;

            if (amount != 0)
            {
                rowWidth += 4 - amount;
            }

            int fileSize = BmpFileHeader.DEFAULT_OFFSET + height * rowWidth * 3;
            var output   = new byte[fileSize];

            using (var writer = new BinaryWriter(new MemoryStream(output)))
            {
                var fileHeader = new BmpFileHeader
                {
                    FileSize     = fileSize,
                    Height       = height,
                    Width        = width,
                    BitsPerPixel = 24,
                    Planes       = 1,
                    ImageSize    = fileSize - BmpFileHeader.DEFAULT_OFFSET,
                    ClrUsed      = 0,
                    ClrImportant = 0
                };
                writer.Write(fileHeader.Type);
                writer.Write(fileHeader.FileSize);
                writer.Write(fileHeader.Reserved);
                writer.Write(fileHeader.Offset);
                writer.Write(fileHeader.HeaderSize);
                writer.Write(fileHeader.Width);
                writer.Write(fileHeader.Height);
                writer.Write(fileHeader.Planes);
                writer.Write(fileHeader.BitsPerPixel);
                writer.Write(fileHeader.Compression);
                writer.Write(fileHeader.ImageSize);
                writer.Write(fileHeader.XPelsPerMeter);
                writer.Write(fileHeader.YPelsPerMeter);
                writer.Write(fileHeader.ClrUsed);
                writer.Write(fileHeader.ClrImportant);

                if (amount != 0)
                {
                    amount = 4 - amount;
                }

                for (int y = height - 1; y >= 0; y--)
                {
                    for (var x = 0; x < width; x++)
                    {
                        int offset = (y * width + x) * 4;

                        writer.Write(pixelData[offset + 0]);
                        writer.Write(pixelData[offset + 1]);
                        writer.Write(pixelData[offset + 2]);
                    }

                    for (var i = 0; i < amount; i++)
                    {
                        writer.Write((byte)0);
                    }
                }
            }

            return(output);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Decode the provided bmp to a BGRA pixel array.
        /// Supported formats are:
        /// - 1, 4, and 8 bit BMP, tested with up to 256 colors.
        /// - 16bit BMP (untested)
        /// - 24bit BMP
        /// - 32bit BMP (untested)
        /// </summary>
        /// <param name="bmpData">The bmp file as bytes to decode.</param>
        /// <param name="fileHeader">The header of the file. Contains information such as the size of the image.</param>
        /// <returns>An RGBA pixel array extracted from the BMP.</returns>
        public static byte[] Decode(ReadOnlyMemory <byte> bmpData, out BmpFileHeader fileHeader)
        {
            using var reader = new ByteReader(bmpData);

            fileHeader = new BmpFileHeader
            {
                Type     = reader.ReadInt16(),
                FileSize = reader.ReadInt32(),
                Reserved = reader.ReadInt32(),
                Offset   = reader.ReadInt32(),

                // Second header
                HeaderSize    = reader.ReadInt32(),
                Width         = reader.ReadInt32(),
                Height        = reader.ReadInt32(),
                Planes        = reader.ReadInt16(),
                BitsPerPixel  = reader.ReadInt16(),
                Compression   = reader.ReadInt32(),
                ImageSize     = reader.ReadInt32(),
                XPelsPerMeter = reader.ReadInt32(),
                YPelsPerMeter = reader.ReadInt32(),
                ClrUsed       = reader.ReadInt32(),
                ClrImportant  = reader.ReadInt32()
            };

            if (fileHeader.Compression != 0)
            {
                throw new Exception($"Unsupported BMP compression - {fileHeader.Compression}");
            }

            int colorMapSize = -1;

            if (fileHeader.ClrUsed == 0)
            {
                if (fileHeader.BitsPerPixel == 1 ||
                    fileHeader.BitsPerPixel == 4 ||
                    fileHeader.BitsPerPixel == 8)
                {
                    colorMapSize = (int)Math.Pow(2, fileHeader.BitsPerPixel) * 4;
                }
            }
            else
            {
                colorMapSize = fileHeader.ClrUsed * 4;
            }

            ReadOnlySpan <byte> palette = null;

            if (colorMapSize > 0)
            {
                palette = reader.ReadBytes(colorMapSize);
            }

            ReadOnlySpan <byte> pixelIn = reader.ReadBytes(fileHeader.ImageSize);
            var pixelOut = new byte[fileHeader.Width * fileHeader.Height * 4];

            if (fileHeader.HeaderSize != 40)
            {
                throw new Exception(
                          $"Header Size value '{fileHeader.HeaderSize}' is not valid.");
            }

            if (fileHeader.BitsPerPixel == 32)
            {
                ReadRgb32(pixelIn, pixelOut, fileHeader.Width, fileHeader.Height);
            }
            else if (fileHeader.BitsPerPixel == 24)
            {
                ReadRgb24(pixelIn, pixelOut, fileHeader.Width, fileHeader.Height);
            }
            else if (fileHeader.BitsPerPixel == 16)
            {
                ReadRgb16(pixelIn, pixelOut, fileHeader.Width, fileHeader.Height);
            }
            else if (fileHeader.BitsPerPixel <= 8)
            {
                ReadRgbPalette(
                    pixelIn,
                    pixelOut,
                    palette,
                    fileHeader.Width,
                    fileHeader.Height,
                    fileHeader.BitsPerPixel);
            }

            return(pixelOut);
        }