From b2f43307ffbd38da9963597b6361b30406b6b481 Mon Sep 17 00:00:00 2001 From: hkc Date: Fri, 4 Feb 2022 18:08:53 +0300 Subject: [PATCH] More housekeeping stuff & fixes * Added `testbuild` target. Used in development to test common compilers, as well as check for possible issues via OCLint. * `__{blk,bra}_*` now use state to get palette & other options. TODO: optimize number of ANSI color codes when fg==bg --- Makefile | 4 + src/fmt_strings.h | 10 +- src/mod_blocks.c | 364 +++++++++++++++++++++------------------------- src/mod_braille.c | 12 +- 4 files changed, 181 insertions(+), 209 deletions(-) diff --git a/Makefile b/Makefile index a80e449..e22701e 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,7 @@ yaitaa: lib obj/%.o: src/%.c $(CC) $(CFLAGS) $^ $(INCLUDES) -DVERSION="\"$(VERSION)\"" -c -o $@ +testbuild: + make clean all CC=clang + make clean all + oclint src/*.c diff --git a/src/fmt_strings.h b/src/fmt_strings.h index 881e63a..1c28ed8 100644 --- a/src/fmt_strings.h +++ b/src/fmt_strings.h @@ -3,11 +3,12 @@ #define S_JSON_HEAD "{\n \"width\": %d,\n \"height\": %d,\n \"data\": [\n" #define S_JSON_LSTA " [\n" -#define S_JSON_PRGB "{ \"char\": \"\\u%04x\", \"fg\": %d, \"bg\": %d }" -#define S_JSON_PBLK "{ \"char\": \"%s\", \"fg\": %d, \"bg\": %d }" +#define S_JSON_PBBW " { \"char\": \"%s\", \"fg\": 16777215, \"bg\": 0 }" +#define S_JSON_PRGB " { \"char\": \"\\u%04x\", \"fg\": %d, \"bg\": %d }" +#define S_JSON_PBLK " { \"char\": \"%s\", \"fg\": %d, \"bg\": %d }" #define S_JSON_LEND " ],\n" #define S_JSON_LEND_FINAL " ]\n" -#define S_JSON_TAIL "}" +#define S_JSON_TAIL " ]\n}" #define S_HTML_HEAD "\n" #define S_HTML_LSTA "" @@ -15,12 +16,13 @@ "background: rgb(%d, %d, %d);\">&#%d;" #define S_HTML_PBLK "" +#define S_HTML_PBBW "" #define S_HTML_LEND "\n" #define S_HTML_TAIL "
%s%s
" #define S_ANSI "\033[%d;%dm" -#define S_ANSI_S "\033[%d;%dm%s" #define S_ANSI_RGB "\033[38;2;%d;%d;%d;48;2;%d;%d;%dm" #define S_ANSI_256 "\033[38;5;%d;48;5;%dm" +#define S_ANSI_RST "\033[0m" #endif diff --git a/src/mod_blocks.c b/src/mod_blocks.c index f63b86a..54c6d04 100644 --- a/src/mod_blocks.c +++ b/src/mod_blocks.c @@ -5,213 +5,32 @@ #include "commons.h" #include "fmt_strings.h" -const char *BLOCKS[4] = { " ", "\xe2\x96\x80", "\xe2\x96\x84", "\xe2\x96\x88" }; -const char *BLOCKS_ESC[4] = { " ", "\\u2580", "\\u2584", "\\u2588" }; +const char *BLK[4] = { " ", "\xe2\x96\x80", "\xe2\x96\x84", "\xe2\x96\x88" }; +const char *BLKJ[4] = { " ", "\\u2580", "\\u2584", "\\u2588" }; + +void __blk_start_output(asc_state_t s); +void __blk_start_line(asc_state_t s, bool final); +void __blk_put_pixel(asc_state_t s, rgba8 top, rgba8 bot, bool final); +void __blk_putc_bw(asc_state_t s, int top, int bot, bool final); +void __blk_putc_ansi(asc_state_t s, int top, int bot, bool final); +void __blk_putc_256(asc_state_t s, int top, int bot, bool final); +void __blk_putc_true(asc_state_t s, rgba8 top, rgba8 bot, bool final); +void __blk_end_line(asc_state_t s, bool final); +void __blk_end_output(asc_state_t s); void mod_blocks_prepare(asc_state_t *state) { - int w, h; + int width, height; get_size_keep_aspect( state->source_image->width, state->source_image->height, - state->args.width, state->args.height * 2, &w, &h); - h = (h / 2) * 2; - state->image = image_resize(state->source_image, w, h); + state->args.width, state->args.height * 2, &width, &height); + height = (height / 2) * 2; + state->image = image_resize(state->source_image, width, height); if (state->args.dither) m_prepare_dither(state); } -void __blk_start_output(asc_state_t state) -{ - switch (state.args.out_format) - { - case ASC_FMT_JSON: - fprintf(state.out_file, "{\n"); - fprintf(state.out_file, " \"width\": %d,\n", state.image->width); - fprintf(state.out_file, " \"height\": %d,\n", state.image->height / 2); - fprintf(state.out_file, " \"data\": ["); - break; - case ASC_FMT_HTML: - fprintf(state.out_file, "\n"); - break; - default: - break; - } -} - -void __blk_end_output(asc_state_t state) -{ - switch (state.args.out_format) - { - case ASC_FMT_JSON: - fprintf(state.out_file, " ]\n}"); - break; - case ASC_FMT_HTML: - fprintf(state.out_file, "
\n"); - break; - default: - break; - } -} - -void __blk_start_line(FILE *fp, asc_format_t fmt, bool final) -{ - (void)final; - if (fmt == ASC_FMT_JSON) - fprintf(fp, S_JSON_LSTA); - else if (fmt == ASC_FMT_HTML) - fprintf(fp, S_HTML_LSTA); -} - -void __blk_end_line(FILE *fp, asc_format_t fmt, asc_style_t stl, bool final) -{ - switch (fmt) - { - case ASC_FMT_JSON: - fprintf(fp, final ? " ]\n" : " ],\n"); - break; - case ASC_FMT_HTML: - fprintf(fp, "\n"); - break; - default: - if (stl != ASC_STL_BLACKWHITE) fprintf(fp, "\033[0m"); - fprintf(fp, "\n"); - break; - } -} - -void __blk_putc_bw(int ndx, FILE *fp, asc_format_t fmt, bool final) -{ - switch (fmt) - { - case ASC_FMT_JSON: - fprintf(fp, final ? "\"%s\"" : "\"%s\", ", BLOCKS_ESC[ndx]); - break; - case ASC_FMT_HTML: - fprintf(fp, "%s", BLOCKS[ndx]); - break; - default: - fprintf(fp, "%s", BLOCKS[ndx]); - break; - } -} - -void __blk_putc_ansi(FILE *fp, asc_format_t fmt, bool final, int ct, int cb, palette_t pal) -{ - rgba8 top_rgb = pal.palette[ct], bot_rgb = pal.palette[cb]; - int top_int = top_rgb.r << 16 | top_rgb.g << 8 | top_rgb.b; - int bot_int = bot_rgb.r << 16 | bot_rgb.g << 8 | bot_rgb.b; - switch (fmt) - { - case ASC_FMT_JSON: - fprintf(fp, S_JSON_PBLK, BLOCKS_ESC[1], top_int, bot_int); - if (!final) fprintf(fp, ", "); - break; - case ASC_FMT_HTML: - fprintf(fp, S_HTML_PBLK, top_rgb.r, top_rgb.g, top_rgb.b, - bot_rgb.r, bot_rgb.g, bot_rgb.b, BLOCKS[1]); - break; - default: - fprintf(fp, S_ANSI_S, ct + (ct >= 8 ? 82 : 30), cb + (cb >= 8 ? 92 : 40), - BLOCKS[1]); - break; - } -} - -void __blk_putc_256(FILE *fp, asc_format_t fmt, bool final, int ct, int cb, palette_t pal) -{ - rgba8 top_rgb = pal256_to_rgb(pal, ct), bot_rgb = pal256_to_rgb(pal, cb); - int top_int = top_rgb.r << 16 | top_rgb.g << 8 | top_rgb.b; - int bot_int = bot_rgb.r << 16 | bot_rgb.g << 8 | bot_rgb.b; - switch (fmt) - { - case ASC_FMT_JSON: - fprintf(fp, "{ \"char\": \"%s\", \"fg\": %d, \"bg\": %d }", - BLOCKS_ESC[1], top_int, bot_int); - if (!final) fprintf(fp, ", "); - break; - case ASC_FMT_HTML: - fprintf(fp, "%s", - top_rgb.r, top_rgb.g, top_rgb.b, - bot_rgb.r, bot_rgb.g, bot_rgb.b, - BLOCKS[1]); - break; - default: - fprintf(fp, "\033[38;5;%d;48;5;%dm%s", ct, cb, BLOCKS[1]); - break; - } -} - -void __blk_putc_truecolor(FILE *fp, asc_format_t fmt, bool final, rgba8 top, rgba8 bot) -{ - int top_int = top.r << 16 | top.g << 8 | top.b; - int bot_int = bot.r << 16 | bot.g << 8 | bot.b; - switch (fmt) - { - case ASC_FMT_JSON: - fprintf(fp, "{ \"char\": \"%s\", \"fg\": %d, \"bg\": %d }", - BLOCKS_ESC[1], top_int, bot_int); - if (!final) fprintf(fp, ", "); - break; - case ASC_FMT_HTML: - fprintf(fp, "%s", - top.r, top.g, top.b, bot.r, bot.g, bot.b, BLOCKS[1]); - break; - default: - fprintf(fp, "\033[38;2;%d;%d;%d;48;2;%d;%d;%dm%s", - top.r, top.g, top.b, bot.r, bot.g, bot.b, BLOCKS[1]); - break; - } -} - -void __blk_put_pixel(asc_state_t state, rgba8 top, rgba8 bot, bool final) -{ - asc_format_t fmt = state.args.out_format; - FILE *fp = state.out_file; - switch (state.args.out_style) - { - case ASC_STL_BLACKWHITE: - { - bool bri_top = calc_brightness(top) > 0.5; - bool bri_bot = calc_brightness(bot) > 0.5; - if ( bri_top && bri_bot) __blk_putc_bw(3, fp, fmt, final); - if (!bri_top && bri_bot) __blk_putc_bw(2, fp, fmt, final); - if ( bri_top && !bri_bot) __blk_putc_bw(1, fp, fmt, final); - if (!bri_top && !bri_bot) __blk_putc_bw(0, fp, fmt, final); - } - break; - case ASC_STL_ANSI_VGA: - case ASC_STL_ANSI_XTERM: - case ASC_STL_ANSI_DISCORD: - { - palette_t *pal = get_palette_by_id(state.args.out_style); - int index_top = closest_color(*pal, top), - index_bot = closest_color(*pal, bot); - __blk_putc_ansi(fp, fmt, final, index_top, index_bot, *pal); - } - break; - case ASC_STL_256COLOR: - { - int index_top = closest_color(c_palette_256, top), - index_bot = closest_color(c_palette_256, bot); - __blk_putc_256(fp, fmt, final, index_top, index_bot, c_palette_ansi_vga); - } - break; - case ASC_STL_TRUECOLOR: - __blk_putc_truecolor(fp, fmt, final, top, bot); - break; - case ASC_STL_PALETTE: - { - palette_t *pal = state.palette; - __blk_putc_truecolor(fp, fmt, final, - clamp_to_pal(*pal, top), clamp_to_pal(*pal, bot)); - } - break; - case ASC_STL_ENDL: - break; - } -} - void mod_blocks_main(asc_state_t state) { image_t *img = state.image; @@ -219,14 +38,161 @@ void mod_blocks_main(asc_state_t state) for (int y = 0; y < img->height; y += 2) { bool final = y >= (img->height - 2); - __blk_start_line(state.out_file, state.args.out_format, final); + __blk_start_line(state, final); for (int x = 0; x < img->width; x++) { rgba8 top = img->pixels[x + y * img->width]; rgba8 bot = img->pixels[x + (y + 1) * img->width]; __blk_put_pixel(state, top, bot, x >= (img->width - 1)); } - __blk_end_line(state.out_file, state.args.out_format, state.args.out_style, final); + __blk_end_line(state, final); } __blk_end_output(state); } + +void __blk_start_output(asc_state_t state) +{ + if (state.args.out_format == ASC_FMT_JSON) + fprintf(state.out_file, S_JSON_HEAD, + state.image->width, state.image->height / 2); + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_HEAD); +} + +void __blk_end_output(asc_state_t state) +{ + if (state.args.out_format == ASC_FMT_JSON) + fprintf(state.out_file, S_JSON_TAIL); + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_TAIL); +} + +void __blk_start_line(asc_state_t state, bool final) +{ + (void)final; + if (state.args.out_format == ASC_FMT_JSON) + fprintf(state.out_file, S_JSON_LSTA); + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_LSTA); +} + +void __blk_end_line(asc_state_t state, bool final) +{ + if (state.args.out_format == ASC_FMT_JSON) + fprintf(state.out_file, final ? S_JSON_LEND_FINAL : S_JSON_LEND); + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_LEND); + else + { + if (state.args.out_style != ASC_STL_BLACKWHITE) + fprintf(state.out_file, S_ANSI_RST); + fprintf(state.out_file, "\n"); + } +} + +void __blk_putc_bw(asc_state_t state, int top, int bot, bool final) +{ + if (state.args.out_format == ASC_FMT_JSON) + { + fprintf(state.out_file, S_JSON_PBBW, BLKJ[top | (bot << 1)]); + if (!final) fprintf(state.out_file, ","); + fprintf(state.out_file, "\n"); + } + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_PBBW, BLK[top | (bot << 1)]); + else + fprintf(state.out_file, "%s", BLK[top | (bot << 1)]); +} + +void __blk_putc_ansi(asc_state_t state, int ct, int cb, bool final) +{ + rgba8 top = state.palette->palette[ct], bot = state.palette->palette[cb]; + if (state.args.out_format == ASC_FMT_JSON) + { + fprintf(state.out_file, S_JSON_PBLK, BLKJ[1], RGBN(top), RGBN(bot)); + if (!final) fprintf(state.out_file, ","); + fprintf(state.out_file, "\n"); + } + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_PBLK, top.r, top.g, top.b, + bot.r, bot.g, bot.b, BLK[1]); + else + fprintf(state.out_file, S_ANSI"%s", ct + (ct >= 8 ? 82 : 30), + cb + (cb >= 8 ? 92 : 40), BLK[1]); +} + +void __blk_putc_256(asc_state_t s, int ct, int cb, bool final) +{ + rgba8 top = pal256_to_rgb(*s.palette, ct), + bot = pal256_to_rgb(*s.palette, cb); + FILE *fp = s.out_file; + + if (s.args.out_format == ASC_FMT_JSON) + { + fprintf(fp, S_JSON_PBLK, BLKJ[1], RGBN(top), RGBN(bot)); + if (!final) fprintf(fp, ","); + fprintf(s.out_file, "\n"); + } + else if (s.args.out_format == ASC_FMT_HTML) + fprintf(fp, S_HTML_PBLK, top.r, top.g, top.b, bot.r, bot.g, bot.b, BLK[1]); + else + fprintf(fp, S_ANSI_256"%s", ct, cb, BLK[1]); +} + +void __blk_putc_true(asc_state_t state, rgba8 top, rgba8 bot, bool final) +{ + if (state.args.out_format == ASC_FMT_JSON) + { + fprintf(state.out_file, S_JSON_PBLK, BLKJ[1], RGBN(top), RGBN(bot)); + if (!final) fprintf(state.out_file, ","); + fprintf(state.out_file, "\n"); + } + else if (state.args.out_format == ASC_FMT_HTML) + fprintf(state.out_file, S_HTML_PBLK, top.r, top.g, top.b, + bot.r, bot.g, bot.b, BLK[1]); + else + fprintf(state.out_file, S_ANSI_RGB"%s", top.r, top.g, top.b, + bot.r, bot.g, bot.b, BLK[1]); +} + +void __blk_put_pixel(asc_state_t state, rgba8 top, rgba8 bot, bool final) +{ + switch (state.args.out_style) + { + case ASC_STL_BLACKWHITE: + { + bool btop = calc_brightness(top) > 0.5; + bool bbot = calc_brightness(bot) > 0.5; + __blk_putc_bw(state, btop, bbot, final); + } + break; + case ASC_STL_ANSI_VGA: + case ASC_STL_ANSI_XTERM: + case ASC_STL_ANSI_DISCORD: + { + palette_t pal = *state.palette; + int itop = closest_color(pal, top), ibot = closest_color(pal, bot); + __blk_putc_ansi(state, itop, ibot, final); + } + break; + case ASC_STL_256COLOR: + { + int itop = closest_color(c_palette_256, top), + ibot = closest_color(c_palette_256, bot); + __blk_putc_256(state, itop, ibot, final); + } + break; + case ASC_STL_PALETTE: + { + palette_t pal = *state.palette; + __blk_putc_true(state, clamp_to_pal(pal, top), + clamp_to_pal(pal, bot), final); + } + break; + case ASC_STL_TRUECOLOR: + __blk_putc_true(state, top, bot, final); + break; + case ASC_STL_ENDL: + break; + } +} diff --git a/src/mod_braille.c b/src/mod_braille.c index fac8f81..22e072f 100644 --- a/src/mod_braille.c +++ b/src/mod_braille.c @@ -11,7 +11,7 @@ void __bra_putc_esc(asc_state_t s, uint8_t ch); void __bra_start_output(asc_state_t s); void __bra_start_line(asc_state_t s, bool final); void __bra_put_pixel(asc_state_t s, rgba8 bg, rgba8 fg, uint8_t ch, bool final); -void __bra_putc_ansi(asc_state_t s, int bg, int fg, uint8_t ch, palette_t pal, bool final); +void __bra_putc_ansi(asc_state_t s, int bg, int fg, uint8_t ch, bool final); void __bra_putc_256(asc_state_t s, int bg, int fg, uint8_t ch, bool final); void __bra_putc_true(asc_state_t s, rgba8 bg, rgba8 fg, uint8_t ch, bool final); void __bra_end_line(asc_state_t s, bool final); @@ -87,7 +87,8 @@ void mod_braille_main(asc_state_t state) braille_char |= (1 << i); } } - __bra_put_pixel(state, color_min, color_max, braille_char, final); + __bra_put_pixel(state, color_min, color_max, + braille_char, x >= (img->width - 2)); } __bra_end_line(state, final); } @@ -140,7 +141,7 @@ void __bra_put_pixel(asc_state_t s, rgba8 min, rgba8 max, uint8_t ch, bool fin) { palette_t pal = *get_palette_by_id(s.args.out_style); __bra_putc_ansi(s, - closest_color(pal, min), closest_color(pal, max), ch, pal, fin); + closest_color(pal, min), closest_color(pal, max), ch, fin); } break; case ASC_STL_256COLOR: @@ -160,10 +161,9 @@ void __bra_put_pixel(asc_state_t s, rgba8 min, rgba8 max, uint8_t ch, bool fin) } } -void __bra_putc_ansi -(asc_state_t s, int bgi, int fgi, uint8_t ch, palette_t pal, bool fin) +void __bra_putc_ansi(asc_state_t s, int bgi, int fgi, uint8_t ch, bool fin) { - rgba8 bg = pal.palette[bgi], fg = pal.palette[fgi]; + rgba8 bg = s.palette->palette[bgi], fg = s.palette->palette[fgi]; FILE *fp = s.out_file; switch (s.args.out_format) {