/******************************************************************************* * bmpdump.c * Dump the contents of a BMP (Windows Bitmap) graphics file. * * 1.0 03-23-92 drt. First cut. * 1.1 08-25-92 drt. Renamed bmp_header members. * 1.2 08-26-92 drt. Added -c option. * 1.3 09-20-92 drt. Added -D option. Reads actual size of palette. * 1.4 07-29-94 drt. Fixed CHKDATE (don't use this yet). */ static const char * prog = "bmpdump"; static const char vers[] = "1.4"; static const char date[] = "07-29-94"; static const char auth[] = "David R Tribble"; /* includes */ #include #include #include #include #include #include #include "bmp.h" /* manifest constants */ #define TRUE 1 #define FALSE 0 #ifndef CHKDATE #define CHKDATE 0 #endif /* debug macros */ #ifndef DEBUG #define DEBUG 0 #endif #if DEBUG #define D(expr) expr #define DB(expr) (dbgf != NULL ? (expr) : 0) #else #define D(expr) 0 #define DB(expr) 0 #endif /* private variables */ static FILE * dbgf = NULL; static int opt_colormap = FALSE; static int opt_data = FALSE; static unsigned pow2[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, }; /******************************************************************************* * dump_bmp * Read and dump contents of BMP file `fp' to stream `out'. */ int dump_bmp(BMP_FILE *fp, FILE *out) { unsigned x, y; unsigned len, alen; long pix; int ch; struct bmp_rgb map4[0x100]; struct os2_bmp_rgb map3[0x100]; /* read BMP file header */ DB(fprintf(dbgf, "read hdr\n")); if (bmp_read_hdr(fp) < 0) return -1; DB(fprintf(dbgf, "dump hdr\n")); bmp_dump_hdr(out, &fp->h); fprintf(out, "\n"); /* read color palette (if there is one) */ if (fp->h.bits > 0 && fp->h.bits <= 8) { /* determine actual size of color palette */ len = pow2[fp->h.bits]; alen = (fp->h.biClrUsed > 0 ? fp->h.biClrUsed : len); DB(fprintf(dbgf, "read palette, %u/%u colors\n", alen, len)); if (fp->flags & BMP_FILE_F_OS2) { /* read OS/2 BMP color map */ DB(fprintf(dbgf, "read OS/2 color map\n")); memset(map3, 0x00, sizeof(map3)); if (fread(map3, sizeof(map3[0]), alen, fp->fp) != alen) { DB(fprintf(dbgf, "can't read palette\n")); return -3; } memset(map4, 0x00, sizeof(map4)); for (x = 0; x < alen; x++) { map4[x].r = map3[x].r; map4[x].g = map3[x].g; map4[x].b = map3[x].b; map4[x].a = 0x00; } fp->map = map4; } else { /* read BMP color map */ DB(fprintf(dbgf, "read BMP color map\n")); memset(map4, 0x00, sizeof(map4)); if (fread(map4, sizeof(map4[0]), alen, fp->fp) != alen) { DB(fprintf(dbgf, "can't read palette\n")); return -3; } fp->map = map4; } if (opt_colormap) { /* dump color palette */ DB(fprintf(dbgf, "dump palette\n")); fprintf(out, "color palette\n"); bmp_dump_rgbtab(out, fp->map, alen); fprintf(out, "\n"); } } /* seek to pixel data */ DB(fprintf(dbgf, "seek=%ld\n", ftell(fp->fp))); if (fp->h.headersize > ftell(fp->fp)) { long len, pos; unsigned char buf[0x10]; /* dump extra bytes as comment data */ pos = ftell(fp->fp); len = fp->h.headersize - ftell(fp->fp); len += pos; DB(fprintf(dbgf, "dump comment data, %ld bytes\n", len)); fprintf(out, "extraneous data\n"); for ( ; pos < len; pos += 0x10) { /* print offset */ fprintf(out, "%.4lX ", pos); for (x = 0x00; x < 0x10 && pos+x < fp->h.headersize; x++) buf[x] = getc(fp->fp); /* print hex data */ for (y = x, x = 0x00; x < y; x++) fprintf(out, "%.2X ", buf[x]); for ( ; x < 0x10; x++) fprintf(out, ".. "); /* print character (ASCII) data */ fprintf(out, " ", len); for (x = 0x00; x < y; x++) fprintf(out, "%c", (isprint(buf[x] & 0x7F) ? buf[x] & 0x7F : '.')); fprintf(out, "\n"); } fprintf(out, "\n"); /* seek to start of pixel data */ DB(fprintf(dbgf, "seek to %ld\n", fp->h.headersize)); if (fseek(fp->fp, fp->h.headersize, SEEK_SET) != 0) { DB(fprintf(dbgf, "seek(%ld) failure\n", fp->h.headersize)); fprintf(out, "can't seek to pixel data (%ld)\n", fp->h.headersize); return -9; } } /* read pixel values */ if (opt_data) { DB(fprintf(dbgf, "dump pixels\n")); fprintf(out, "pixel data\n"); for (y = 0; y < fp->h.depth; y++) { /* read a scan line */ fprintf(out, "%u", fp->h.depth-y-1); DB(fprintf(dbgf, " read pix[%u][%u..%u]\n", y, 0, fp->h.width-1)); for (x = 0; x < fp->h.width; x++) { /* read next pixel value */ pix = bmp_read_pixel(fp); if (pix < 0) { fprintf(out, "\npremature end of file\n"); goto end_y; } switch (fp->h.bits) { case 1: case 2: case 4: fprintf(out, "%s%.1lX", (x % 38 == 0 ? "\n " : " "), pix); break; case 8: default: fprintf(out, "%s%.2lX", (x % 25 == 0 ? "\n " : " "), pix); break; case 24: fprintf(out, "%s%.6lX", (x % 10 == 0 ? "\n " : " "), pix); break; } } fprintf(out, "\n"); bmp_read_eoln(fp); } fprintf(out, "\n"); fprintf(out, "end of image\n\n"); } else { DB(fprintf(dbgf, "skip pixel data\n")); } end_y: return 0; } /******************************************************************************* * usage * Print usage message, then punt. */ static void usage() { fprintf(stderr, "[%s %s, %s %s]\n\n", prog, vers, date, auth); fprintf(stderr, "Dump the contents of a Windows bitmap (BMP) file.\n\n"); fprintf(stderr, "usage: %s [-option...] file...\n\n", prog); fprintf(stderr, "-c Display color map table\n"); fprintf(stderr, "-d Display image pixel data\n"); #if DEBUG fprintf(stderr, "-D Enable debugging trace\n"); #endif exit(255); } /******************************************************************************* * main */ static char inbuf[20*1024]; int main(int argc, char **argv) { int i; BMP_FILE * in; #if DEBUG fprintf(stderr, "\n--- debugs ------------------------\n"); #endif /* parse option args */ while (argc > 1 && argv[1][0] == '-') { switch (argv[1][1]) { case 'c': opt_colormap = TRUE; break; case 'd': opt_data = TRUE; break; case 'D': dbgf = stderr; break; default: usage(); } argc--, argv++; } /* check args */ if (argc < 2) usage(); #if CHKDATE > 0 if (time(NULL) >= CHKDATE) usage(); #endif /* process BMP file name args */ for (i = 1; i < argc; i++) { in = bmp_open(argv[i], O_RDONLY); if (in == NULL) { fprintf(stderr, "%s: can't read %s\n", prog, argv[i]); } else { fprintf(stdout, "%s:\n", argv[i]); setvbuf(in->fp, inbuf, _IOFBF, sizeof(inbuf)); dump_bmp(in, stdout); bmp_close(in); fflush(stdout); } } return 0; } /* end bmpdump.c */