Browse Source

Support various kinds of BMP headers (incl reading bmp with alpha)

rdb 10 years ago
parent
commit
623d81db6b
2 changed files with 75 additions and 43 deletions
  1. 17 12
      panda/src/pnmimagetypes/bmp.h
  2. 58 31
      panda/src/pnmimagetypes/pnmFileTypeBMPReader.cxx

+ 17 - 12
panda/src/pnmimagetypes/bmp.h

@@ -32,6 +32,10 @@ static unsigned long BMPoffbits(int classv, unsigned long bitcount);
 
 #define C_WIN   1
 #define C_OS2   2
+#define C_WINV2 3
+#define C_WINV3 4
+#define C_WINV4 5
+#define C_WINV5 6
 
 static char     er_internal[] = "%s: internal error!";
 
@@ -41,8 +45,12 @@ BMPlenfileheader(int classv)
         switch (classv)
         {
         case C_WIN:
-                return 14;
         case C_OS2:
+        case C_WINV2:
+        case C_WINV3:
+        case C_WINV4:
+        case C_WINV5:
+                return 14;
                 return 14;
         default:
                 pm_error(er_internal, "BMPlenfileheader");
@@ -59,6 +67,14 @@ BMPleninfoheader(int classv)
                 return 40;
         case C_OS2:
                 return 12;
+        case C_WINV2:
+                return 52;
+        case C_WINV3:
+                return 56;
+        case C_WINV4:
+                return 108;
+        case C_WINV5:
+                return 124;
         default:
                 pm_error(er_internal, "BMPleninfoheader");
                 return 0;
@@ -107,17 +123,6 @@ BMPlenline(int classv, unsigned long bitcount, unsigned long x)
 {
         unsigned long   bitsperline;
 
-        switch (classv)
-        {
-        case C_WIN:
-                break;
-        case C_OS2:
-                break;
-        default:
-                pm_error(er_internal, "BMPlenline");
-                return 0;
-        }
-
         bitsperline = x * bitcount;
 
         /*

+ 58 - 31
panda/src/pnmimagetypes/pnmFileTypeBMPReader.cxx

@@ -191,37 +191,45 @@ BMPreadinfoheader(
         {
         case 12:
                 classv = C_OS2;
-
-                cx = GetShort(fp);
-                cy = GetShort(fp);
-                cPlanes = GetShort(fp);
-                cBitCount = GetShort(fp);
-
                 break;
-        case 40:
+        case 40:  // BITMAPINFOHEADER
                 classv = C_WIN;
+                break;
+        case 52:  // BITMAPV2INFOHEADER
+                classv = C_WINV2;
+                break;
+        case 56:  // BITMAPV3INFOHEADER
+                classv = C_WINV3;
+                break;
+        case 108:  // BITMAPV4HEADER
+                classv = C_WINV4;
+                break;
+        case 124:  // BITMAPV5HEADER
+                classv = C_WINV5;
+                break;
+        default:
+                pm_error("%s: unknown cbFix: %d", ifname, cbFix);
+                break;
+        }
 
+        if (classv == C_OS2) {
+                cx = GetShort(fp);
+                cy = GetShort(fp);
+        } else {
                 cx = GetLong(fp);
                 cy = GetLong(fp);
-                cPlanes = GetShort(fp);
-                cBitCount = GetShort(fp);
-
-                /*
-                 * We've read 16 bytes so far, need to read 24 more
-                 * for the required total of 40.
-                 */
+        }
+        cPlanes = GetShort(fp);
+        cBitCount = GetShort(fp);
 
+        /*
+         * We've read 16 bytes so far, need to read more
+         * for the required total.
+         */
+        if (classv != C_OS2) {
+            for (int i = 0; i < cbFix - 16; i += 4) {
                 GetLong(fp);
-                GetLong(fp);
-                GetLong(fp);
-                GetLong(fp);
-                GetLong(fp);
-                GetLong(fp);
-
-                break;
-        default:
-                pm_error("%s: unknown cbFix: %d", ifname, cbFix);
-                break;
+            }
         }
 
         if (cPlanes != 1)
@@ -239,6 +247,16 @@ BMPreadinfoheader(
                            ,cy
                            ,cBitCount);
                 break;
+        case C_WINV2:
+        case C_WINV3:
+        case C_WINV4:
+        case C_WINV5:
+                pm_message("Windows BMP V%d, %dx%dx%d"
+                           ,(classv - C_WINV2 + 2)
+                           ,cx
+                           ,cy
+                           ,cBitCount);
+                break;
         case C_OS2:
                 pm_message("OS/2 BMP, %dx%dx%d"
                            ,cx
@@ -288,7 +306,7 @@ BMPreadrgbtable(
                 R[i] = (pixval) GetByte(fp);
                 nbyte += 3;
 
-                if (classv == C_WIN)
+                if (classv != C_OS2)
                 {
                         (void) GetByte(fp);
                         nbyte++;
@@ -307,6 +325,7 @@ BMPreadrow(
         istream           *fp,
         unsigned long  *ppos,   /* number of bytes read from fp */
         pixel          *row,
+        xelval         *alpha_row,
         unsigned long   cx,
         unsigned short  cBitCount,
         int             indexed,
@@ -335,6 +354,10 @@ BMPreadrow(
                   b = GetByte(fp);
                   g = GetByte(fp);
                   r = GetByte(fp);
+                  if (cBitCount > 24) {
+                    *(alpha_row++) = GetByte(fp);
+                    ++nbyte;
+                  }
                   nbyte += 3;
                   PPM_ASSIGN(*row, r, g, b);
                 } else {
@@ -369,7 +392,7 @@ BMPreadrow(
 }
 
 static void
-BMPreadbits(xel *array,
+BMPreadbits(xel *array, xelval *alpha_array,
         istream           *fp,
         unsigned long  *ppos,   /* number of bytes read from fp */
         unsigned long   offBits,
@@ -386,7 +409,7 @@ BMPreadbits(xel *array,
 
         readto(fp, ppos, offBits);
 
-        if(cBitCount > 24)
+        if(cBitCount > 24 && cBitCount != 32)
         {
                 pm_error("%s: cannot handle cBitCount: %d"
                          ,ifname
@@ -400,7 +423,7 @@ BMPreadbits(xel *array,
         for (y = (long)cy - 1; y >= 0; y--)
         {
                 int rc;
-                rc = BMPreadrow(fp, ppos, array + y*cx, cx, cBitCount, indexed, R, G, B);
+                rc = BMPreadrow(fp, ppos, array + y*cx, alpha_array + y*cx, cx, cBitCount, indexed, R, G, B);
                 if(rc == -1)
                 {
                         pm_error("%s: couldn't read row %d"
@@ -472,7 +495,11 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
     }
   }
 
-  _num_channels = 3;
+  if (cBitCount > 24) {
+    _num_channels = 4;
+  } else {
+    _num_channels = 3;
+  }
   _x_size = (int)cx;
   _y_size = (int)cy;
   _maxval = 255;
@@ -498,8 +525,8 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
 //               below.
 ////////////////////////////////////////////////////////////////////
 int PNMFileTypeBMP::Reader::
-read_data(xel *array, xelval *) {
-  BMPreadbits(array, _file, &pos, offBits, _x_size, _y_size,
+read_data(xel *array, xelval *alpha_array) {
+  BMPreadbits(array, alpha_array, _file, &pos, offBits, _x_size, _y_size,
               cBitCount, classv, indexed, R, G, B);
 
   if (pos != BMPlenfile(classv, cBitCount, _x_size, _y_size)) {