File: cpw_bitmaps.c/***************************************************************************/
/* */
/* cpw_bitmaps.c */
/* */
/* Cpw interface to BMP file loading and saving. */
/* */
/* Copyright 2001-2002 by */
/* Jim Mathies, */
/* */
/* This file is part of the Cpw project, and may only be used, */
/* modified, and distributed under the terms of the Cpw project */
/* license. By continuing to use, modify, or distribute this file */
/* you indicate that you have read the license and understand and */
/* accept it fully. */
/* */
/* File Platform: cross */
/* */
/***************************************************************************/
#include "cpw_bitmaps.h"
#include "cpw_error.h"
#define BITMAP_ID 0x4D42
/* reads an rgb bitmap image */
bool cpw_bitmap_load( pCpw cpw, char * filename, CpwImage * image )
{
FILE * fp;
BITMAPINFOHEADER bitmapInfoHeader;
BITMAPFILEHEADER bitmapFileHeader;
uint_32 index;
uint_32 len;
uint_32 datasize;
unsigned char byte;
unsigned char red;
unsigned char grn;
unsigned char blu;
uint_16 word;
pChar tempBuf;
if ( image == 0 ) {
cpw_error_set( cpw, cpw_error_invalidparameter );
return false;
}
fp = fopen( filename, "rb" );
if ( fp == 0 ) {
cpw_error_set( cpw, cpw_error_failedtoload );
return false;
}
len = fread( &bitmapFileHeader, sizeof( BITMAPFILEHEADER ), 1, fp );
if ( len != 1 ) {
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
}
if ( bitmapFileHeader.bfType != BITMAP_ID ) {
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
}
len = fread( &bitmapInfoHeader, sizeof( BITMAPINFOHEADER ), 1, fp );
if ( len != 1 ) {
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
}
switch ( bitmapInfoHeader.biBitCount ) {
/* currently no support for 0 (jpeg), 1 (mono), 4 (indexed), or 8 (indexed) bits */
case 0:
case 1:
case 4:
case 8:
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
break;
case 16:
datasize = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 2;
image->depth = 3;
break;
case 24:
datasize = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3;
image->depth = 3;
break;
case 32:
datasize = bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 4;
image->depth = 3;
break;
break;
default:
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
break;
}
if ( bitmapInfoHeader.biCompression == BI_RGB ||
bitmapInfoHeader.biCompression == BI_BITFIELDS ) {
} else {
/* currently no support for compressed bitmaps */
cpw_error_set( cpw, cpw_error_invalidformat );
fclose( fp );
return false;
}
/* jump forward to the data */
fseek( fp, bitmapFileHeader.bfOffBits, SEEK_SET );
image->data = (pChar) cpwmalloc( datasize );
if ( !image->data ) {
cpw_error_set( cpw, cpw_error_outofmemory );
fclose( fp );
return false;
}
len = fread( image->data, 1, datasize, fp );
if ( len != datasize ) {
cpw_error_set( cpw, cpw_error_invalidformat );
cpwfree( image->data );
fclose( fp );
return false;
}
fclose( fp );
/* Convert data to RGB, 8 bits per color. (BMP's are BGR not RGB) */
switch( bitmapInfoHeader.biBitCount ) {
case 16:
/* red, green, and blue are represented with 5 bits for each color */
tempBuf = cpwmalloc( bitmapInfoHeader.biWidth * bitmapInfoHeader.biHeight * 3 );
if ( !tempBuf ) {
cpw_error_set( cpw, cpw_error_outofmemory );
cpwfree( image->data );
fclose( fp );
return false;
}
for ( index = 0; index < datasize; index += 3 ) {
word = (uint_16)*( image->data + index );
/* 0x7C00 red (0111 1100 0000 0000) */
red = (word | 0x7C00) >> 10;
/* 0x03E0 green (0000 0011 1110 0000) */
grn = (word | 0x03E0) >> 5;
/* 0x001F blue (0000 0000 0001 1111) */
blu = (word | 0x001F);
tempBuf[index+0] = red;
tempBuf[index+1] = grn;
tempBuf[index+2] = blu;
}
cpwfree( image->data );
image->data = tempBuf;
break;
case 24:
/* red, green, and blue are represented with 8 bits for each color */
/* bitmap data is BGR so we convert to RGB */
for ( index = 0; index < datasize; index += 3 ) {
byte = image->data[index]; /* byte = blue */
image->data[index] = image->data[index + 2]; /* swap red */
image->data[index + 2] = byte; /* blue over */
}
break;
case 32:
/* red, green, and blue are represented with 12 bits for each color */
break;
}
image->depth = 3;
image->width = bitmapInfoHeader.biWidth;
image->height = bitmapInfoHeader.biHeight;
return true;
}