diff --git a/img2cpi.c b/img2cpi.c index 4f66bc3..f2da4e4 100644 --- a/img2cpi.c +++ b/img2cpi.c @@ -23,9 +23,15 @@ struct cc_char { unsigned char character; unsigned char bg, fg; }; +struct palette { + const uint8_t count; + union color colors[] __attribute__((counted_by(count))); +}; +#define LENGTHOF(...) (sizeof(__VA_ARGS__) / sizeof(*(__VA_ARGS__))) +#define PALETTE(...) { .count = LENGTHOF((union color[]){__VA_ARGS__}), .colors = {__VA_ARGS__} } const extern char font_atlas[256][11]; -const extern union color DEFAULT_PALETTE[16], DEFAULT_GRAY_PALETTE[16]; +const extern struct palette DEFAULT_PALETTE, DEFAULT_GRAY_PALETTE; struct arguments { bool fast_mode; @@ -76,8 +82,7 @@ struct image { struct image_pal { int w, h; uint8_t *pixels; - const union color *palette; - size_t palette_size; + const struct palette *palette; }; bool parse_cmdline(int argc, char **argv); @@ -85,7 +90,7 @@ void show_help(const char *progname, bool show_all, FILE *fp); struct image *image_load(const char *fp); struct image *image_new(int w, int h); struct image *image_resize(struct image *original, int new_w, int new_h); -struct image_pal *image_quantize(struct image *original, const union color *colors, size_t n_colors); +struct image_pal *image_quantize(struct image *original, const struct palette *palette); float get_color_difference(union color a, union color b); float get_color_brightness(union color clr); void image_unload(struct image *img); @@ -163,10 +168,10 @@ int main(int argc, char **argv) { } // TODO: load palette, maybe calculate it too? k-means? - const union color *palette = DEFAULT_PALETTE; + const struct palette *palette = &DEFAULT_PALETTE; switch (args.palette_type) { - case PALETTE_DEFAULT: palette = DEFAULT_PALETTE; break; - case PALETTE_DEFAULT_GRAY: palette = DEFAULT_GRAY_PALETTE; break; + case PALETTE_DEFAULT: palette = &DEFAULT_PALETTE; break; + case PALETTE_DEFAULT_GRAY: palette = &DEFAULT_GRAY_PALETTE; break; case PALETTE_AUTO: assert(0 && "Not implemented"); break; case PALETTE_LIST: assert(0 && "Not implemented"); break; case PALETTE_PATH: assert(0 && "Not implemented"); break; @@ -198,7 +203,7 @@ int main(int argc, char **argv) { // TODO: actually do stuff struct cc_char *characters = calloc(args.width * args.height, sizeof(struct cc_char)); - struct image_pal *quantized_image = image_quantize(canvas, palette, 16); + struct image_pal *quantized_image = image_quantize(canvas, palette); if (!quantized_image) { fprintf(stderr, "Error: failed to open the file\n"); return EXIT_FAILURE; @@ -217,9 +222,9 @@ int main(int argc, char **argv) { fputc(args.height, fp); fputc(0x00, fp); for (int i = 0; i < 16; i++) { - fputc(palette[i].rgba.r, fp); - fputc(palette[i].rgba.g, fp); - fputc(palette[i].rgba.b, fp); + fputc(palette->colors[i].rgba.r, fp); + fputc(palette->colors[i].rgba.g, fp); + fputc(palette->colors[i].rgba.b, fp); } for (int i = 0; i < args.width * args.height; i++) { fputc(characters[i].character, fp); @@ -486,19 +491,18 @@ void get_size_keep_aspect(int w, int h, int dw, int dh, int *ow, int *oh) } } -struct image_pal *image_quantize(struct image *original, const union color *colors, size_t n_colors) { +struct image_pal *image_quantize(struct image *original, const struct palette *palette) { struct image_pal *out = calloc(1, sizeof(struct image_pal)); out->w = original->w; out->h = original->h; out->pixels = calloc(original->w, original->h); - out->palette = colors; - out->palette_size = n_colors; + out->palette = palette; for (int i = 0; i < out->w * out->h; i++) { int closest_color = 0; float closest_distance = 1e20; - for (int color = 0; color < n_colors; color++) { - float dist = get_color_difference(colors[color], original->pixels[i]); + for (int color = 0; color < palette->count; color++) { + float dist = get_color_difference(palette->colors[color], original->pixels[i]); if (dist <= closest_distance) { closest_distance = dist; closest_color = color; @@ -531,7 +535,7 @@ void convert_2x3(const struct image_pal *img, struct cc_char *characters) { for (int oy = 0; oy < 3; oy++) { for (int ox = 0; ox < 2; ox++) { unsigned char pix = img->pixels[ox + (x + (y * 3 + oy) * w) * 2]; - float brightness = get_color_brightness(img->palette[pix]); + float brightness = get_color_brightness(img->palette->colors[pix]); if (brightness >= brightest_diff) { brightest_i = pix; brightest_diff = brightness; @@ -549,8 +553,8 @@ void convert_2x3(const struct image_pal *img, struct cc_char *characters) { for (int ox = 0; ox < 2; ox++) { if (ox == 1 && oy == 2) continue; unsigned char pix = img->pixels[ox + (x + (y * 3 + oy) * w) * 2]; - float diff_bg = get_color_difference(img->palette[darkest_i], img->palette[pix]); - float diff_fg = get_color_difference(img->palette[brightest_i], img->palette[pix]); + float diff_bg = get_color_difference(img->palette->colors[darkest_i], img->palette->colors[pix]); + float diff_fg = get_color_difference(img->palette->colors[brightest_i], img->palette->colors[pix]); if (diff_fg < diff_bg) { bitmap |= pixel_bits[oy][ox]; } @@ -559,8 +563,8 @@ void convert_2x3(const struct image_pal *img, struct cc_char *characters) { { unsigned char pix = img->pixels[1 + (x + (y * 3 + 2) * w) * 2]; - float diff_bg = get_color_difference(img->palette[darkest_i], img->palette[pix]); - float diff_fg = get_color_difference(img->palette[brightest_i], img->palette[pix]); + float diff_bg = get_color_difference(img->palette->colors[darkest_i], img->palette->colors[pix]); + float diff_fg = get_color_difference(img->palette->colors[brightest_i], img->palette->colors[pix]); if (diff_fg < diff_bg) { bitmap ^= 31; unsigned char tmp = darkest_i; @@ -579,9 +583,9 @@ void convert_2x3(const struct image_pal *img, struct cc_char *characters) { void convert_8x11(const struct image_pal *img, struct cc_char *characters) { int w = img->w / 8, h = img->h / 11; float palette_self_diffs[0x100][0x10] = {{(float) 0xffffff}}; - for (int input_color = 0x0; input_color < 0x100 && input_color < img->palette_size; input_color++) { - for (int output_color = 0x0; output_color < 0x10 && output_color < img->palette_size; output_color++) { - palette_self_diffs[input_color][output_color] = get_color_difference(img->palette[input_color], img->palette[output_color]); + for (int input_color = 0x0; input_color < 0x100 && input_color < img->palette->count; input_color++) { + for (int output_color = 0x0; output_color < 0x10 && output_color < img->palette->count; output_color++) { + palette_self_diffs[input_color][output_color] = get_color_difference(img->palette->colors[input_color], img->palette->colors[output_color]); } } @@ -593,7 +597,7 @@ void convert_8x11(const struct image_pal *img, struct cc_char *characters) { uint8_t pixel_unresolved = img->pixels[ ox + (x + (y * 11 + oy) * w) * 8 ]; - for (int color = 0x0; color < 0x10 && color < img->palette_size; color++) { + for (int color = 0x0; color < 0x10 && color < img->palette->count; color++) { chunk_palette_diffs[ox][oy][color] = palette_self_diffs[pixel_unresolved][color]; } } @@ -628,7 +632,7 @@ void convert_8x11(const struct image_pal *img, struct cc_char *characters) { } } -const union color DEFAULT_PALETTE[16] = { +const struct palette DEFAULT_PALETTE = PALETTE( { { 0xf0, 0xf0, 0xf0, 0xff } }, { { 0xf2, 0xb2, 0x33, 0xff } }, { { 0xe5, 0x7f, 0xd8, 0xff } }, @@ -645,7 +649,7 @@ const union color DEFAULT_PALETTE[16] = { { { 0x57, 0xa6, 0x4e, 0xff } }, { { 0xcc, 0x4c, 0x4c, 0xff } }, { { 0x11, 0x11, 0x11, 0xff } } -}, DEFAULT_GRAY_PALETTE[16] = { +), DEFAULT_GRAY_PALETTE = PALETTE( { { 0xf0, 0xf0, 0xf0, 0xff } }, { { 0x9d, 0x9d, 0x9d, 0xff } }, { { 0xbe, 0xbe, 0xbe, 0xff } }, @@ -662,7 +666,7 @@ const union color DEFAULT_PALETTE[16] = { { { 0x6e, 0x6e, 0x6e, 0xff } }, { { 0x76, 0x76, 0x76, 0xff } }, { { 0x11, 0x11, 0x11, 0xff } } -}; +); const char font_atlas[256][11] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },