diff --git a/Makefile b/Makefile index 8b58fdb..294fbd7 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99 -ggdb CLIBS := -lm INCLUDES := -Isrc OBJECTS := obj/stb_image.o obj/stb_image_resize.o \ - obj/colors.o obj/args.o obj/image.o \ + obj/colors.o obj/args.o obj/image.o obj/commons.o \ obj/mod_blocks.o all: lib asciify diff --git a/src/args.c b/src/args.c index be6309b..0767b45 100644 --- a/src/args.c +++ b/src/args.c @@ -1,4 +1,5 @@ #include "args.h" +#include "colors.h" #include #include #include @@ -242,6 +243,9 @@ int prepare_state(int argc, char **argv, asc_args_t args, asc_state_t *state) fclose(fp); } + if (args.out_style == ASC_STL_256COLOR) + make_pal256(&c_palette_256, c_palette_ansi_vga); + state->out_file = stdout; if (strcmp(args.output_filename, "-")) state->out_file = fopen(args.output_filename, "wb"); diff --git a/src/colors.c b/src/colors.c index 0c44a59..c5caf71 100644 --- a/src/colors.c +++ b/src/colors.c @@ -11,6 +11,10 @@ palette_t c_palette_bw = { } }; +palette_t c_palette_256 = { + .n_colors = 0 +}; + palette_t c_palette_ansi_discord = { .n_colors = 8, .palette = { @@ -89,30 +93,11 @@ int closest_color(palette_t pal, rgba8 color) return nearest; } -int closest_256(palette_t pal, rgba8 color) -{ - (void)pal; - if (color.r == color.g && color.g == color.b) - { - if (color.r < 8) return 16; - if (color.r > 248) return 231; - return 232 + (int)ceil((color.r - 8.0) / 247.0 * 24.0); - } - int oc = 16; - oc += 36 * (int)ceil(color.r / 255.0 * 5.0); - oc += 6 * (int)ceil(color.g / 255.0 * 5.0); - oc += (int)ceil(color.b / 255.0 * 5.0); - return oc; -} - rgba8 pal256_to_rgb(palette_t pal, int ndx) { + (void)pal; rgba8 out = { 0, 0, 0, 255 }; - if (ndx < 16) - { - return pal.palette[ndx]; - } - else if (ndx >= 232) + if (ndx >= 232) { int l = (ndx - 232) * 255 / 24; out.r = out.g = out.b = l; @@ -129,6 +114,17 @@ rgba8 pal256_to_rgb(palette_t pal, int ndx) return out; } +void make_pal256(palette_t *dst, palette_t ansi) +{ + if (dst->n_colors == 256) return; + dst->n_colors = 256; + for (int i = 0; i < 256; i++) + { + rgba8 res = pal256_to_rgb(ansi, i); + memcpy(&dst->palette[i], &res, sizeof(rgba8)); + } +} + float calc_brightness(rgba8 c) { return 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b; diff --git a/src/colors.h b/src/colors.h index c6968b0..0cdca34 100644 --- a/src/colors.h +++ b/src/colors.h @@ -14,13 +14,14 @@ typedef struct { } palette_t; extern palette_t c_palette_bw; +extern palette_t c_palette_256; extern palette_t c_palette_ansi_discord; extern palette_t c_palette_ansi_vga; extern palette_t c_palette_ansi_xterm; int closest_color(palette_t pal, rgba8 color); -int closest_256(palette_t pal, rgba8 color); rgba8 pal256_to_rgb(palette_t pal, int ndx); +void make_pal256(palette_t *dst, palette_t ansi); bool load_palette_gpl(palette_t *pal, FILE *fp); bool load_palette_raw(palette_t *pal, FILE *fp); bool load_palette(palette_t *pal, FILE *fp); diff --git a/src/commons.c b/src/commons.c new file mode 100644 index 0000000..7cda1d6 --- /dev/null +++ b/src/commons.c @@ -0,0 +1,39 @@ +#include "colors.h" +#include "commons.h" + +void m_prepare_dither(asc_state_t *state) +{ + if (state->args.dither) + { + image_t *res = NULL; + switch (state->args.out_style) + { + case ASC_STL_BLACKWHITE: + res = image_dither(state->image, c_palette_bw); + break; + case ASC_STL_ANSI_VGA: + res = image_dither(state->image, c_palette_ansi_vga); + break; + case ASC_STL_ANSI_XTERM: + res = image_dither(state->image, c_palette_ansi_xterm); + break; + case ASC_STL_ANSI_DISCORD: + res = image_dither(state->image, c_palette_ansi_discord); + break; + case ASC_STL_256COLOR: + res = image_dither(state->image, c_palette_256); + break; + case ASC_STL_PALETTE: + res = image_dither(state->image, *state->palette); + break; + case ASC_STL_TRUECOLOR: + case ASC_STL_ENDL: + break; + } + if (res != NULL) + { + image_unload(state->image); + state->image = res; + } + } +} diff --git a/src/commons.h b/src/commons.h new file mode 100644 index 0000000..a1f9d78 --- /dev/null +++ b/src/commons.h @@ -0,0 +1,8 @@ +#ifndef _COMMONS_H_ +#define _COMMONS_H_ + +#include "args.h" + +void m_prepare_dither(asc_state_t *state); + +#endif diff --git a/src/image.h b/src/image.h index a11111c..75d5d39 100644 --- a/src/image.h +++ b/src/image.h @@ -12,7 +12,6 @@ typedef struct { typedef rgba8 (*dither_quantizer_t)(rgba8 clr, void *param); - image_t *image_load(FILE *file); image_t *image_resize(image_t *img, int width, int height); image_t *image_dither(image_t *img, palette_t palette); diff --git a/src/mod_blocks.c b/src/mod_blocks.c index 0181751..2eda702 100644 --- a/src/mod_blocks.c +++ b/src/mod_blocks.c @@ -2,18 +2,12 @@ #include "mod_blocks.h" #include "image.h" #include "colors.h" +#include "commons.h" const char *BLOCKS[4] = { " ", "\xe2\x96\x80", "\xe2\x96\x84", "\xe2\x96\x88" }; const char *BLOCKS_ESC[4] = { " ", "\\u2580", "\\u2584", "\\u2588" }; -rgba8 __to_256(rgba8 c, void *p) -{ - (void)p; - return pal256_to_rgb(c_palette_ansi_vga, closest_256(c_palette_ansi_vga, c)); -} - - void mod_blocks_prepare(asc_state_t *state) { int w, h; @@ -21,49 +15,8 @@ void mod_blocks_prepare(asc_state_t *state) state->source_image->width, state->source_image->height, state->args.width, state->args.height * 2, &w, &h); h = (h / 2) * 2; - if (state->args.verbose) - { - fprintf(stderr, "src: %dx%d\n", - state->source_image->width, - state->source_image->height); - fprintf(stderr, "tgt: %dx%d\n", state->args.width, state->args.height * 2); - fprintf(stderr, "dst: %dx%d\n", w, h); - } state->image = image_resize(state->source_image, w, h); - // TODO: dither - if (state->args.dither) - { - image_t *res = NULL; - switch (state->args.out_style) - { - case ASC_STL_BLACKWHITE: - res = image_dither(state->image, c_palette_bw); - break; - case ASC_STL_ANSI_VGA: - res = image_dither(state->image, c_palette_ansi_vga); - break; - case ASC_STL_ANSI_XTERM: - res = image_dither(state->image, c_palette_ansi_xterm); - break; - case ASC_STL_ANSI_DISCORD: - res = image_dither(state->image, c_palette_ansi_discord); - break; - case ASC_STL_256COLOR: - res = image_dither_fn(state->image, __to_256, NULL); - break; - case ASC_STL_PALETTE: - res = image_dither(state->image, *state->palette); - break; - case ASC_STL_TRUECOLOR: - case ASC_STL_ENDL: - break; - } - if (res != NULL) - { - image_unload(state->image); - state->image = res; - } - } + m_prepare_dither(state); } void __start_output(asc_state_t state) @@ -254,8 +207,8 @@ void __put_pixel(asc_state_t state, rgba8 top, rgba8 bot, bool final) break; case ASC_STL_256COLOR: { - int index_top = closest_256(c_palette_ansi_vga, top), - index_bot = closest_256(c_palette_ansi_vga, bot); + int index_top = closest_color(c_palette_256, top), + index_bot = closest_color(c_palette_256, bot); __putc_256(fp, fmt, final, index_top, index_bot, c_palette_ansi_vga); } break;