/*---------------------------------------------------------------------------- .BMP file dumper Chris Giese http://SisAndHappy.com/ChrisGiese/ This code is public domain (no copyright). You can do whatever you want with it. 7 April 2018: initial release ----------------------------------------------------------------------------*/ #include #if 0 #include #else typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned long uint32_t; #endif /****************************************************************************/ static uint16_t read_le16(const void *buf0) { const uint8_t *buf = buf0; uint16_t rv; rv = buf[1]; /* MSB */ rv <<= 8; rv |= buf[0]; /* LSB */ return rv; } /****************************************************************************/ static uint32_t read_le32(const void *buf0) { const uint8_t *buf = buf0; uint32_t rv; rv = buf[3]; /* MSB */ rv <<= 8; rv |= buf[2]; rv <<= 8; rv |= buf[1]; rv <<= 8; rv |= buf[0]; /* LSB */ return rv; } /****************************************************************************/ int main(int arg_c, char *arg_v[]) { uint32_t file_len, raster_start, bih_len, compr, start, len; uint16_t depth; /* 14-byte BITMAPFILEINFO header plus the first part of the 40-byte (usually) BITMAPINFO header */ uint8_t buf[34]; FILE *f; int j; if(arg_c < 2) { printf("Displays information about .BMP files.\n"); return 1; } for(j = 1; j < arg_c; j++) { if((f = fopen(arg_v[j], "rb")) == NULL) { printf("Error: can't open file '%s'\n", arg_v[j]); continue; } fseek(f, 0, SEEK_END); file_len = ftell(f); fseek(f, 0, SEEK_SET); if(fread(buf, 1, sizeof(buf), f) != sizeof(buf) || buf[0] != 'B' || buf[1] != 'M') { printf("Error: file '%s' is not a .BMP file\n", arg_v[j]); fclose(f); continue; } printf("\n.BMP file '%s':\n", arg_v[j]); raster_start = read_le32(&buf[10]); bih_len = read_le32(&buf[14]); depth = read_le16(&buf[28]); compr = read_le32(&buf[30]); printf("%lu x %lu pixels, %u planes", read_le32(&buf[18]), read_le32(&buf[22]), read_le16(&buf[26])); printf(", %u bits per pixel, compression %lu", depth, compr); if(compr == 0) printf(" (uncompressed)\n"); else if(compr == 1) printf(" (RLE8)\n"); else if(compr == 2) printf(" (RLE4)\n"); else if(compr == 3) printf(" (BITFIELDS)\n"); else printf(" (?)\n"); /* extra space at the end of BITMAPINFOHEADER might be used for the RGB masks... */ if(compr == 3 && raster_start > 14 + bih_len) /* ...or for something else; though I know not what: if(depth > 8 && raster_start > 14 + bih_len) */ { fseek(f, 54, SEEK_SET); if(fread(buf, 1, 12, f) != 12) { printf("Error reading .BMP file '%s'\n", arg_v[j]); fclose(f); continue; } printf("RGB masks=%08lX:%08lX:%08lX\n", read_le32(&buf[0]), read_le32(&buf[4]), read_le32(&buf[8])); } fclose(f); printf("Offset Size Description\n" "------ -------- -----------\n" " 0 14 BITMAPFILEHEADER\n" " 14 %8lu BITMAPINFOHEADER\n", bih_len); start = 14 + bih_len; if(depth <= 8 && raster_start > start) { len = raster_start - start; printf("%6lu %8lu palette\n", start, len); } printf("%6lu %8lu raster\n", raster_start, file_len - raster_start); } return 0; }