// // bmp.cpp - source file / freeware // // David Henry - tfc_duke@hotmail.com // #include "bmp.h" #include #include extern "C"{ long filelength(int fhandle); } // -------------------------------------------------- // LoadFileBMP() - load a Windows/OS2 BITMAP image // [.bmp]. // // parameters : // - filename [in] : image source file // - pixels [out] : 32 bits rgb image data // - width [out] : image width in pixels // - height [out] : image height in pixels // - flipvert [in] : flip vertically // // return value : // - -1 : no image data // - 0 : failure // - 1 : success // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // accepted image formats : // # RGB 1-4-8-24-32 bits WINDOWS - OS/2 // # RLE 4-8 bits WINDOWS // -------------------------------------------------- int LoadFileBMP( const char *filename, unsigned char **pixels, int *width, int *height, bool flipvert ) { FILE *file; // file stream BITMAPFILEHEADER *bmfh; // bitmap file header BITMAPINFOHEADER *bmih; // bitmap info header (windows) BITMAPCOREHEADER *bmch; // bitmap core header (os/2) RGBTRIPLE *os2_palette; // pointer to the color palette os/2 RGBQUAD *win_palette; // pointer to the color palette windows char *buffer; // buffer storing the entire file unsigned char *ptr; // pointer to pixels data int bitCount; // number of bits per pixel int compression; // compression type (rgb/rle) int row, col, i; // temporary variables int w, h; // width, height ///////////////////////////////////////////////////// // read the entire file in the buffer file = fopen(filename,"rb"); if( !file) return 0; long flen = filelength(fileno(file)); buffer = new char[ flen + 1 ]; int rd = fread(buffer, flen, 1, file); char *pBuff = buffer; fclose(file); ///////////////////////////////////////////////////// // read the header bmfh = (BITMAPFILEHEADER *)pBuff; pBuff += sizeof( BITMAPFILEHEADER ); // verify that it's a BITMAP file if( bmfh->bfType != BITMAP_ID ) { delete [] buffer; return 0; } bmch = (BITMAPCOREHEADER *)pBuff; bmih = (BITMAPINFOHEADER *)pBuff; if( (bmih->biCompression < 0) || (bmih->biCompression > 3) ) { // OS/2 style pBuff += sizeof( BITMAPCOREHEADER ); bitCount = bmch->bcBitCount; compression = BI_OS2; w = bmch->bcWidth; h = bmch->bcHeight; } else { // WINDOWS style pBuff += sizeof( BITMAPINFOHEADER ); bitCount = bmih->biBitCount; compression = bmih->biCompression; w = bmih->biWidth; h = bmih->biHeight; } if( width ) *width = w; if( height ) *height = h; if( !pixels ) { delete [] buffer; return (-1); } ///////////////////////////////////////////////////// // read the palette if( bitCount <= 8 ) { // 24 and 32 bits images are not paletted // ajust the palette pointer to the memory in the buffer os2_palette = (RGBTRIPLE *)pBuff; win_palette = (RGBQUAD *)pBuff; // [number of colors in the palette] * [size of one pixel] pBuff += (1 << bitCount) * (bitCount >> 3) * sizeof( unsigned char ); } ///////////////////////////////////////////////////// // allocate memory to store pixel data *pixels = new unsigned char[ w * h * 3 ]; ptr = &(*pixels)[0]; // move the pixel data pointer to the begening of bitmap data pBuff = buffer + (bmfh->bfOffBits * sizeof( char )); ///////////////////////////////////////////////////// // read pixel data following the image compression // type and the number of bits per pixels ///////////////////////////////////////////////////// switch( compression ) { case BI_OS2: case BI_RGB: { for( row = h - 1; row >= 0; row-- ) { if( flipvert ) ptr = &(*pixels)[ row * w * 3 ]; switch( bitCount ) { case 1: { // RGB 1 BITS for( col = 0; col < (int)(w / 8); col++ ) { // read the current pixel unsigned char color = *((unsigned char *)(pBuff++)); for( i = 7; i >= 0; i--, ptr += 3 ) { // convert indexed pixel (1 bit) into rgb (32 bits) pixel int clrIdx = ((color & (1< 0); if( compression == BI_OS2 ) { ptr[2] = os2_palette[ clrIdx ].rgbtRed; ptr[1] = os2_palette[ clrIdx ].rgbtGreen; ptr[0] = os2_palette[ clrIdx ].rgbtBlue; } else { ptr[2] = win_palette[ clrIdx ].rgbRed; ptr[1] = win_palette[ clrIdx ].rgbGreen; ptr[0] = win_palette[ clrIdx ].rgbBlue; } } } break; } case 4: { // RGB 4 BITS for( col = 0; col < (int)(w / 2); col++, ptr += 6 ) { // read the current pixel unsigned char color = *((unsigned char *)(pBuff++)); // convert indexed pixel (4 bits) into rgb (32 bits) pixel int clrIdx; if( compression == BI_OS2 ) { clrIdx = (color >> 4); ptr[2] = os2_palette[ clrIdx ].rgbtRed; ptr[1] = os2_palette[ clrIdx ].rgbtGreen; ptr[0] = os2_palette[ clrIdx ].rgbtBlue; clrIdx = (color & 0x0F); ptr[6] = os2_palette[ clrIdx ].rgbtRed; ptr[5] = os2_palette[ clrIdx ].rgbtGreen; ptr[4] = os2_palette[ clrIdx ].rgbtBlue; } else { clrIdx = (color >> 4); ptr[2] = win_palette[ clrIdx ].rgbRed; ptr[1] = win_palette[ clrIdx ].rgbGreen; ptr[0] = win_palette[ clrIdx ].rgbBlue; clrIdx = (color & 0x0F); ptr[6] = win_palette[ clrIdx ].rgbRed; ptr[5] = win_palette[ clrIdx ].rgbGreen; ptr[4] = win_palette[ clrIdx ].rgbBlue; } } break; } case 8: { // RGB 8 BITS for( col = 0; col < w; col++, ptr += 3 ) { // read the current pixel unsigned char color = *((unsigned char *)(pBuff++)); // convert indexed pixel (8 bits) into rgb (32 bits) pixel if( compression == BI_OS2 ) { ptr[2] = os2_palette[ color ].rgbtRed; ptr[1] = os2_palette[ color ].rgbtGreen; ptr[0] = os2_palette[ color ].rgbtBlue; } else { ptr[2] = win_palette[ color ].rgbRed; ptr[1] = win_palette[ color ].rgbGreen; ptr[0] = win_palette[ color ].rgbBlue; } } break; } case 24: { // RGB 24 BITS for( col = 0; col < w; col++, ptr += 3 ) { // convert bgr pixel (24 bits) into rgb (32 bits) pixel RGBTRIPLE *pix = (RGBTRIPLE *)pBuff; pBuff += sizeof( RGBTRIPLE ); ptr[2] = pix->rgbtRed; ptr[1] = pix->rgbtGreen; ptr[0] = pix->rgbtBlue; } break; } case 32: { // RGB 32 BITS for( col = 0; col < w; col++, ptr += 3 ) { // // convert bgr pixel (32 bits) into rgb (32 bits) pixel RGBQUAD *pix = (RGBQUAD *)pBuff; pBuff += sizeof( RGBQUAD ); ptr[2] = pix->rgbRed; ptr[1] = pix->rgbGreen; ptr[0] = pix->rgbBlue; } break; } } } break; } case BI_RLE8: { // RLE 8 BITS for( row = h - 1; row >= 0; row-- ) { if( flipvert ) ptr = &(*pixels)[ row * w * 3 ]; for( col = 0; col < w; /* nothing */ ) { // get one packet (2 bytes) unsigned char byte1 = *((unsigned char *)(pBuff++)); unsigned char byte2 = *((unsigned char *)(pBuff++)); if( byte1 == RLE_COMMAND ) { // absolute encoding for( i = 0; i < byte2; i++, ptr += 3, col++ ) { // read the current pixel unsigned char color = *((unsigned char *)(pBuff++)); // convert indexed pixel (8 bits) into rgb (32 bits) pixel ptr[2] = win_palette[ color ].rgbRed; ptr[1] = win_palette[ color ].rgbGreen; ptr[0] = win_palette[ color ].rgbBlue; } if( (byte2 % 2) == 1 ) pBuff++; } else { // read next pixels for( i = 0; i < byte1; i++, ptr += 3, col++ ) { // convert indexed pixel (8 bits) into rgb (32 bits) pixel ptr[2] = win_palette[ byte2 ].rgbRed; ptr[1] = win_palette[ byte2 ].rgbGreen; ptr[0] = win_palette[ byte2 ].rgbBlue; } } } } break; } case BI_RLE4: { // RLE 4 BITS unsigned char color; int bytesRead = 0; // number of bytes read for( row = h - 1; row >= 0; row-- ) { if( flipvert ) ptr = &(*pixels)[ row * w * 3 ]; for( col = 0; col < w; /* nothing */ ) { // get one packet (2 bytes) unsigned char byte1 = *((unsigned char *)(pBuff++)); unsigned char byte2 = *((unsigned char *)(pBuff++)); bytesRead += 2; if( byte1 == RLE_COMMAND ) { // absolute encoding unsigned char databyte; for( i = 0; i < byte2; i++, ptr += 3, col++ ) { if( (i % 2) == 0 ) { // read the current pixel databyte = *((unsigned char *)(pBuff++)); bytesRead++; color = (databyte >> 4); // 4 first bits } else { color = (databyte & 0x0F); // 4 last bits } // convert indexed pixel (4 bits) into rgb (32 bits) pixel ptr[2] = win_palette[ color ].rgbRed; ptr[1] = win_palette[ color ].rgbGreen; ptr[0] = win_palette[ color ].rgbBlue; } while( (bytesRead % 2) != 0 ) { pBuff++; bytesRead++; } } else { // read next pixels for( i = 0; i < byte1; i++, ptr += 3, col++ ) { if( (i % 2) == 0 ) color = (byte2 >> 4); // 4 first bits else color = (byte2 & 0x0F); // 4 last bits // convert indexed pixel (4 bits) into rgb (32 bits) pixel ptr[2] = win_palette[ color ].rgbRed; ptr[1] = win_palette[ color ].rgbGreen; ptr[0] = win_palette[ color ].rgbBlue; } } } } break; } } // free buffer memory delete [] buffer; // return success return 1; }