From a9b03212984cb3821b16a6bd3e5d8686933ebd0e Mon Sep 17 00:00:00 2001 From: John Hawthorn Date: Wed, 18 Jun 2008 15:57:16 -0700 Subject: more complete bmp support. Supports 1,2,4,8,24 bit images without compression (including OS/2) --- src/bmp.c | 113 +++++++++++++++++++++++++++++++++++++++++++------------------ src/xlib.c | 2 +- 2 files changed, 81 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/bmp.c b/src/bmp.c index 9f79a9f..046fad6 100644 --- a/src/bmp.c +++ b/src/bmp.c @@ -27,14 +27,16 @@ struct rgb_t{ struct bmp_t{ struct image img; unsigned long bitmapoffset; + int compression; int bpp; int ncolors; struct rgb_t *colours; + unsigned int rowwidth; }; struct image *bmp_open(FILE *f){ struct bmp_t *b; - unsigned long headerend; + unsigned long headersize; rewind(f); if(getc(f) != 'B' || getc(f) != 'M') @@ -46,59 +48,104 @@ struct image *bmp_open(FILE *f){ fseek(f, 10, SEEK_SET); b->bitmapoffset = getlong(f); - fseek(f, 18, SEEK_SET); - b->img.width = getlong(f); - b->img.height = getlong(f); - fseek(f, 14, SEEK_SET); - headerend = 14 + getlong(f); - - fseek(f, 28, SEEK_SET); - b->bpp = getshort(f); + headersize = getlong(f); - if(b->bpp == 24){ + if(headersize == 12){ /* OS/2 v1 */ b->ncolors = 0; + fseek(f, 18, SEEK_SET); + b->img.width = getshort(f); + b->img.height = getshort(f); + b->compression = 0; }else{ - int i; + fseek(f, 18, SEEK_SET); + b->img.width = getlong(f); + b->img.height = getlong(f); + + fseek(f, 28, SEEK_SET); + b->bpp = getshort(f); + + fseek(f, 30, SEEK_SET); + b->compression = getlong(f); + fseek(f, 46, SEEK_SET); - if(!(b->ncolors = getlong(f))){ - b->ncolors = 1 << b->bpp; - } - + b->ncolors = getlong(f); + } + + if(!b->ncolors){ + b->ncolors = 1 << b->bpp; + } + + if(b->compression){ + fprintf(stderr, "unsupported compression method %i\n", b->compression); + return NULL; + } + + if(b->bpp >= 16){ + b->rowwidth = b->img.width * b->bpp; + }else{ + int i; b->colours = malloc(b->ncolors * sizeof(struct rgb_t)); - fseek(f, headerend, SEEK_SET); + fseek(f, 14+headersize, SEEK_SET); for(i = 0; i < b->ncolors; i++){ b->colours[i].b = getc(f); b->colours[i].g = getc(f); b->colours[i].r = getc(f); + if(headersize != 12) + getc(f); } + b->rowwidth = (b->img.width * b->bpp + 7) / 8; + } + if(b->rowwidth & 3){ + b->rowwidth += 4 - (b->rowwidth & 3); } return (struct image *)b; } +static void readrow(struct image *img, unsigned char *row, unsigned char *buf){ + struct bmp_t *b = (struct bmp_t *)img; + int x; + int i = 0; + if(b->bpp == 24 || b->bpp == 32){ + for(x = 0; x < img->width * 3; x+=3){ + buf[x + 2] = row[i++]; + buf[x + 1] = row[i++]; + buf[x + 0] = row[i++]; + if(b->bpp == 32) + i++; + } + }else if(b->bpp <= 8){ + int mask; + int pixelsperbit = 8 / b->bpp; + mask = ~((~0) << b->bpp); + for(x = 0; x < img->width; x++){ + unsigned char c = ((row[i / pixelsperbit]) >> ((8 - ((i+1) % pixelsperbit) * b->bpp)) % 8) & mask; + *buf++ = b->colours[c].r; + *buf++ = b->colours[c].g; + *buf++ = b->colours[c].b; + i++; + } + }else{ + fprintf(stderr, "bad bpp %i\n", b->bpp); + return; + } +} + int bmp_read(struct image *img){ struct bmp_t *b = (struct bmp_t *)img; FILE *f = img->f; fseek(f, b->bitmapoffset, SEEK_SET); - if(b->bpp == 24){ - int i, x, y; - int row = img->width * 3; - i = img->height * row; - for(y = img->height; y; y--){ - i -= row; - for(x = 0; x < img->width * 3; x+=3){ - img->buf[i + x + 2] = getc(f); - img->buf[i + x + 1] = getc(f); - img->buf[i + x + 0] = getc(f); - } - if(x & 3){ - fseek(f, 4 - (x & 3), SEEK_CUR); - } - } - }else{ - //TODO + int i, y; + int dy = img->width * 3; + i = img->height * dy; + unsigned char row[b->rowwidth]; + for(y = img->height; y; y--){ + i -= dy; + if(fread(row, 1, b->rowwidth, f) != b->rowwidth) + return 1; + readrow(img, row, &img->buf[i]); } return 0; diff --git a/src/xlib.c b/src/xlib.c index e781835..7d8c027 100644 --- a/src/xlib.c +++ b/src/xlib.c @@ -111,7 +111,7 @@ void drawimage(struct image *img, int width, int height){ static struct image *lastimg = NULL; static int lastwidth = 0, lastheight = 0; static XImage *ximg = NULL; - if(img == lastimg && width == lastwidth && height == lastheight){ + if(0 && img == lastimg && width == lastwidth && height == lastheight){ }else{ if(ximg) XDestroyImage(ximg); -- cgit v1.2.3