fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

Fl_BMP_Image.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_BMP_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
00003 //
00004 // Fl_BMP_Image routines.
00005 //
00006 // Copyright 1997-2010 by Easy Software Products.
00007 // Image support by Matthias Melcher, Copyright 2000-2009.
00008 //
00009 // This library is free software; you can redistribute it and/or
00010 // modify it under the terms of the GNU Library General Public
00011 // License as published by the Free Software Foundation; either
00012 // version 2 of the License, or (at your option) any later version.
00013 //
00014 // This library is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017 // Library General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Library General Public
00020 // License along with this library; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00022 // USA.
00023 //
00024 // Please report all bugs and problems on the following page:
00025 //
00026 //     http://www.fltk.org/str.php
00027 //
00028 // Contents:
00029 //
00030 //   Fl_BMP_Image::Fl_BMP_Image() - Load a BMP image file.
00031 //
00032 
00033 //
00034 // Include necessary header files...
00035 //
00036 
00037 #include <FL/Fl_BMP_Image.H>
00038 #include <FL/fl_utf8.h>
00039 #include <config.h>
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 
00043 
00044 //
00045 // BMP definitions...
00046 //
00047 
00048 #ifndef BI_RGB
00049 #  define BI_RGB       0             // No compression - straight BGR data
00050 #  define BI_RLE8      1             // 8-bit run-length compression
00051 #  define BI_RLE4      2             // 4-bit run-length compression
00052 #  define BI_BITFIELDS 3             // RGB bitmap with RGB masks
00053 #endif // !BI_RGB
00054 
00055 
00056 //
00057 // Local functions...
00058 //
00059 
00060 static int              read_long(FILE *fp);
00061 static unsigned short   read_word(FILE *fp);
00062 static unsigned int     read_dword(FILE *fp);
00070 Fl_BMP_Image::Fl_BMP_Image(const char *bmp) // I - File to read
00071   : Fl_RGB_Image(0,0,0) {
00072   FILE          *fp;            // File pointer
00073   int           info_size,      // Size of info header
00074                 depth,          // Depth of image (bits)
00075                 bDepth = 3,     // Depth of image (bytes)
00076                 compression,    // Type of compression
00077                 colors_used,    // Number of colors used
00078                 x, y,           // Looping vars
00079                 color,          // Color of RLE pixel
00080                 repcount,       // Number of times to repeat
00081                 temp,           // Temporary color
00082                 align,          // Alignment bytes
00083                 dataSize,       // number of bytes in image data set
00084                 row_order,      // 1 = normal;  -1 = flipped row order
00085                 start_y,        // Beginning Y
00086                 end_y;          // Ending Y
00087   long          offbits;        // Offset to image data
00088   uchar         bit,            // Bit in image
00089                 byte;           // Byte in image
00090   uchar         *ptr;           // Pointer into pixels
00091   uchar         colormap[256][3];// Colormap
00092   uchar         havemask;       // Single bit mask follows image data
00093   int           use_5_6_5;      // Use 5:6:5 for R:G:B channels in 16 bit images
00094 
00095 
00096   // Open the file...
00097   if ((fp = fl_fopen(bmp, "rb")) == NULL) return;
00098 
00099   // Get the header...
00100   byte = (uchar)getc(fp);       // Check "BM" sync chars
00101   bit  = (uchar)getc(fp);
00102   if (byte != 'B' || bit != 'M') {
00103     fclose(fp);
00104     return;
00105   }
00106 
00107   read_dword(fp);               // Skip size
00108   read_word(fp);                // Skip reserved stuff
00109   read_word(fp);
00110   offbits = (long)read_dword(fp);// Read offset to image data
00111 
00112   // Then the bitmap information...
00113   info_size = read_dword(fp);
00114 
00115 //  printf("offbits = %ld, info_size = %d\n", offbits, info_size);
00116 
00117   havemask  = 0;
00118   row_order = -1;
00119   use_5_6_5 = 0;
00120 
00121   if (info_size < 40) {
00122     // Old Windows/OS2 BMP header...
00123     w(read_word(fp));
00124     h(read_word(fp));
00125     read_word(fp);
00126     depth = read_word(fp);
00127     compression = BI_RGB;
00128     colors_used = 0;
00129 
00130     repcount = info_size - 12;
00131   } else {
00132     // New BMP header...
00133     w(read_long(fp));
00134     // If the height is negative, the row order is flipped
00135     temp = read_long(fp);
00136     if (temp < 0) row_order = 1;
00137     h(abs(temp));
00138     read_word(fp);
00139     depth = read_word(fp);
00140     compression = read_dword(fp);
00141     dataSize = read_dword(fp);
00142     read_long(fp);
00143     read_long(fp);
00144     colors_used = read_dword(fp);
00145     read_dword(fp);
00146 
00147     repcount = info_size - 40;
00148 
00149     if (!compression && depth>=8 && w()>32/depth) {
00150       int Bpp = depth/8;
00151       int maskSize = (((w()*Bpp+3)&~3)*h()) + (((((w()+7)/8)+3)&~3)*h());
00152       if (maskSize==2*dataSize) {
00153         havemask = 1;
00154         h(h()/2);
00155         bDepth = 4;
00156       }
00157     }
00158   }
00159 
00160 //  printf("w() = %d, h() = %d, depth = %d, compression = %d, colors_used = %d, repcount = %d\n",
00161 //         w(), h(), depth, compression, colors_used, repcount);
00162 
00163   // Skip remaining header bytes...
00164   while (repcount > 0) {
00165     getc(fp);
00166     repcount --;
00167   }
00168 
00169   // Check header data...
00170   if (!w() || !h() || !depth) {
00171     fclose(fp);
00172     return;
00173   }
00174 
00175   // Get colormap...
00176   if (colors_used == 0 && depth <= 8)
00177     colors_used = 1 << depth;
00178 
00179   for (repcount = 0; repcount < colors_used; repcount ++) {
00180     // Read BGR color...
00181     if (fread(colormap[repcount], 1, 3, fp)==0) { /* ignore */ }
00182 
00183     // Skip pad byte for new BMP files...
00184     if (info_size > 12) getc(fp);
00185   }
00186 
00187   // Read first dword of colormap. It tells us if 5:5:5 or 5:6:5 for 16 bit
00188   if (depth == 16)
00189     use_5_6_5 = (read_dword(fp) == 0xf800);
00190 
00191   // Set byte depth for RGBA images
00192   if (depth == 32)
00193     bDepth=4;
00194 
00195   // Setup image and buffers...
00196   d(bDepth);
00197   if (offbits) fseek(fp, offbits, SEEK_SET);
00198 
00199   array = new uchar[w() * h() * d()];
00200   alloc_array = 1;
00201 
00202   // Read the image data...
00203   color = 0;
00204   repcount = 0;
00205   align = 0;
00206   byte  = 0;
00207   temp  = 0;
00208 
00209   if (row_order < 0) {
00210     start_y = h() - 1;
00211     end_y   = -1;
00212   } else {
00213     start_y = 0;
00214     end_y   = h();
00215   }
00216 
00217   for (y = start_y; y != end_y; y += row_order) {
00218     ptr = (uchar *)array + y * w() * d();
00219 
00220     switch (depth)
00221     {
00222       case 1 : // Bitmap
00223           for (x = w(), bit = 128; x > 0; x --) {
00224             if (bit == 128) byte = (uchar)getc(fp);
00225 
00226             if (byte & bit) {
00227               *ptr++ = colormap[1][2];
00228               *ptr++ = colormap[1][1];
00229               *ptr++ = colormap[1][0];
00230             } else {
00231               *ptr++ = colormap[0][2];
00232               *ptr++ = colormap[0][1];
00233               *ptr++ = colormap[0][0];
00234             }
00235 
00236             if (bit > 1)
00237               bit >>= 1;
00238             else
00239               bit = 128;
00240           }
00241 
00242           // Read remaining bytes to align to 32 bits...
00243           for (temp = (w() + 7) / 8; temp & 3; temp ++) {
00244             getc(fp);
00245           }
00246           break;
00247 
00248       case 4 : // 16-color
00249           for (x = w(), bit = 0xf0; x > 0; x --) {
00250             // Get a new repcount as needed...
00251             if (repcount == 0) {
00252               if (compression != BI_RLE4) {
00253                 repcount = 2;
00254                 color = -1;
00255               } else {
00256                 while (align > 0) {
00257                   align --;
00258                   getc(fp);
00259                 }
00260 
00261                 if ((repcount = getc(fp)) == 0) {
00262                   if ((repcount = getc(fp)) == 0) {
00263                     // End of line...
00264                     x ++;
00265                     continue;
00266                   } else if (repcount == 1) {
00267                     // End of image...
00268                     break;
00269                   } else if (repcount == 2) {
00270                     // Delta...
00271                     repcount = getc(fp) * getc(fp) * w();
00272                     color = 0;
00273                   } else {
00274                     // Absolute...
00275                     color = -1;
00276                     align = ((4 - (repcount & 3)) / 2) & 1;
00277                   }
00278                 } else {
00279                   color = getc(fp);
00280                 }
00281               }
00282             }
00283 
00284             // Get a new color as needed...
00285             repcount --;
00286 
00287             // Extract the next pixel...
00288             if (bit == 0xf0) {
00289               // Get the next color byte as needed...
00290               if (color < 0) temp = getc(fp);
00291               else temp = color;
00292 
00293               // Copy the color value...
00294               *ptr++ = colormap[(temp >> 4) & 15][2];
00295               *ptr++ = colormap[(temp >> 4) & 15][1];
00296               *ptr++ = colormap[(temp >> 4) & 15][0];
00297 
00298               bit  = 0x0f;
00299             } else {
00300               bit  = 0xf0;
00301 
00302               // Copy the color value...
00303               *ptr++ = colormap[temp & 15][2];
00304               *ptr++ = colormap[temp & 15][1];
00305               *ptr++ = colormap[temp & 15][0];
00306             }
00307 
00308           }
00309 
00310           if (!compression) {
00311             // Read remaining bytes to align to 32 bits...
00312             for (temp = (w() + 1) / 2; temp & 3; temp ++) {
00313               getc(fp);
00314             }
00315           }
00316           break;
00317 
00318       case 8 : // 256-color
00319           for (x = w(); x > 0; x --) {
00320             // Get a new repcount as needed...
00321             if (compression != BI_RLE8) {
00322               repcount = 1;
00323               color = -1;
00324             }
00325 
00326             if (repcount == 0) {
00327               while (align > 0) {
00328                 align --;
00329                 getc(fp);
00330               }
00331 
00332               if ((repcount = getc(fp)) == 0) {
00333                 if ((repcount = getc(fp)) == 0) {
00334                   // End of line...
00335                   x ++;
00336                   continue;
00337                 } else if (repcount == 1) {
00338                   // End of image...
00339                   break;
00340                 } else if (repcount == 2) {
00341                   // Delta...
00342                   repcount = getc(fp) * getc(fp) * w();
00343                   color = 0;
00344                 } else {
00345                   // Absolute...
00346                   color = -1;
00347                   align = (2 - (repcount & 1)) & 1;
00348                 }
00349               } else {
00350                 color = getc(fp);
00351               }
00352             }
00353 
00354             // Get a new color as needed...
00355             if (color < 0) temp = getc(fp);
00356             else temp = color;
00357 
00358             repcount --;
00359 
00360             // Copy the color value...
00361             *ptr++ = colormap[temp][2];
00362             *ptr++ = colormap[temp][1];
00363             *ptr++ = colormap[temp][0];
00364             if (havemask) ptr++;
00365           }
00366 
00367           if (!compression) {
00368             // Read remaining bytes to align to 32 bits...
00369             for (temp = w(); temp & 3; temp ++) {
00370               getc(fp);
00371             }
00372           }
00373           break;
00374 
00375       case 16 : // 16-bit 5:5:5 or 5:6:5 RGB
00376           for (x = w(); x > 0; x --, ptr += bDepth) {
00377             uchar b = getc(fp), a = getc(fp) ;
00378             if (use_5_6_5) {
00379                 ptr[2] = (uchar)(( b << 3 ) & 0xf8);
00380                 ptr[1] = (uchar)(((a << 5) & 0xe0) | ((b >> 3) & 0x1c));
00381                 ptr[0] = (uchar)(a & 0xf8);
00382             } else {
00383                 ptr[2] = (uchar)((b << 3) & 0xf8);
00384                 ptr[1] = (uchar)(((a << 6) & 0xc0) | ((b >> 2) & 0x38));
00385                 ptr[0] = (uchar)((a<<1) & 0xf8);
00386             }
00387           }
00388 
00389           // Read remaining bytes to align to 32 bits...
00390           for (temp = w() * 2; temp & 3; temp ++) {
00391             getc(fp);
00392           }
00393           break;
00394 
00395       case 24 : // 24-bit RGB
00396           for (x = w(); x > 0; x --, ptr += bDepth) {
00397             ptr[2] = (uchar)getc(fp);
00398             ptr[1] = (uchar)getc(fp);
00399             ptr[0] = (uchar)getc(fp);
00400           }
00401 
00402           // Read remaining bytes to align to 32 bits...
00403           for (temp = w() * 3; temp & 3; temp ++) {
00404             getc(fp);
00405           }
00406           break;
00407                   
00408       case 32 : // 32-bit RGBA
00409          for (x = w(); x > 0; x --, ptr += bDepth) {
00410             ptr[2] = (uchar)getc(fp);
00411             ptr[1] = (uchar)getc(fp);
00412             ptr[0] = (uchar)getc(fp);
00413             ptr[3] = (uchar)getc(fp);
00414           }
00415           break;
00416     }
00417   }
00418   
00419   if (havemask) {
00420     for (y = h() - 1; y >= 0; y --) {
00421       ptr = (uchar *)array + y * w() * d() + 3;
00422       for (x = w(), bit = 128; x > 0; x --, ptr+=bDepth) {
00423         if (bit == 128) byte = (uchar)getc(fp);
00424         if (byte & bit)
00425           *ptr = 0;
00426         else
00427           *ptr = 255;
00428         if (bit > 1)
00429           bit >>= 1;
00430         else
00431           bit = 128;
00432       }
00433       // Read remaining bytes to align to 32 bits...
00434       for (temp = (w() + 7) / 8; temp & 3; temp ++)
00435         getc(fp);
00436     }
00437   }
00438 
00439   // Close the file and return...
00440   fclose(fp);
00441 }
00442 
00443 
00444 //
00445 // 'read_word()' - Read a 16-bit unsigned integer.
00446 //
00447 
00448 static unsigned short   // O - 16-bit unsigned integer
00449 read_word(FILE *fp) {   // I - File to read from
00450   unsigned char b0, b1; // Bytes from file
00451 
00452   b0 = (uchar)getc(fp);
00453   b1 = (uchar)getc(fp);
00454 
00455   return ((b1 << 8) | b0);
00456 }
00457 
00458 
00459 //
00460 // 'read_dword()' - Read a 32-bit unsigned integer.
00461 //
00462 
00463 static unsigned int             // O - 32-bit unsigned integer
00464 read_dword(FILE *fp) {          // I - File to read from
00465   unsigned char b0, b1, b2, b3; // Bytes from file
00466 
00467   b0 = (uchar)getc(fp);
00468   b1 = (uchar)getc(fp);
00469   b2 = (uchar)getc(fp);
00470   b3 = (uchar)getc(fp);
00471 
00472   return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
00473 }
00474 
00475 
00476 //
00477 // 'read_long()' - Read a 32-bit signed integer.
00478 //
00479 
00480 static int                      // O - 32-bit signed integer
00481 read_long(FILE *fp) {           // I - File to read from
00482   unsigned char b0, b1, b2, b3; // Bytes from file
00483 
00484   b0 = (uchar)getc(fp);
00485   b1 = (uchar)getc(fp);
00486   b2 = (uchar)getc(fp);
00487   b3 = (uchar)getc(fp);
00488 
00489   return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0);
00490 }
00491 
00492 
00493 //
00494 // End of "$Id: Fl_BMP_Image.cxx 7903 2010-11-28 21:06:39Z matt $".
00495 //