// // "$Id$" // // Fl_BMP_Image routines. // // Copyright 1997-2009 by Easy Software Products. // Image support by Matthias Melcher, Copyright 2000-2009. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Library General Public License for more details. // // You should have received a copy of the GNU Library General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // // Please report all bugs and problems on the following page: // // http://www.fltk.org/str.php // // Contents: // // Fl_BMP_Image::Fl_BMP_Image() - Load a BMP image file. // // // Include necessary header files... // #include #include #include #include // // BMP definitions... // #ifndef BI_RGB # define BI_RGB 0 // No compression - straight BGR data # define BI_RLE8 1 // 8-bit run-length compression # define BI_RLE4 2 // 4-bit run-length compression # define BI_BITFIELDS 3 // RGB bitmap with RGB masks #endif // !BI_RGB // // Local functions... // static int read_long(FILE *fp); static unsigned short read_word(FILE *fp); static unsigned int read_dword(FILE *fp); /** The constructor loads the named BMP image from the given bmp filename.

The inherited destructor free all memory and server resources that are used by the image.

The destructor free all memory and server resources that are used by the image */ Fl_BMP_Image::Fl_BMP_Image(const char *bmp) // I - File to read : Fl_RGB_Image(0,0,0) { FILE *fp; // File pointer int info_size, // Size of info header depth, // Depth of image (bits) bDepth = 3, // Depth of image (bytes) compression, // Type of compression colors_used, // Number of colors used x, y, // Looping vars color, // Color of RLE pixel repcount, // Number of times to repeat temp, // Temporary color align, // Alignment bytes dataSize, // number of bytes in image data set row_order, // 1 = normal; -1 = flipped row order start_y, // Beginning Y end_y; // Ending Y long offbits; // Offset to image data uchar bit, // Bit in image byte; // Byte in image uchar *ptr; // Pointer into pixels uchar colormap[256][3];// Colormap uchar havemask; // Single bit mask follows image data int use_5_6_5; // Use 5:6:5 for R:G:B channels in 16 bit images // Open the file... if ((fp = fopen(bmp, "rb")) == NULL) return; // Get the header... byte = (uchar)getc(fp); // Check "BM" sync chars bit = (uchar)getc(fp); if (byte != 'B' || bit != 'M') { fclose(fp); return; } read_dword(fp); // Skip size read_word(fp); // Skip reserved stuff read_word(fp); offbits = (long)read_dword(fp);// Read offset to image data // Then the bitmap information... info_size = read_dword(fp); // printf("offbits = %ld, info_size = %d\n", offbits, info_size); havemask = 0; row_order = -1; use_5_6_5 = 0; if (info_size < 40) { // Old Windows/OS2 BMP header... w(read_word(fp)); h(read_word(fp)); read_word(fp); depth = read_word(fp); compression = BI_RGB; colors_used = 0; repcount = info_size - 12; } else { // New BMP header... w(read_long(fp)); // If the height is negative, the row order is flipped temp = read_long(fp); if (temp < 0) row_order = 1; h(abs(temp)); read_word(fp); depth = read_word(fp); compression = read_dword(fp); dataSize = read_dword(fp); read_long(fp); read_long(fp); colors_used = read_dword(fp); read_dword(fp); repcount = info_size - 40; if (!compression && depth>=8 && w()>32/depth) { int Bpp = depth/8; int maskSize = (((w()*Bpp+3)&~3)*h()) + (((((w()+7)/8)+3)&~3)*h()); if (maskSize==2*dataSize) { havemask = 1; h(h()/2); bDepth = 4; } } } // printf("w() = %d, h() = %d, depth = %d, compression = %d, colors_used = %d, repcount = %d\n", // w(), h(), depth, compression, colors_used, repcount); // Skip remaining header bytes... while (repcount > 0) { getc(fp); repcount --; } // Check header data... if (!w() || !h() || !depth) { fclose(fp); return; } // Get colormap... if (colors_used == 0 && depth <= 8) colors_used = 1 << depth; for (repcount = 0; repcount < colors_used; repcount ++) { // Read BGR color... fread(colormap[repcount], 1, 3, fp); // Skip pad byte for new BMP files... if (info_size > 12) getc(fp); } // Read first dword of colormap. It tells us if 5:5:5 or 5:6:5 for 16 bit if (depth == 16) use_5_6_5 = (read_dword(fp) == 0xf800); // Set byte depth for RGBA images if (depth == 32) bDepth=4; // Setup image and buffers... d(bDepth); if (offbits) fseek(fp, offbits, SEEK_SET); array = new uchar[w() * h() * d()]; alloc_array = 1; // Read the image data... color = 0; repcount = 0; align = 0; byte = 0; temp = 0; if (row_order < 0) { start_y = h() - 1; end_y = -1; } else { start_y = 0; end_y = h(); } for (y = start_y; y != end_y; y += row_order) { ptr = (uchar *)array + y * w() * d(); switch (depth) { case 1 : // Bitmap for (x = w(), bit = 128; x > 0; x --) { if (bit == 128) byte = (uchar)getc(fp); if (byte & bit) { *ptr++ = colormap[1][2]; *ptr++ = colormap[1][1]; *ptr++ = colormap[1][0]; } else { *ptr++ = colormap[0][2]; *ptr++ = colormap[0][1]; *ptr++ = colormap[0][0]; } if (bit > 1) bit >>= 1; else bit = 128; } // Read remaining bytes to align to 32 bits... for (temp = (w() + 7) / 8; temp & 3; temp ++) { getc(fp); } break; case 4 : // 16-color for (x = w(), bit = 0xf0; x > 0; x --) { // Get a new repcount as needed... if (repcount == 0) { if (compression != BI_RLE4) { repcount = 2; color = -1; } else { while (align > 0) { align --; getc(fp); } if ((repcount = getc(fp)) == 0) { if ((repcount = getc(fp)) == 0) { // End of line... x ++; continue; } else if (repcount == 1) { // End of image... break; } else if (repcount == 2) { // Delta... repcount = getc(fp) * getc(fp) * w(); color = 0; } else { // Absolute... color = -1; align = ((4 - (repcount & 3)) / 2) & 1; } } else { color = getc(fp); } } } // Get a new color as needed... repcount --; // Extract the next pixel... if (bit == 0xf0) { // Get the next color byte as needed... if (color < 0) temp = getc(fp); else temp = color; // Copy the color value... *ptr++ = colormap[(temp >> 4) & 15][2]; *ptr++ = colormap[(temp >> 4) & 15][1]; *ptr++ = colormap[(temp >> 4) & 15][0]; bit = 0x0f; } else { bit = 0xf0; // Copy the color value... *ptr++ = colormap[temp & 15][2]; *ptr++ = colormap[temp & 15][1]; *ptr++ = colormap[temp & 15][0]; } } if (!compression) { // Read remaining bytes to align to 32 bits... for (temp = (w() + 1) / 2; temp & 3; temp ++) { getc(fp); } } break; case 8 : // 256-color for (x = w(); x > 0; x --) { // Get a new repcount as needed... if (compression != BI_RLE8) { repcount = 1; color = -1; } if (repcount == 0) { while (align > 0) { align --; getc(fp); } if ((repcount = getc(fp)) == 0) { if ((repcount = getc(fp)) == 0) { // End of line... x ++; continue; } else if (repcount == 1) { // End of image... break; } else if (repcount == 2) { // Delta... repcount = getc(fp) * getc(fp) * w(); color = 0; } else { // Absolute... color = -1; align = (2 - (repcount & 1)) & 1; } } else { color = getc(fp); } } // Get a new color as needed... if (color < 0) temp = getc(fp); else temp = color; repcount --; // Copy the color value... *ptr++ = colormap[temp][2]; *ptr++ = colormap[temp][1]; *ptr++ = colormap[temp][0]; if (havemask) ptr++; } if (!compression) { // Read remaining bytes to align to 32 bits... for (temp = w(); temp & 3; temp ++) { getc(fp); } } break; case 16 : // 16-bit 5:5:5 or 5:6:5 RGB for (x = w(); x > 0; x --, ptr += bDepth) { uchar b = getc(fp), a = getc(fp) ; if (use_5_6_5) { ptr[2] = (uchar)(( b << 3 ) & 0xf8); ptr[1] = (uchar)(((a << 5) & 0xe0) | ((b >> 3) & 0x1c)); ptr[0] = (uchar)(a & 0xf8); } else { ptr[2] = (uchar)((b << 3) & 0xf8); ptr[1] = (uchar)(((a << 6) & 0xc0) | ((b >> 2) & 0x38)); ptr[0] = (uchar)((a<<1) & 0xf8); } } // Read remaining bytes to align to 32 bits... for (temp = w() * 2; temp & 3; temp ++) { getc(fp); } break; case 24 : // 24-bit RGB for (x = w(); x > 0; x --, ptr += bDepth) { ptr[2] = (uchar)getc(fp); ptr[1] = (uchar)getc(fp); ptr[0] = (uchar)getc(fp); } // Read remaining bytes to align to 32 bits... for (temp = w() * 3; temp & 3; temp ++) { getc(fp); } break; case 32 : // 32-bit RGBA for (x = w(); x > 0; x --, ptr += bDepth) { ptr[2] = (uchar)getc(fp); ptr[1] = (uchar)getc(fp); ptr[0] = (uchar)getc(fp); ptr[3] = (uchar)getc(fp); } break; } } if (havemask) { for (y = h() - 1; y >= 0; y --) { ptr = (uchar *)array + y * w() * d() + 3; for (x = w(), bit = 128; x > 0; x --, ptr+=bDepth) { if (bit == 128) byte = (uchar)getc(fp); if (byte & bit) *ptr = 0; else *ptr = 255; if (bit > 1) bit >>= 1; else bit = 128; } // Read remaining bytes to align to 32 bits... for (temp = (w() + 7) / 8; temp & 3; temp ++) getc(fp); } } // Close the file and return... fclose(fp); } // // 'read_word()' - Read a 16-bit unsigned integer. // static unsigned short // O - 16-bit unsigned integer read_word(FILE *fp) { // I - File to read from unsigned char b0, b1; // Bytes from file b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); return ((b1 << 8) | b0); } // // 'read_dword()' - Read a 32-bit unsigned integer. // static unsigned int // O - 32-bit unsigned integer read_dword(FILE *fp) { // I - File to read from unsigned char b0, b1, b2, b3; // Bytes from file b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); b2 = (uchar)getc(fp); b3 = (uchar)getc(fp); return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } // // 'read_long()' - Read a 32-bit signed integer. // static int // O - 32-bit signed integer read_long(FILE *fp) { // I - File to read from unsigned char b0, b1, b2, b3; // Bytes from file b0 = (uchar)getc(fp); b1 = (uchar)getc(fp); b2 = (uchar)getc(fp); b3 = (uchar)getc(fp); return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); } // // End of "$Id$". //