Skip to content

Commit

Permalink
Merged Ryan's change to fix BMP loading in http://hg.libsdl.org/SDL/r…
Browse files Browse the repository at this point in the history
…ev/08f3b56969b1

Deal with various .bmp file format variants in SDL_LoadBMP_RW().

This helps when modern versions of The Gimp (and lots of other things)
produces a 32-bit bitmap with an alpha channel, or anything with "BI_BITFIELDS"
format, since that data is now embedded in the bitmap info header instead of
directly following it and we would accidentally skip over embedded versions of
it.

Fixes Bugzilla #2714.
  • Loading branch information
slouken committed Jun 13, 2015
1 parent 78f95c0 commit 467c7ea
Showing 1 changed file with 81 additions and 71 deletions.
152 changes: 81 additions & 71 deletions IMG_bmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,15 +225,17 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
int bmpPitch;
int i, pad;
SDL_Surface *surface;
Uint32 Rmask;
Uint32 Gmask;
Uint32 Bmask;
Uint32 Amask;
Uint32 Rmask = 0;
Uint32 Gmask = 0;
Uint32 Bmask = 0;
Uint32 Amask = 0;
SDL_Palette *palette;
Uint8 *bits;
Uint8 *top, *end;
SDL_bool topDown;
int ExpandBMP;
SDL_bool haveRGBMasks = SDL_FALSE;
SDL_bool haveAlphaMask = SDL_FALSE;
SDL_bool correctAlpha = SDL_FALSE;

/* The Win32 BMP file header (14 bytes) */
Expand Down Expand Up @@ -284,7 +286,7 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)

/* Read the Win32 BITMAPINFOHEADER */
biSize = SDL_ReadLE32(src);
if ( biSize == 12 ) {
if ( biSize == 12 ) { /* really old BITMAPCOREHEADER */
biWidth = (Uint32)SDL_ReadLE16(src);
biHeight = (Uint32)SDL_ReadLE16(src);
biPlanes = SDL_ReadLE16(src);
Expand All @@ -295,9 +297,8 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
biYPelsPerMeter = 0;
biClrUsed = 0;
biClrImportant = 0;
} else {
const unsigned int headerSize = 40;

} else if (biSize >= 40) { /* some version of BITMAPINFOHEADER */
Uint32 headerSize;
biWidth = SDL_ReadLE32(src);
biHeight = SDL_ReadLE32(src);
biPlanes = SDL_ReadLE16(src);
Expand All @@ -309,6 +310,46 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
biClrUsed = SDL_ReadLE32(src);
biClrImportant = SDL_ReadLE32(src);

/* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
if (biSize != 64) {
/* This is complicated. If compression is BI_BITFIELDS, then
we have 3 DWORDS that specify the RGB masks. This is either
stored here in an BITMAPV2INFOHEADER (which only differs in
that it adds these RGB masks) and biSize >= 52, or we've got
these masks stored in the exact same place, but strictly
speaking, this is the bmiColors field in BITMAPINFO immediately
following the legacy v1 info header, just past biSize. */
if (biCompression == BI_BITFIELDS) {
haveRGBMasks = SDL_TRUE;
Rmask = SDL_ReadLE32(src);
Gmask = SDL_ReadLE32(src);
Bmask = SDL_ReadLE32(src);

/* ...v3 adds an alpha mask. */
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
haveAlphaMask = SDL_TRUE;
Amask = SDL_ReadLE32(src);
}
} else {
/* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
if (biSize >= 52) { /* BITMAPV2INFOHEADER; adds RGB masks */
/*Rmask = */ SDL_ReadLE32(src);
/*Gmask = */ SDL_ReadLE32(src);
/*Bmask = */ SDL_ReadLE32(src);
}
if (biSize >= 56) { /* BITMAPV3INFOHEADER; adds alpha mask */
/*Amask = */ SDL_ReadLE32(src);
}
}

/* Insert other fields here; Wikipedia and MSDN say we're up to
v5 of this header, but we ignore those for now (they add gamma,
color spaces, etc). Ignoring the weird OS/2 2.x format, we
currently parse up to v3 correctly (hopefully!). */
}

/* skip any header bytes we didn't handle... */
headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
if (biSize > headerSize) {
SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
}
Expand All @@ -321,7 +362,7 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
}

/* Check for read error */
if ( strcmp(SDL_GetError(), "") != 0 ) {
if (SDL_strcmp(SDL_GetError(), "") != 0) {
was_error = SDL_TRUE;
goto done;
}
Expand All @@ -339,78 +380,47 @@ static SDL_Surface *LoadBMP_RW (SDL_RWops *src, int freesrc)
}

/* RLE4 and RLE8 BMP compression is supported */
Rmask = Gmask = Bmask = Amask = 0;
switch (biCompression) {
case BI_RGB:
/* If there are no masks, use the defaults */
if ( bfOffBits == (14+biSize) ) {
/* Default values for the BMP format */
switch (biBitCount) {
case 15:
case 16:
Rmask = 0x7C00;
Gmask = 0x03E0;
Bmask = 0x001F;
break;
case 24:
SDL_assert(!haveRGBMasks);
SDL_assert(!haveAlphaMask);
/* Default values for the BMP format */
switch (biBitCount) {
case 15:
case 16:
Rmask = 0x7C00;
Gmask = 0x03E0;
Bmask = 0x001F;
break;
case 24:
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
Rmask = 0x000000FF;
Gmask = 0x0000FF00;
Bmask = 0x00FF0000;
#else
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
#endif
break;
case 32:
/* We don't know if this has alpha channel or not */
correctAlpha = SDL_TRUE;
Amask = 0xFF000000;
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
break;
default:
break;
}
break;
case 32:
/* We don't know if this has alpha channel or not */
correctAlpha = SDL_TRUE;
Amask = 0xFF000000;
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
break;
default:
break;
}
/* Fall through -- read the RGB masks */
break;

default:
switch (biBitCount) {
case 15:
case 16:
Rmask = SDL_ReadLE32(src);
Gmask = SDL_ReadLE32(src);
Bmask = SDL_ReadLE32(src);
break;
case 32:
Rmask = SDL_ReadLE32(src);
Gmask = SDL_ReadLE32(src);
Bmask = SDL_ReadLE32(src);
Amask = SDL_ReadLE32(src);
case BI_BITFIELDS:
break; /* we handled this in the info header. */

/* ImageMagick seems to put out bogus masks here. Pick a default. */
if ((Rmask == 0xFFFFFF) && (Gmask == 0xFFFFFF) &&
(Bmask == 0xFFFFFF) && (Amask == 0xFFFFFF) ) {
Amask = 0xFF000000;
Rmask = 0x00FF0000;
Gmask = 0x0000FF00;
Bmask = 0x000000FF;
} else if ((Rmask == 0xFFFFFF00) && (Gmask == 0xFFFFFF00) &&
(Bmask == 0xFFFFFF00) && (Amask == 0xFFFFFF00) ) {
/* argh, The Gimp seems to put out different bogus masks! */
Amask = 0x000000FF;
Rmask = 0xFF000000;
Gmask = 0x00FF0000;
Bmask = 0x0000FF00;
}
break;
default:
break;
}
default:
break;
}

Expand Down

0 comments on commit 467c7ea

Please sign in to comment.