Skip to content

Commit

Permalink
Common: support loading BMPs with extended headers (only formally)
Browse files Browse the repository at this point in the history
This lets them to be recognized, but does not guarantee that any advanced pixel data is retrieved correctly.
For me this fixes loading 32-bit BMPs created by some painting software.
  • Loading branch information
ivan-mogilko committed Jan 5, 2025
1 parent d956285 commit fd272e2
Showing 1 changed file with 22 additions and 11 deletions.
33 changes: 22 additions & 11 deletions Common/gfx/image_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ static void bmp_read_image(Stream *in, PixelBuffer &pxdata, const BMP_InfoHeader
/* bmp_read_RLE8_compressed_image:
* For reading the 8 bit RLE compressed BMP image format.
*/
static void bmp_read_RLE8_compressed_image(Stream *in, PixelBuffer &pxdata, BMP_InfoHeader &hdr)
static void bmp_read_RLE8_compressed_image(Stream *in, PixelBuffer &pxdata, const BMP_InfoHeader &hdr)
{
unsigned char count, val, val0;
int j, pos, line;
Expand Down Expand Up @@ -326,7 +326,7 @@ static void bmp_read_RLE8_compressed_image(Stream *in, PixelBuffer &pxdata, BMP_
/* bmp_read_RLE4_compressed_image:
* For reading the 4 bit RLE compressed BMP image format.
*/
static void bmp_read_RLE4_compressed_image(Stream *in, PixelBuffer &pxdata, BMP_InfoHeader &hdr)
static void bmp_read_RLE4_compressed_image(Stream *in, PixelBuffer &pxdata, const BMP_InfoHeader &hdr)
{
unsigned char b[8];
unsigned char count;
Expand Down Expand Up @@ -405,7 +405,7 @@ static void bmp_read_RLE4_compressed_image(Stream *in, PixelBuffer &pxdata, BMP_
/* bmp_read_bitfields_image:
* For reading the bitfield compressed BMP image format.
*/
static void bmp_read_bitfields_image(Stream *in, PixelBuffer &pxdata, BMP_InfoHeader &hdr)
static void bmp_read_bitfields_image(Stream *in, PixelBuffer &pxdata, const BMP_InfoHeader &hdr)
{
int k, i, line, height, dir;
int color_depth;
Expand Down Expand Up @@ -556,6 +556,11 @@ bool SaveBMP(const BitmapData &bmp, const RGB *pal, Stream *out) {

PixelBuffer LoadBMP(Stream *in, RGB *pal) {
BMP_InfoHeader hdr;
int rMask = 0;
int gMask = 0;
int bMask = 0;

const soff_t format_at = in->GetPosition(); // starting offset

int16_t bmpType = in->ReadInt16(); /* file type */
hdr.bfSize = in->ReadInt32(); /* size of the BMP file in bytes */
Expand Down Expand Up @@ -588,7 +593,7 @@ PixelBuffer LoadBMP(Stream *in, RGB *pal) {
hdr.importantColorsCount = 0;

bmp_read_palette(hdr.offsetBits - 26, pal, in, true);
} else if(hdr.headerSize == BMP_INFO_HEADER_SIZE) {
} else if (hdr.headerSize >= BMP_INFO_HEADER_SIZE) {
hdr.w = in->ReadInt32(); /* bitmap width in pixels (signed integer) */
hdr.h = in->ReadInt32(); /* bitmap height in pixels (signed integer) */
hdr.colorPlanes = in->ReadInt16(); /* number of color planes (must be 1) */
Expand All @@ -601,7 +606,11 @@ PixelBuffer LoadBMP(Stream *in, RGB *pal) {
hdr.colorsCount = in->ReadInt32(); /* number of colors in the color palette */
hdr.importantColorsCount = in->ReadInt32(); /* number of important colors used */

if(hdr.compression != kBI_BitFields) {
if(hdr.compression == kBI_BitFields) {
rMask = in->ReadInt32();
gMask = in->ReadInt32();
bMask = in->ReadInt32();
} else {
bmp_read_palette(hdr.offsetBits - 54, pal, in, false);
}
} else {
Expand All @@ -612,11 +621,10 @@ PixelBuffer LoadBMP(Stream *in, RGB *pal) {
w = hdr.w;
h = std::abs(hdr.h);

if(hdr.compression == kBI_BitFields) {
int rMask = in->ReadInt32();
/*int gMask =*/ in->ReadInt32();
int bMask = in->ReadInt32();

// Check RGB bit masks.
// TODO: normally we should deduce bit shifts and pass this information
// further into bmp_read_bitfields_image(), where these will be used
if (hdr.compression == kBI_BitFields) {
if ((bMask == 0x001f) && (rMask == 0x7C00)) {
bpp = 15;
} else if ((bMask == 0x001f) && (rMask == 0xF800)) {
Expand All @@ -640,6 +648,9 @@ PixelBuffer LoadBMP(Stream *in, RGB *pal) {
return {};
}

// Set right to the pixel data, possibly skip any unused fields from advanced versions
in->Seek(format_at + hdr.offsetBits, kSeekBegin);

switch (hdr.compression) {
case kBI_RGB_None:
bmp_read_image(in, pxdata, hdr);
Expand All @@ -654,7 +665,7 @@ PixelBuffer LoadBMP(Stream *in, RGB *pal) {
bmp_read_bitfields_image(in, pxdata, hdr);
break;
default:
return {};
return {}; // unsupported compression type
}

return std::move(pxdata);
Expand Down

0 comments on commit fd272e2

Please sign in to comment.