kolibrios/programs/demos/cubetext/trunk/bmp.cpp

443 lines
10 KiB
C++

//
// bmp.cpp - source file / freeware
//
// David Henry - tfc_duke@hotmail.com
//
#include "bmp.h"
#include <stdio.h>
#include <libc/stubs.h>
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<<i)) > 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;
}