Fixed bug 1943 - Wrong handling of legacy 32bpp BMP files
authorSam Lantinga <slouken@libsdl.org>
Sun, 07 Jul 2013 18:23:04 -0700
changeset 73783d5f62bac8e7
parent 7377 489d5c90e9da
child 7379 b27c778a2bdb
Fixed bug 1943 - Wrong handling of legacy 32bpp BMP files

Kang Seonghoon

While BMP format supports alpha channel, it is enabled only when the header is at least 56 bytes long (BITMAPV3INFOHEADER and later). For very common 40-byte-long header (BITMAPINFOHEADER) 32bpp format should be interpreted as BGRX format, but currently SDL interprets them as BGRA format and causes a significant compatibility problem as many 32bpp files use a padding byte of 0 ("transparent" in BGRA interpretation).

---

I fixed this by checking to see if the alpha channel is all 0, and if so, setting it opaque.
src/video/SDL_bmp.c
     1.1 --- a/src/video/SDL_bmp.c	Sun Jul 07 20:06:08 2013 -0400
     1.2 +++ b/src/video/SDL_bmp.c	Sun Jul 07 18:23:04 2013 -0700
     1.3 @@ -47,6 +47,35 @@
     1.4  #endif
     1.5  
     1.6  
     1.7 +static void CorrectAlphaChannel(SDL_Surface *surface)
     1.8 +{
     1.9 +    /* Check to see if there is any alpha channel data */
    1.10 +    SDL_bool hasAlpha = SDL_FALSE;
    1.11 +#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    1.12 +    int alphaChannelOffset = 0;
    1.13 +#else
    1.14 +    int alphaChannelOffset = 3;
    1.15 +#endif
    1.16 +    Uint8 *alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
    1.17 +    Uint8 *end = alpha + surface->h * surface->pitch;
    1.18 +
    1.19 +    while (alpha < end) {
    1.20 +        if (*alpha != 0) {
    1.21 +            hasAlpha = SDL_TRUE;
    1.22 +            break;
    1.23 +        }
    1.24 +        alpha += 4;
    1.25 +    }
    1.26 +
    1.27 +    if (!hasAlpha) {
    1.28 +        alpha = ((Uint8*)surface->pixels) + alphaChannelOffset;
    1.29 +        while (alpha < end) {
    1.30 +            *alpha = SDL_ALPHA_OPAQUE;
    1.31 +            alpha += 4;
    1.32 +        }
    1.33 +    }
    1.34 +}
    1.35 +
    1.36  SDL_Surface *
    1.37  SDL_LoadBMP_RW(SDL_RWops * src, int freesrc)
    1.38  {
    1.39 @@ -64,6 +93,7 @@
    1.40      Uint8 *top, *end;
    1.41      SDL_bool topDown;
    1.42      int ExpandBMP;
    1.43 +    SDL_bool correctAlpha = SDL_FALSE;
    1.44  
    1.45      /* The Win32 BMP file header (14 bytes) */
    1.46      char magic[2];
    1.47 @@ -182,6 +212,8 @@
    1.48  #endif
    1.49                  break;
    1.50              case 32:
    1.51 +                /* We don't know if this has alpha channel or not */
    1.52 +                correctAlpha = SDL_TRUE;
    1.53                  Amask = 0xFF000000;
    1.54                  Rmask = 0x00FF0000;
    1.55                  Gmask = 0x0000FF00;
    1.56 @@ -358,6 +390,9 @@
    1.57              bits -= surface->pitch;
    1.58          }
    1.59      }
    1.60 +    if (correctAlpha) {
    1.61 +        CorrectAlphaChannel(surface);
    1.62 +    }
    1.63    done:
    1.64      if (was_error) {
    1.65          if (src) {