src/video/SDL_bmp.c
changeset 9126 08f3b56969b1
parent 9001 c750aab87e82
child 9334 5eb5ab33286e
     1.1 --- a/src/video/SDL_bmp.c	Sat Sep 06 23:20:14 2014 +0200
     1.2 +++ b/src/video/SDL_bmp.c	Mon Sep 08 01:36:22 2014 -0400
     1.3 @@ -85,15 +85,17 @@
     1.4      int bmpPitch;
     1.5      int i, pad;
     1.6      SDL_Surface *surface;
     1.7 -    Uint32 Rmask;
     1.8 -    Uint32 Gmask;
     1.9 -    Uint32 Bmask;
    1.10 -    Uint32 Amask;
    1.11 +    Uint32 Rmask = 0;
    1.12 +    Uint32 Gmask = 0;
    1.13 +    Uint32 Bmask = 0;
    1.14 +    Uint32 Amask = 0;
    1.15      SDL_Palette *palette;
    1.16      Uint8 *bits;
    1.17      Uint8 *top, *end;
    1.18      SDL_bool topDown;
    1.19      int ExpandBMP;
    1.20 +    SDL_bool haveRGBMasks = SDL_FALSE;
    1.21 +    SDL_bool haveAlphaMask = SDL_FALSE;
    1.22      SDL_bool correctAlpha = SDL_FALSE;
    1.23  
    1.24      /* The Win32 BMP file header (14 bytes) */
    1.25 @@ -144,15 +146,14 @@
    1.26  
    1.27      /* Read the Win32 BITMAPINFOHEADER */
    1.28      biSize = SDL_ReadLE32(src);
    1.29 -    if (biSize == 12) {
    1.30 +    if (biSize == 12) {   /* really old BITMAPCOREHEADER */
    1.31          biWidth = (Uint32) SDL_ReadLE16(src);
    1.32          biHeight = (Uint32) SDL_ReadLE16(src);
    1.33          /* biPlanes = */ SDL_ReadLE16(src);
    1.34          biBitCount = SDL_ReadLE16(src);
    1.35          biCompression = BI_RGB;
    1.36 -    } else {
    1.37 -        const unsigned int headerSize = 40;
    1.38 -
    1.39 +    } else if (biSize >= 40) {  /* some version of BITMAPINFOHEADER */
    1.40 +        Uint32 headerSize;
    1.41          biWidth = SDL_ReadLE32(src);
    1.42          biHeight = SDL_ReadLE32(src);
    1.43          /* biPlanes = */ SDL_ReadLE16(src);
    1.44 @@ -164,6 +165,54 @@
    1.45          biClrUsed = SDL_ReadLE32(src);
    1.46          /* biClrImportant = */ SDL_ReadLE32(src);
    1.47  
    1.48 +        /* 64 == BITMAPCOREHEADER2, an incompatible OS/2 2.x extension. Skip this stuff for now. */
    1.49 +        if (biSize == 64) {
    1.50 +            /* ignore these extra fields. */
    1.51 +            if (biCompression == BI_BITFIELDS) {
    1.52 +                /* this value is actually huffman compression in this variant. */
    1.53 +                SDL_SetError("Compressed BMP files not supported");
    1.54 +                was_error = SDL_TRUE;
    1.55 +                goto done;
    1.56 +            }
    1.57 +        } else {
    1.58 +            /* This is complicated. If compression is BI_BITFIELDS, then
    1.59 +               we have 3 DWORDS that specify the RGB masks. This is either
    1.60 +               stored here in an BITMAPV2INFOHEADER (which only differs in
    1.61 +               that it adds these RGB masks) and biSize >= 52, or we've got
    1.62 +               these masks stored in the exact same place, but strictly
    1.63 +               speaking, this is the bmiColors field in BITMAPINFO immediately
    1.64 +               following the legacy v1 info header, just past biSize. */
    1.65 +            if (biCompression == BI_BITFIELDS) {
    1.66 +                haveRGBMasks = SDL_TRUE;
    1.67 +                Rmask = SDL_ReadLE32(src);
    1.68 +                Gmask = SDL_ReadLE32(src);
    1.69 +                Bmask = SDL_ReadLE32(src);
    1.70 +
    1.71 +                /* ...v3 adds an alpha mask. */
    1.72 +                if (biSize >= 56) {  /* BITMAPV3INFOHEADER; adds alpha mask */
    1.73 +                    haveAlphaMask = SDL_TRUE;
    1.74 +                    Amask = SDL_ReadLE32(src);
    1.75 +                }
    1.76 +            } else {
    1.77 +                /* the mask fields are ignored for v2+ headers if not BI_BITFIELD. */
    1.78 +                if (biSize >= 52) {  /* BITMAPV2INFOHEADER; adds RGB masks */
    1.79 +                    /*Rmask = */ SDL_ReadLE32(src);
    1.80 +                    /*Gmask = */ SDL_ReadLE32(src);
    1.81 +                    /*Bmask = */ SDL_ReadLE32(src);
    1.82 +                }
    1.83 +                if (biSize >= 56) {  /* BITMAPV3INFOHEADER; adds alpha mask */
    1.84 +                    /*Amask = */ SDL_ReadLE32(src);
    1.85 +                }
    1.86 +            }
    1.87 +
    1.88 +            /* Insert other fields here; Wikipedia and MSDN say we're up to
    1.89 +               v5 of this header, but we ignore those for now (they add gamma,
    1.90 +               color spaces, etc). Ignoring the weird OS/2 2.x format, we
    1.91 +               currently parse up to v3 correctly (hopefully!). */
    1.92 +        }
    1.93 +
    1.94 +        /* skip any header bytes we didn't handle... */
    1.95 +        headerSize = (Uint32) (SDL_RWtell(src) - (fp_offset + 14));
    1.96          if (biSize > headerSize) {
    1.97              SDL_RWseek(src, (biSize - headerSize), RW_SEEK_CUR);
    1.98          }
    1.99 @@ -194,80 +243,46 @@
   1.100      }
   1.101  
   1.102      /* We don't support any BMP compression right now */
   1.103 -    Rmask = Gmask = Bmask = Amask = 0;
   1.104      switch (biCompression) {
   1.105      case BI_RGB:
   1.106          /* If there are no masks, use the defaults */
   1.107 -        if (bfOffBits == (14 + biSize)) {
   1.108 -            /* Default values for the BMP format */
   1.109 -            switch (biBitCount) {
   1.110 -            case 15:
   1.111 -            case 16:
   1.112 -                Rmask = 0x7C00;
   1.113 -                Gmask = 0x03E0;
   1.114 -                Bmask = 0x001F;
   1.115 -                break;
   1.116 -            case 24:
   1.117 -#if SDL_BYTEORDER == SDL_BIG_ENDIAN
   1.118 -                Rmask = 0x000000FF;
   1.119 -                Gmask = 0x0000FF00;
   1.120 -                Bmask = 0x00FF0000;
   1.121 -#else
   1.122 -                Rmask = 0x00FF0000;
   1.123 -                Gmask = 0x0000FF00;
   1.124 -                Bmask = 0x000000FF;
   1.125 -#endif
   1.126 -                break;
   1.127 -            case 32:
   1.128 -                /* We don't know if this has alpha channel or not */
   1.129 -                correctAlpha = SDL_TRUE;
   1.130 -                Amask = 0xFF000000;
   1.131 -                Rmask = 0x00FF0000;
   1.132 -                Gmask = 0x0000FF00;
   1.133 -                Bmask = 0x000000FF;
   1.134 -                break;
   1.135 -            default:
   1.136 -                break;
   1.137 -            }
   1.138 -            break;
   1.139 -        }
   1.140 -        /* Fall through -- read the RGB masks */
   1.141 -
   1.142 -    case BI_BITFIELDS:
   1.143 +        SDL_assert(!haveRGBMasks);
   1.144 +        SDL_assert(!haveAlphaMask);
   1.145 +        /* Default values for the BMP format */
   1.146          switch (biBitCount) {
   1.147          case 15:
   1.148          case 16:
   1.149 -            Rmask = SDL_ReadLE32(src);
   1.150 -            Gmask = SDL_ReadLE32(src);
   1.151 -            Bmask = SDL_ReadLE32(src);
   1.152 +            Rmask = 0x7C00;
   1.153 +            Gmask = 0x03E0;
   1.154 +            Bmask = 0x001F;
   1.155 +            break;
   1.156 +        case 24:
   1.157 +#if SDL_BYTEORDER == SDL_BIG_ENDIAN
   1.158 +            Rmask = 0x000000FF;
   1.159 +            Gmask = 0x0000FF00;
   1.160 +            Bmask = 0x00FF0000;
   1.161 +#else
   1.162 +            Rmask = 0x00FF0000;
   1.163 +            Gmask = 0x0000FF00;
   1.164 +            Bmask = 0x000000FF;
   1.165 +#endif
   1.166              break;
   1.167          case 32:
   1.168 -            Rmask = SDL_ReadLE32(src);
   1.169 -            Gmask = SDL_ReadLE32(src);
   1.170 -            Bmask = SDL_ReadLE32(src);
   1.171 -            Amask = SDL_ReadLE32(src);
   1.172 -
   1.173 -            /* ImageMagick seems to put out bogus masks here. Pick a default. */
   1.174 -            if ((Rmask == 0xFFFFFF) && (Gmask == 0xFFFFFF) &&
   1.175 -                (Bmask == 0xFFFFFF) && (Amask == 0xFFFFFF) ) {
   1.176 -                Amask = 0xFF000000;
   1.177 -                Rmask = 0x00FF0000;
   1.178 -                Gmask = 0x0000FF00;
   1.179 -                Bmask = 0x000000FF;
   1.180 -            } else if ((Rmask == 0xFFFFFF00) && (Gmask == 0xFFFFFF00) &&
   1.181 -                       (Bmask == 0xFFFFFF00) && (Amask == 0xFFFFFF00) ) {
   1.182 -                /* argh, The Gimp seems to put out different bogus masks! */
   1.183 -                Amask = 0x000000FF;
   1.184 -                Rmask = 0xFF000000;
   1.185 -                Gmask = 0x00FF0000;
   1.186 -                Bmask = 0x0000FF00;
   1.187 -            }
   1.188 -
   1.189 +            /* We don't know if this has alpha channel or not */
   1.190 +            correctAlpha = SDL_TRUE;
   1.191 +            Amask = 0xFF000000;
   1.192 +            Rmask = 0x00FF0000;
   1.193 +            Gmask = 0x0000FF00;
   1.194 +            Bmask = 0x000000FF;
   1.195              break;
   1.196          default:
   1.197              break;
   1.198          }
   1.199          break;
   1.200 +
   1.201 +    case BI_BITFIELDS:
   1.202 +        break;  /* we handled this in the info header. */
   1.203 +
   1.204      default:
   1.205          SDL_SetError("Compressed BMP files not supported");
   1.206          was_error = SDL_TRUE;