From 1eccdde3a34dd4269f777373a2d1a5039c2e8211 Mon Sep 17 00:00:00 2001 From: hkc Date: Wed, 2 Oct 2024 15:31:24 +0300 Subject: [PATCH] Moved stuff into separate functions, minor cleanup --- img2cpi.c | 264 +++++++++++++++++++++++++++--------------------------- 1 file changed, 134 insertions(+), 130 deletions(-) diff --git a/img2cpi.c b/img2cpi.c index 790df88..62fff89 100644 --- a/img2cpi.c +++ b/img2cpi.c @@ -76,6 +76,8 @@ struct image { struct image_pal { int w, h; uint8_t *pixels; + const union color *palette; + size_t palette_size; }; bool parse_cmdline(int argc, char **argv); @@ -89,6 +91,9 @@ float get_color_brightness(union color clr); void image_unload(struct image *img); void get_size_keep_aspect(int w, int h, int dw, int dh, int *ow, int *oh); +void convert_2x3(const struct image_pal *img, struct cc_char *characters); +void convert_8x11(const struct image_pal *img, struct cc_char *characters); + const char *known_file_extensions[] = { ".png", ".jpg", ".jpeg", ".jfif", ".jpg", ".gif", ".tga", ".bmp", ".hdr", ".pnm", 0 @@ -190,7 +195,6 @@ int main(int argc, char **argv) { small_w * sizeof(union color)); } - // TODO: actually do stuff struct cc_char *characters = calloc(args.width * args.height, sizeof(struct cc_char)); @@ -200,105 +204,10 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } - FILE *tmp = fopen("/tmp/img.raw", "wb"); - for (int i = 0; i < quantized_image->w * quantized_image->h; i++) { - union color pix = palette[quantized_image->pixels[i]]; - fputc(pix.rgba.r, tmp); - fputc(pix.rgba.g, tmp); - fputc(pix.rgba.b, tmp); - } - fclose(tmp); - if (args.fast_mode) { - // use old 2x3 - for (int y = 0; y < args.height; y++) { - for (int x = 0; x < args.width; x++) { - unsigned char darkest_i = 0, brightest_i = 0; - float darkest_diff = 0xffffff, brightest_diff = 0; - - for (int oy = 0; oy < 3; oy++) { - for (int ox = 0; ox < 2; ox++) { - unsigned char pix = quantized_image->pixels[ox + (x + (y * 3 + oy) * args.width) * 2]; - float brightness = get_color_brightness(palette[pix]); - if (brightness >= brightest_diff) { - brightest_i = pix; - brightest_diff = brightness; - } - if (brightness <= darkest_diff) { - darkest_i = pix; - darkest_diff = brightness; - } - } - } - - unsigned char bitmap = 0; - const static unsigned char pixel_bits[3][2] = { { 1, 2}, { 4, 8 }, { 16, 0 } }; - for (int oy = 0; oy < 3; oy++) { - for (int ox = 0; ox < 2; ox++) { - if (ox == 1 && oy == 2) continue; - unsigned char pix = quantized_image->pixels[ox + (x + (y * 3 + oy) * args.width) * 2]; - float diff_bg = get_color_difference(palette[darkest_i], palette[pix]); - float diff_fg = get_color_difference(palette[brightest_i], palette[pix]); - if (diff_fg < diff_bg) { - bitmap |= pixel_bits[oy][ox]; - } - } - } - - { - unsigned char pix = quantized_image->pixels[1 + (x + (y * 3 + 2) * args.width) * 2]; - float diff_bg = get_color_difference(palette[darkest_i], palette[pix]); - float diff_fg = get_color_difference(palette[brightest_i], palette[pix]); - if (diff_fg < diff_bg) { - bitmap ^= 31; - unsigned char tmp = darkest_i; - darkest_i = brightest_i; - brightest_i = tmp; - } - } - - characters[x + y * args.width].character = 0x80 + bitmap; - characters[x + y * args.width].bg = darkest_i; - characters[x + y * args.width].fg = brightest_i; - } - } + convert_2x3(quantized_image, characters); } else { - // use new 8x11 character matching - for (int y = 0; y < args.height; y++) { - for (int x = 0; x < args.width; x++) { - // Oh boy... - float min_diff = 0xffffff; - char closest_sym = 0x00, closest_color = 0xae; - for (int sym = 0x01; sym <= 0xFF; sym++) { - if (sym == '\t' || sym == '\n' || sym == '\r' || sym == '\x0e') { - continue; - } - for (int color = 0x00; color <= 0xff; color++) { - union color cell_bg = palette[color & 0xF], - cell_fg = palette[color >> 4]; - float difference = 0; - for (int oy = 0; oy < 11; oy++) { - unsigned char sym_line = font_atlas[sym][oy]; - for (int ox = 0; ox < 8; ox++) { - bool lit = sym_line & (0x80 >> ox); - union color pixel = palette[quantized_image->pixels[ - ox + (x + (y * 11 + oy) * args.width) * 8 - ]]; - difference += get_color_difference(pixel, lit ? cell_fg : cell_bg); - } - } - if (difference <= min_diff) { - min_diff = difference; - closest_sym = sym; - closest_color = color; - } - } - } - characters[x + y * args.width].character = closest_sym; - characters[x + y * args.width].bg = closest_color & 0xF; - characters[x + y * args.width].fg = closest_color >> 4; - } - } + convert_8x11(quantized_image, characters); } // TODO: implement something other than CPIv0 @@ -582,6 +491,8 @@ struct image_pal *image_quantize(struct image *original, const union color *colo out->w = original->w; out->h = original->h; out->pixels = calloc(original->w, original->h); + out->palette = colors; + out->palette_size = n_colors; for (int i = 0; i < out->w * out->h; i++) { int closest_color = 0; @@ -610,40 +521,133 @@ float get_color_brightness(union color clr) { return get_color_difference(clr, (union color){ .v = 0 }); } +void convert_2x3(const struct image_pal *img, struct cc_char *characters) { + int w = img->w / 2, h = img->h / 3; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + unsigned char darkest_i = 0, brightest_i = 0; + float darkest_diff = 0xffffff, brightest_diff = 0; + + 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]); + if (brightness >= brightest_diff) { + brightest_i = pix; + brightest_diff = brightness; + } + if (brightness <= darkest_diff) { + darkest_i = pix; + darkest_diff = brightness; + } + } + } + + unsigned char bitmap = 0; + const static unsigned char pixel_bits[3][2] = { { 1, 2}, { 4, 8 }, { 16, 0 } }; + for (int oy = 0; oy < 3; oy++) { + 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]); + if (diff_fg < diff_bg) { + bitmap |= pixel_bits[oy][ox]; + } + } + } + + { + 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]); + if (diff_fg < diff_bg) { + bitmap ^= 31; + unsigned char tmp = darkest_i; + darkest_i = brightest_i; + brightest_i = tmp; + } + } + + characters[x + y * w].character = 0x80 + bitmap; + characters[x + y * w].bg = darkest_i; + characters[x + y * w].fg = brightest_i; + } + } +} + +void convert_8x11(const struct image_pal *img, struct cc_char *characters) { + int w = img->w / 8, h = img->h / 11; + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + float min_diff = 0xffffff; + char closest_sym = 0x00, closest_color = 0xae; + for (int sym = 0x01; sym <= 0xFF; sym++) { + if (sym == '\t' || sym == '\n' || sym == '\r' || sym == '\x0e') { + continue; + } + for (int color = 0x00; color <= 0xff; color++) { + union color cell_bg = img->palette[color & 0xF], + cell_fg = img->palette[color >> 4]; + float difference = 0; + for (int oy = 0; oy < 11; oy++) { + unsigned char sym_line = font_atlas[sym][oy]; + for (int ox = 0; ox < 8; ox++) { + bool lit = sym_line & (0x80 >> ox); + union color pixel = img->palette[img->pixels[ + ox + (x + (y * 11 + oy) * w) * 8 + ]]; + difference += get_color_difference(pixel, lit ? cell_fg : cell_bg); + } + } + if (difference <= min_diff) { + min_diff = difference; + closest_sym = sym; + closest_color = color; + } + } + } + characters[x + y * w].character = closest_sym; + characters[x + y * w].bg = closest_color & 0xF; + characters[x + y * w].fg = closest_color >> 4; + } + } +} + const union color DEFAULT_PALETTE[16] = { - { 0xf0, 0xf0, 0xf0, 0xff }, - { 0xf2, 0xb2, 0x33, 0xff }, - { 0xe5, 0x7f, 0xd8, 0xff }, - { 0x99, 0xb2, 0xf2, 0xff }, - { 0xde, 0xde, 0x6c, 0xff }, - { 0x7f, 0xcc, 0x19, 0xff }, - { 0xf2, 0xb2, 0xcc, 0xff }, - { 0x4c, 0x4c, 0x4c, 0xff }, - { 0x99, 0x99, 0x99, 0xff }, - { 0x4c, 0x99, 0xb2, 0xff }, - { 0xb2, 0x66, 0xe5, 0xff }, - { 0x33, 0x66, 0xcc, 0xff }, - { 0x7f, 0x66, 0x4c, 0xff }, - { 0x57, 0xa6, 0x4e, 0xff }, - { 0xcc, 0x4c, 0x4c, 0xff }, - { 0x11, 0x11, 0x11, 0xff } + { { 0xf0, 0xf0, 0xf0, 0xff } }, + { { 0xf2, 0xb2, 0x33, 0xff } }, + { { 0xe5, 0x7f, 0xd8, 0xff } }, + { { 0x99, 0xb2, 0xf2, 0xff } }, + { { 0xde, 0xde, 0x6c, 0xff } }, + { { 0x7f, 0xcc, 0x19, 0xff } }, + { { 0xf2, 0xb2, 0xcc, 0xff } }, + { { 0x4c, 0x4c, 0x4c, 0xff } }, + { { 0x99, 0x99, 0x99, 0xff } }, + { { 0x4c, 0x99, 0xb2, 0xff } }, + { { 0xb2, 0x66, 0xe5, 0xff } }, + { { 0x33, 0x66, 0xcc, 0xff } }, + { { 0x7f, 0x66, 0x4c, 0xff } }, + { { 0x57, 0xa6, 0x4e, 0xff } }, + { { 0xcc, 0x4c, 0x4c, 0xff } }, + { { 0x11, 0x11, 0x11, 0xff } } }, DEFAULT_GRAY_PALETTE[16] = { - { 0xf0, 0xf0, 0xf0, 0xff }, - { 0x9d, 0x9d, 0x9d, 0xff }, - { 0xbe, 0xbe, 0xbe, 0xff }, - { 0xbf, 0xbf, 0xbf, 0xff }, - { 0xb8, 0xb8, 0xb8, 0xff }, - { 0x76, 0x76, 0x76, 0xff }, - { 0xd0, 0xd0, 0xd0, 0xff }, - { 0x4c, 0x4c, 0x4c, 0xff }, - { 0x99, 0x99, 0x99, 0xff }, - { 0x87, 0x87, 0x87, 0xff }, - { 0xa9, 0xa9, 0xa9, 0xff }, - { 0x77, 0x77, 0x77, 0xff }, - { 0x65, 0x65, 0x65, 0xff }, - { 0x6e, 0x6e, 0x6e, 0xff }, - { 0x76, 0x76, 0x76, 0xff }, - { 0x11, 0x11, 0x11, 0xff } + { { 0xf0, 0xf0, 0xf0, 0xff } }, + { { 0x9d, 0x9d, 0x9d, 0xff } }, + { { 0xbe, 0xbe, 0xbe, 0xff } }, + { { 0xbf, 0xbf, 0xbf, 0xff } }, + { { 0xb8, 0xb8, 0xb8, 0xff } }, + { { 0x76, 0x76, 0x76, 0xff } }, + { { 0xd0, 0xd0, 0xd0, 0xff } }, + { { 0x4c, 0x4c, 0x4c, 0xff } }, + { { 0x99, 0x99, 0x99, 0xff } }, + { { 0x87, 0x87, 0x87, 0xff } }, + { { 0xa9, 0xa9, 0xa9, 0xff } }, + { { 0x77, 0x77, 0x77, 0xff } }, + { { 0x65, 0x65, 0x65, 0xff } }, + { { 0x6e, 0x6e, 0x6e, 0xff } }, + { { 0x76, 0x76, 0x76, 0xff } }, + { { 0x11, 0x11, 0x11, 0xff } } }; const char font_atlas[256][11] = {