void GImage::decodeBMP( BinaryInput& input) { // The BMP decoding uses these flags. static const uint16 PICTURE_NONE = 0x0000; static const uint16 PICTURE_BITMAP = 0x1000; // Compression Flags static const uint16 PICTURE_UNCOMPRESSED = 0x0100; static const uint16 PICTURE_MONOCHROME = 0x0001; static const uint16 PICTURE_4BIT = 0x0002; static const uint16 PICTURE_8BIT = 0x0004; static const uint16 PICTURE_16BIT = 0x0008; static const uint16 PICTURE_24BIT = 0x0010; static const uint16 PICTURE_32BIT = 0x0020; (void)PICTURE_16BIT; (void)PICTURE_32BIT; // This is a simple BMP loader that can handle uncompressed BMP files. // Verify this is a BMP file by looking for the BM tag. input.reset(); std::string tag = input.readString(2); if (tag != "BM") { throw Error("Not a BMP file", input.getFilename()); } m_channels = 3; // Skip to the BITMAPINFOHEADER's width and height input.skip(16); m_width = input.readUInt32(); m_height = input.readUInt32(); // Skip to the bit count and compression type input.skip(2); uint16 bitCount = input.readUInt16(); uint32 compressionType = input.readUInt32(); uint8 red; uint8 green; uint8 blue; uint8 blank; // Only uncompressed bitmaps are supported by this code if ((int32)compressionType != BI_RGB) { throw Error("BMP images must be uncompressed", input.getFilename()); } uint8* palette = NULL; // Create the palette if needed if (bitCount <= 8) { // Skip to the palette color count in the header input.skip(12); int numColors = input.readUInt32(); palette = (uint8*)System::malloc(numColors * 3); debugAssert(palette); // Skip past the end of the header to the palette info input.skip(4); int c; for (c = 0; c < numColors * 3; c += 3) { // Palette information in bitmaps is stored in BGR_ format. // That means it's blue-green-red-blank, for each entry. blue = input.readUInt8(); green = input.readUInt8(); red = input.readUInt8(); blank = input.readUInt8(); palette[c] = red; palette[c + 1] = green; palette[c + 2] = blue; } } int hStart = 0; int hEnd = 0; int hDir = 0; if (m_height < 0) { m_height = -m_height; hStart = 0; hEnd = m_height; hDir = 1; } else { //height = height; hStart = m_height - 1; hEnd = -1; hDir = -1; } m_byte = (uint8*)m_memMan->alloc(m_width * m_height * 3); debugAssert(m_byte); int BMScanWidth; int BMPadding; uint8 BMGroup; uint8 BMPixel8; int currPixel; int dest; int flags = PICTURE_NONE; if (bitCount == 1) { // Note that this file is not necessarily grayscale, since it's possible // the palette is blue-and-white, or whatever. But of course most image // programs only write 1-bit images if they're black-and-white. flags = PICTURE_BITMAP | PICTURE_UNCOMPRESSED | PICTURE_MONOCHROME; // For bitmaps, each scanline is dword-aligned. BMScanWidth = (m_width + 7) >> 3; if (BMScanWidth & 3) { BMScanWidth += 4 - (BMScanWidth & 3); } // Powers of 2 int pow2[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; for (int h = hStart; h != hEnd; h += hDir) { currPixel = 0; dest = 3 * h * m_width; for (int w = 0; w < BMScanWidth; ++w) { BMGroup = input.readUInt8(); // Now we read the pixels. Usually there are eight pixels per byte, // since each pixel is represented by one bit, but if the width // is not a multiple of eight, the last byte will have some bits // set, with the others just being extra. Plus there's the // dword-alignment padding. So we keep checking to see if we've // already read "width" number of pixels. for (int i = 7; i >= 0; --i) { if (currPixel < m_width) { int src = 3 * ((BMGroup & pow2[i]) >> i); m_byte[dest] = palette[src]; m_byte[dest + 1] = palette[src + 1]; m_byte[dest + 2] = palette[src + 2]; ++currPixel; dest += 3; } } } }