// x-run: make test-cpi2png #include #include #include #include #include #include #include #include "cc-common.h" int main(int argc, char **argv) { if (argc < 3) { fprintf(stderr, "Usage: %s [input.cpi] [output.png]\n", argv[0]); } FILE *fp_in = fopen(argv[1], "rb"); assert(fp_in != NULL && "Failed to open input file"); unsigned char header[4]; unsigned char version = 0; assert(fread(header, 1, 4, fp_in) == 4 && "Failed to read header: not enough bytes"); if (0 == memcmp(header, "CCPI", 4)) { // Original CCPI (CPIv0) version = 0; } else if (0 == memcmp(header, "CPI", 3)) { // Newer CCPI (CPIvX) version = header[3]; } else { assert(false && "Not a CPI/CCPI image: invalid header"); } if (version & 0x80) { fprintf(stderr, "Draft version: 0x%02x may not be supported properly! Here be dragons!\n", version); } unsigned int width = 0, height = 0; if (version == 0) { width = fgetc(fp_in); height = fgetc(fp_in); (void)fgetc(fp_in); // XXX: ignore scale } else if (version == 1) { assert(read_varint(fp_in, &width) > 0 && "Failed to read width varint"); assert(read_varint(fp_in, &height) > 0 && "Failed to read height varint"); } else { assert(false && "Failed to read size: unsupported version"); } union color *canvas = malloc(width * height * 6 * 9 * sizeof(union color)); // XXX: may change in future when we introduce variable-size palettes // though, it may never change, if I'm being honest. Why would I choose // worse image quality with less colors when I can use all of them? union color colors[16] = { 0 }; // NOTE: our `union color` type is 4 bytes long, while palette stored in the // file itself uses 3 bytes per color, so we can't just `fread` them at once, // sadly. for (int i = 0; i < 16; i++) { colors[i].rgba.r = fgetc(fp_in); colors[i].rgba.g = fgetc(fp_in); colors[i].rgba.b = fgetc(fp_in); colors[i].rgba.a = 0xff; } unsigned char *buffer = calloc(width * height, 2); fread(buffer, 2, width * height, fp_in); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { unsigned char sym = buffer[(x + y * width) * 2]; unsigned char color = buffer[(x + y * width) * 2 + 1]; union color background = colors[color & 0xF]; union color foreground = colors[color >> 4]; for (int oy = 0; oy < 9; oy++) { for (int ox = 0; ox < 6; ox++) { union color pix = ((0x80 >> (ox + 1)) & cc_font_atlas[sym][oy + 1]) ? foreground : background; canvas[ox + (x + (y * 9 + oy) * width) * 6] = pix; } } } } stbi_write_png(argv[2], width * 6, height * 9, 4, canvas, 0); free(canvas); fclose(fp_in); return EXIT_SUCCESS; }