// bmp2raw.c -- Convert a 320x200x256 BMP to raw VGA splash format // // Output format: // 768 bytes: palette (256 x 3 bytes RGB, 6-bit VGA values) // 64000 bytes: pixels (320x200, top-to-bottom scanline order) // // Total output: 64768 bytes #include #include #include #include #include #define VGA_W 320 #define VGA_H 200 #define PALETTE_ENTRIES 256 #define PIXEL_COUNT (VGA_W * VGA_H) int main(int argc, char **argv) { if (argc != 3) { fprintf(stderr, "Usage: bmp2raw \n"); return 1; } FILE *fp = fopen(argv[1], "rb"); if (!fp) { fprintf(stderr, "Cannot open %s\n", argv[1]); return 1; } // Read BMP header uint8_t hdr[54]; if (fread(hdr, 1, 54, fp) != 54) { fprintf(stderr, "Bad BMP header\n"); fclose(fp); return 1; } if (hdr[0] != 'B' || hdr[1] != 'M') { fprintf(stderr, "Not a BMP file\n"); fclose(fp); return 1; } uint32_t pixelOffset = hdr[10] | (hdr[11] << 8) | (hdr[12] << 16) | (hdr[13] << 24); int32_t width = hdr[18] | (hdr[19] << 8) | (hdr[20] << 16) | (hdr[21] << 24); int32_t height = hdr[22] | (hdr[23] << 8) | (hdr[24] << 16) | (hdr[25] << 24); uint16_t bpp = hdr[28] | (hdr[29] << 8); if (width != VGA_W || abs(height) != VGA_H || bpp != 8) { fprintf(stderr, "BMP must be %dx%d 8bpp (got %dx%d %dbpp)\n", VGA_W, VGA_H, width, abs(height), bpp); fclose(fp); return 1; } bool topDown = (height < 0); if (height < 0) { height = -height; } // Read palette (starts at offset 54 for BITMAPINFOHEADER, may vary) uint32_t dibSize = hdr[14] | (hdr[15] << 8) | (hdr[16] << 16) | (hdr[17] << 24); uint32_t palOffset = 14 + dibSize; // BMP file header (14) + DIB header fseek(fp, palOffset, SEEK_SET); uint8_t bmpPal[PALETTE_ENTRIES * 4]; if (fread(bmpPal, 4, PALETTE_ENTRIES, fp) != PALETTE_ENTRIES) { fprintf(stderr, "Cannot read palette\n"); fclose(fp); return 1; } // Convert palette: BMP is BGRA 8-bit, VGA is RGB 6-bit uint8_t vgaPal[PALETTE_ENTRIES * 3]; for (int i = 0; i < PALETTE_ENTRIES; i++) { vgaPal[i * 3 + 0] = bmpPal[i * 4 + 2] >> 2; // R vgaPal[i * 3 + 1] = bmpPal[i * 4 + 1] >> 2; // G vgaPal[i * 3 + 2] = bmpPal[i * 4 + 0] >> 2; // B } // Read pixel data fseek(fp, pixelOffset, SEEK_SET); // BMP rows are padded to 4-byte boundaries (320 is already aligned) uint8_t pixels[PIXEL_COUNT]; if (topDown) { // Already top-to-bottom if (fread(pixels, 1, PIXEL_COUNT, fp) != PIXEL_COUNT) { fprintf(stderr, "Cannot read pixel data\n"); fclose(fp); return 1; } } else { // Bottom-to-top — flip for (int y = VGA_H - 1; y >= 0; y--) { if (fread(pixels + y * VGA_W, 1, VGA_W, fp) != VGA_W) { fprintf(stderr, "Cannot read row %d\n", VGA_H - 1 - y); fclose(fp); return 1; } } } fclose(fp); // Write output FILE *out = fopen(argv[2], "wb"); if (!out) { fprintf(stderr, "Cannot create %s\n", argv[2]); return 1; } fwrite(vgaPal, 1, sizeof(vgaPal), out); fwrite(pixels, 1, PIXEL_COUNT, out); fclose(out); printf("Converted %s -> %s (%d bytes)\n", argv[1], argv[2], (int)(sizeof(vgaPal) + PIXEL_COUNT)); return 0; }