Yesterday i wrote a Windows Bitmap loader and today i thought i would share it with "the community"...
images can be compressed with either RLE4, RLE8, or totally uncompressed.
it will load 4bit/8bit bitmaps in 8bit colour mode,
or 4bit/8bit/24bit bitmaps in 16bit colour mode!
e.g. usage:
flags:
GPIMG_8BIT - load the bitmap as 8bit*
GPIMG_16BIT - load the bitmap as 16bit
GPIMG_PAL - load the bitmap's palette*
*does not work for 24bit bitmaps with no palette information!
flag combinations:
GPIMG_PAL - only load the palette!
GPIMG_8BIT - only load the bitmap!
GPIMG_8BIT|GPIMG_PAL - load the bitmap and the palette!
ok, so the code is not 6 lines of optimized ARM!
if you find this code useful then let me know, also it would be nice to get a credit if you use it.
one last thing, i only tested this with 320x240 bitmaps, so it may screw up if your bitmap is 111x111, i dunno! :rolleyes:
images can be compressed with either RLE4, RLE8, or totally uncompressed.
it will load 4bit/8bit bitmaps in 8bit colour mode,
or 4bit/8bit/24bit bitmaps in 16bit colour mode!
e.g. usage:
Code:
sGpImage gpi;
gpi.flags = GPIMG_8BIT|GPIMG_PAL;
GpLoadBMP( "gp:\gpmm\bitmaps\test.bmp", &gpi );
GP_HPALETTE h_pal;
h_pal = GpPaletteCreateEx( gpi.colours, gpi.pPalette );
gm_free( gpi.pPalette );
gpi.pPalette = NULL;
GpPaletteSelect( h_pal );
GpPaletteRealize();
GpPaletteDelete( h_pal );
h_pal = NULL;
GpBitBlt( NULL, &gp32.LCD[0], 0, 0, 320, 240, (unsigned char*)gpi.pImage, 0, 0, 320, 240 );
GpBitBlt( NULL, &gp32.LCD[1], 0, 0, 320, 240, (unsigned char*)gpi.pImage, 0, 0, 320, 240 );
gm_free( gpi.pImage );
flags:
GPIMG_8BIT - load the bitmap as 8bit*
GPIMG_16BIT - load the bitmap as 16bit
GPIMG_PAL - load the bitmap's palette*
*does not work for 24bit bitmaps with no palette information!
flag combinations:
GPIMG_PAL - only load the palette!
GPIMG_8BIT - only load the bitmap!
GPIMG_8BIT|GPIMG_PAL - load the bitmap and the palette!
Code:
/*******************************************
gp_image.h - GamePark Image Lib - by Feeblez
*******************************************/
#ifndef _GP_IMAGE_H_
#define _GP_IMAGE_H_
#include "gpdef.h"
#include "gpgraphic.h" /* GP_LOGPALENTRY */
#ifdef __cplusplus
extern "C" {
#endif
enum eGpImage
{
/* flags */
GPIMG_8BIT = 1<<0,
GPIMG_16BIT = 1<<1,
GPIMG_PAL = 1<<2
};
struct sGpImage
{
dword flags;
unsigned char* pImage;
ulong w;
ulong h;
GP_LOGPALENTRY* pPalette;
ulong colours; /* <- Mr.Bean's English! */
};
#ifdef __cplusplus
}
#endif
#endif //_GP_IMAGE_H_
Code:
/*****************************************
gp_bmp.h - GamePark Image Lib - by Feeblez
*****************************************/
#ifndef _GP_BMP_H_
#define _GP_BMP_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "gp_image.h"
int GpLoadBMP( const char* strFilename, struct sGpImage* gpi );
#ifdef __cplusplus
}
#endif
#endif //_GP_BMP_H_
Code:
/*****************************************
gp_bmp.c - GamePark Image Lib - by Feeblez
*****************************************/
#include "gp_bmp.h"
#include "gpstdio.h" /* F_HANDLE */
#include "gpmem.h" /* gp_mem */
#define BMP_HDR_DATA_OFFSET 10 /* dword bfOffBits */
#define BMP_HDR_WIDTH 18 /* long biWidth */
#define BMP_HDR_HEIGHT 22 /* long biHeight */
#define BMP_HDR_BPP 28 /* word biBitCount */
#define BMP_HDR_COMPRESSION 30 /* dword biCompression */
#define BMP_HDR_DATA_SIZE 34 /* dword biSizeImage */
#define BMP_HDR_COLOURS 46 /* dword biClrUsed */
#define BMP_HDR_SIZE 54
enum eGpBmp
{
/* bit depth */
BMP_MONOCHROME = 1,
BMP_4_BIT = 4,
BMP_8_BIT = 8,
BMP_24_BIT = 24,
/* compression */
BMP_RGB = 0,
BMP_RLE8,
BMP_RLE4,
BMP_BITFIELDS
};
int GpLoadBMP( const char* strFilename, struct sGpImage* gpi )
{
F_HANDLE hFile;
ERR_CODE err;
ulong read_count = 0;
long old_offset;
char* pData;
/* relevant header info */
ulong bfOffBits;
int biHeight;
word biBitCount;
ulong biCompression;
ulong biSizeImage;
ulong i;
int next_line;
int x, y;
gpi->w = gpi->h = gpi->colours = 0;
gpi->pImage = NULL;
gpi->pPalette = NULL;
if( !strFilename || !*strFilename ) /* bad filename! */
return 0;
err = GpFileOpen( strFilename, OPEN_R, &hFile );
if( err != SM_OK ) /* error opening file */
return 0;
pData = (char*)gm_malloc( BMP_HDR_SIZE );
err = GpFileRead( hFile, pData, BMP_HDR_SIZE, &read_count );
if( err != SM_OK ) /* error reading file! */
goto _fail;
if( gpi->flags & (GPIMG_8BIT|GPIMG_16BIT) )
{
gm_memcpy( &bfOffBits, pData + BMP_HDR_DATA_OFFSET, sizeof(dword) );
gm_memcpy( &biCompression, pData + BMP_HDR_COMPRESSION, sizeof(dword) );
gm_memcpy( &biSizeImage, pData + BMP_HDR_DATA_SIZE, sizeof(dword) );
gm_memcpy( &gpi->w, pData + BMP_HDR_WIDTH, sizeof(dword) );
gm_memcpy( &biHeight, pData + BMP_HDR_HEIGHT, sizeof(dword) );
gpi->h = biHeight & 0x8fffffff;
}
gm_memcpy( &biBitCount, pData + BMP_HDR_BPP, sizeof(word) );
gm_memcpy( &gpi->colours, pData + BMP_HDR_COLOURS, sizeof(dword) );
gm_free( pData );
switch( biBitCount )
{
case BMP_4_BIT:
if( !gpi->colours )
gpi->colours = 16;
break;
case BMP_8_BIT:
if( !gpi->colours )
gpi->colours = 256;
break;
case BMP_24_BIT:
if( (gpi->flags & GPIMG_8BIT) || !(gpi->flags & GPIMG_16BIT) )
goto _fail;
break;
default: /* unsupported bpp! */
/* case BMP_MONOCHROME: */
goto _fail;
};
if( (biBitCount <= BMP_8_BIT) && ((gpi->flags & GPIMG_PAL) || (gpi->flags & GPIMG_16BIT)) )
{
gpi->pPalette = (GP_LOGPALENTRY*)gm_malloc( sizeof(GP_LOGPALENTRY) * gpi->colours );
err = GpFileRead( hFile, gpi->pPalette, sizeof(GP_LOGPALENTRY) * gpi->colours, &read_count );
if( err != SM_OK ) /* error reading file */
goto _fail;
/* BGR -> RGB */
for( i = 0; i < gpi->colours; i++ )
gpi->pPalette[i].peRed ^= gpi->pPalette[i].peBlue ^= gpi->pPalette[i].peRed ^= gpi->pPalette[i].peBlue;
if( !(gpi->flags & (GPIMG_8BIT|GPIMG_16BIT)) )
goto _done; /* all done! */
}
if( gpi->flags & GPIMG_8BIT )
{
unsigned char* sp;
unsigned char* dp;
int count;
int align;
if( biBitCount == BMP_24_BIT ) /* unsupported bpp for 8bit! */
goto _fail;
err = GpFileSeek( hFile, FROM_BEGIN, bfOffBits, &old_offset );
if( err != SM_OK ) /* error seeking file */
goto _fail;
if( !biSizeImage )
{
if( biCompression != BMP_RGB )
goto _fail;
biSizeImage = gpi->w * gpi->h;
}
pData = (unsigned char*)gm_malloc( biSizeImage );
err = GpFileRead( hFile, pData, biSizeImage, &read_count );
if( err != SM_OK ) /* error reading file */
goto _fail;
sp = pData;
gpi->pImage = (unsigned char*)gm_malloc( gpi->w * gpi->h );
dp = gpi->pImage;
if( biHeight < 0 )
{
dp += gpi->h - 1;
next_line = -1 - (gpi->w * gpi->h);
}
else /* bottom-up! oooer */
next_line = 1 - (gpi->w * gpi->h);
x = gpi->w;
y = gpi->h;
if( biBitCount == BMP_8_BIT )
{
if( biCompression == BMP_RLE8 )
{
unsigned char colour;
do
{
switch( *sp )
{
case 0:
sp++;
switch( *sp )
{
/* end of line */
case 0:
sp++;
while( x-- )
{
/* *dp = 0; */
dp += gpi->h;
}
dp += next_line;
x = gpi->w;
y--;
break;
/* end of bitmap */
case 1:
y = 0;
break;
/* delta offset 00 02 X Y */
case 2:
sp++;
count = *sp++;
x -= count;
while( count-- )
{
/* *dp = 0; */
dp += gpi->h;
}
count = *sp++;
y -= count;
while( count-- )
{
/* *dp = 0; */
dp += next_line;
}
break;
/* run of pixels */
default:
count = *sp++;
align = count & 1;
x -= count;
while( count-- )
{
*dp = *sp++;
dp += gpi->h;
}
if( align )
sp++;
break;
}
break;
/* repeat pixel */
default:
count = *sp++;
colour = *sp++;
x -= count;
while( count-- )
{
*dp = colour;
dp += gpi->h;
}
break;
}
}
while(y);
}
else
{
for( y = 0; y < gpi->h; y++ )
{
for( x = 0; x < gpi->w; x++ )
{
*dp = *sp++;
dp += gpi->h;
}
dp += next_line;
}
}
}
else
if( biBitCount == BMP_4_BIT )
{
int nibble;
unsigned char nibble_shift[2] = { 4, 0 };
unsigned char nibble_colour[2];
if( biCompression == BMP_RLE4 )
{
do
{
switch( *sp )
{
case 0:
sp++;
switch( *sp )
{
/* end of line */
case 0:
sp++;
while( x-- )
{
/* *dp = 0; */
dp += gpi->h;
}
dp += next_line;
x = gpi->w;
y--;
break;
/* end of bitmap */
case 1:
y = 0;
break;
/* delta offset 00 02 X Y */
case 2:
sp++;
count = *sp++;
x -= count;
while( count-- )
{
/* *dp = 0; */
dp += gpi->h;
}
count = *sp++;
y -= count;
while( count-- )
{
/* *dp = 0; */
dp += next_line;
}
break;
/* run of pixels */
default:
count = *sp++;
align = count % 4;
if( align )
{
if( align == 1 )
align = 2;
else
align = 1;
}
x -= count;
nibble = 0;
while( count-- )
{
*dp = (*sp >> nibble_shift[nibble]) & 0xf;
dp += gpi->h;
nibble ^= 1;
if( !nibble )
sp++;
}
if( align )
sp += align;
break;
}
break;
/* repeat pixel */
default:
count = *sp++;
nibble_colour[0] = *sp >> 4;
nibble_colour[1] = *sp++ & 0xf;
x -= count;
nibble = 0;
while( count-- )
{
*dp = nibble_colour[nibble];
dp += gpi->h;
nibble ^= 1;
}
break;
}
}
while(y);
}
else
{
for( y = 0; y < gpi->h; y++ )
{
nibble = 0;
for( x = 0; x < gpi->w; x++ )
{
*dp = (*sp >> nibble_shift[nibble]) & 0xf;
dp += gpi->h;
nibble ^= 1;
if( !nibble )
sp++;
}
dp += next_line;
}
}
}
}
else
if( gpi->flags & GPIMG_16BIT )
{
unsigned char* sp;
word* dp;
int count;
int align;
word* pPalette = NULL;
err = GpFileSeek( hFile, FROM_BEGIN, bfOffBits, &old_offset );
if( err != SM_OK ) /* error seeking file */
goto _fail;
if( !biSizeImage )
{
if( biCompression != BMP_RGB )
goto _fail;
biSizeImage = gpi->w * gpi->h * 2;
}
pData = (unsigned char*)gm_malloc( biSizeImage );
err = GpFileRead( hFile, pData, biSizeImage, &read_count );
if( err != SM_OK ) /* error reading file */
goto _fail;
sp = pData;
gpi->pImage = (unsigned char*)gm_malloc( gpi->w * gpi->h * 2 );
dp = (word*)gpi->pImage;
if( biHeight < 0 )
{
dp += gpi->h - 1;
next_line = -1 - (gpi->w * gpi->h);
}
else /* bottom-up! oooer */
next_line = 1 - (gpi->w * gpi->h);
if( gpi->pPalette )
{
pPalette = (word*)gm_malloc( gpi->colours * 2 );
for( i = 0; i < gpi->colours; i++ )
{
pPalette[i] =
((gpi->pPalette[i].peRed >> 3) << 11) |
((gpi->pPalette[i].peGreen >> 3) << 6) |
((gpi->pPalette[i].peBlue >> 3) << 1);
}
if( !(gpi->flags & GPIMG_PAL) )
{
gm_free( gpi->pPalette );
gpi->pPalette = NULL;
}
}
x = gpi->w;
y = gpi->h;
if( biBitCount == BMP_24_BIT )
{
for( y = 0; y < gpi->h; y++ )
{
for( x = 0; x < gpi->w; x++ )
{
*dp =
((sp[2] >> 3) << 11) |
((sp[1] >> 3) << 6) |
((sp[0] >> 3) << 1);
sp += 3;
dp += gpi->h;
}
dp += next_line;
}
}
else
if( biBitCount == BMP_8_BIT )
{
if( biCompression == BMP_RLE8 )
{
word colour;
do
{
switch( *sp )
{
case 0:
sp++;
switch( *sp )
{
/* end of line */
case 0:
sp++;
while( x-- )
{
/* *dp = 0; */
dp += gpi->h;
}
dp += next_line;
x = gpi->w;
y--;
break;
/* end of bitmap */
case 1:
y = 0;
break;
/* delta offset 00 02 X Y */
case 2:
sp++;
count = *sp++;
x -= count;
while( count-- )
{
/* *dp = 0; */
dp += gpi->h;
}
count = *sp++;
y -= count;
while( count-- )
{
/* *dp = 0; */
dp += next_line;
}
break;
/* run of pixels */
default:
count = *sp++;
align = count & 1;
x -= count;
while( count-- )
{
*dp = pPalette[*sp++];
dp += gpi->h;
}
if( align )
sp++;
break;
}
break;
/* repeat pixel */
default:
count = *sp++;
colour = pPalette[*sp++];
x -= count;
while( count-- )
{
*dp = colour;
dp += gpi->h;
}
break;
}
}
while(y);
}
else
{
for( y = 0; y < gpi->h; y++ )
{
for( x = 0; x < gpi->w; x++ )
{
*dp = pPalette[*sp++];
dp += gpi->h;
}
dp += next_line;
}
}
}
else
if( biBitCount == BMP_4_BIT )
{
int nibble;
word nibble_shift[2] = { 4, 0 };
word nibble_colour[2];
if( biCompression == BMP_RLE4 )
{
do
{
switch( *sp )
{
case 0:
sp++;
switch( *sp )
{
/* end of line */
case 0:
sp++;
while( x-- )
{
/* *dp = 0; */
dp += gpi->h;
}
dp += next_line;
x = gpi->w;
y--;
break;
/* end of bitmap */
case 1:
y = 0;
break;
/* delta offset 00 02 X Y */
case 2:
sp++;
count = *sp++;
x -= count;
while( count-- )
{
/* *dp = 0; */
dp += gpi->h;
}
count = *sp++;
y -= count;
while( count-- )
{
/* *dp = 0; */
dp += next_line;
}
break;
/* run of pixels */
default:
count = *sp++;
align = count % 4;
if( align )
{
if( align == 1 )
align = 2;
else
align = 1;
}
x -= count;
nibble = 0;
while( count-- )
{
*dp = pPalette[(*sp >> nibble_shift[nibble]) & 0xf];
dp += gpi->h;
nibble ^= 1;
if( !nibble )
sp++;
}
if( align )
sp += align;
break;
}
break;
/* repeat pixel */
default:
count = *sp++;
nibble_colour[0] = pPalette[*sp >> 4];
nibble_colour[1] = pPalette[*sp++ & 0xf];
x -= count;
nibble = 0;
while( count-- )
{
*dp = nibble_colour[nibble];
dp += gpi->h;
nibble ^= 1;
}
break;
}
}
while(y);
}
else
{
for( y = 0; y < gpi->h; y++ )
{
nibble = 0;
for( x = 0; x < gpi->w; x++ )
{
*dp = pPalette[(*sp >> nibble_shift[nibble]) & 0xf];
dp += gpi->h;
nibble ^= 1;
if( !nibble )
sp++;
}
dp += next_line;
}
}
}
if( pPalette )
{
gm_free( pPalette );
pPalette = NULL;
}
}
gm_free( pData );
_done:
err = GpFileClose( hFile );
if( err != SM_OK ) /* error closing file */
return 0;
return 1;
_fail:
GpFileClose( hFile );
if( pData )
gm_free( pData );
if( gpi->pPalette )
{
gm_free( gpi->pPalette );
gpi->pPalette = NULL;
}
if( gpi->pImage )
{
gm_free( gpi->pImage );
gpi->pImage = NULL;
}
return 0;
}
ok, so the code is not 6 lines of optimized ARM!
if you find this code useful then let me know, also it would be nice to get a credit if you use it.
one last thing, i only tested this with 320x240 bitmaps, so it may screw up if your bitmap is 111x111, i dunno! :rolleyes: