|
- //
- // "$Id: Fl_BMP_Image.cxx 7903 2010-11-28 21:06:39Z matt $"
- //
- // Fl_BMP_Image routines.
- //
- // Copyright 1997-2010 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 <FL/Fl_BMP_Image.H>
- #include <FL/fl_utf8.h>
- #include <config.h>
- #include <stdio.h>
- #include <stdlib.h>
-
-
- //
- // 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.
- <P>The inherited destructor free all memory and server resources that are used by
- the image.
- <P>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 = fl_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...
- if (fread(colormap[repcount], 1, 3, fp)==0) { /* ignore */ }
-
- // 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: Fl_BMP_Image.cxx 7903 2010-11-28 21:06:39Z matt $".
- //
|