Added verbosity and a progress bar
This commit is contained in:
parent
743435200d
commit
c3b5d1a198
74
img2cpi.c
74
img2cpi.c
|
@ -19,6 +19,10 @@
|
|||
|
||||
#define MAX_COLOR_DIFFERENCE 768
|
||||
#define K_MEANS_ITERATIONS 4
|
||||
#define PROGRESS_BAR_WIDTH 24
|
||||
|
||||
#define TOSTRNAME(M) #M
|
||||
#define TOSTR(M) TOSTRNAME(M)
|
||||
|
||||
struct cc_char {
|
||||
unsigned char character;
|
||||
|
@ -27,6 +31,7 @@ struct cc_char {
|
|||
|
||||
struct arguments {
|
||||
bool fast_mode;
|
||||
bool verbose;
|
||||
int width, height;
|
||||
enum cpi_version {
|
||||
CPI_VERSION_AUTO,
|
||||
|
@ -55,6 +60,7 @@ struct arguments {
|
|||
char *output_path;
|
||||
} args = {
|
||||
.fast_mode = false,
|
||||
.verbose = false,
|
||||
.width = 4 * 8 - 1, // 4x3 blocks screen
|
||||
.height = 3 * 6 - 2,
|
||||
.cpi_version = CPI_VERSION_AUTO,
|
||||
|
@ -62,8 +68,7 @@ struct arguments {
|
|||
.input_path = NULL,
|
||||
.output_path = NULL,
|
||||
.palette = NULL,
|
||||
.palette_type = PALETTE_DEFAULT // TODO(kc): change to PALETTE_AUTO when
|
||||
// k-means is implemented
|
||||
.palette_type = PALETTE_AUTO
|
||||
};
|
||||
|
||||
struct image {
|
||||
|
@ -135,6 +140,7 @@ static const struct optiondocs {
|
|||
} optiondocs[] = {
|
||||
{ 'h', "help", 0, "Show help", 0 },
|
||||
{ 'f', "fast", 0, "Use fast (old) method for picking characters and colors", 0 },
|
||||
{ 'v', "verbose", 0, "Increase verbosity", 0 },
|
||||
{ 'W', "width", "width", "Width in characters", 0 },
|
||||
{ 'h', "height", "height", "Height in characters", 0 },
|
||||
{ 'P', "palette", "palette", "Use specific palette.\n"
|
||||
|
@ -165,6 +171,8 @@ static const struct optiondocs {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
static char progress_bar[PROGRESS_BAR_WIDTH];
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (!parse_cmdline(argc, argv)) {
|
||||
show_help(argv[0], false, stderr);
|
||||
|
@ -177,6 +185,11 @@ int main(int argc, char **argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (args.verbose) {
|
||||
memset(progress_bar, '#', PROGRESS_BAR_WIDTH);
|
||||
printf("Input image: %dx%d\n", src_image->w, src_image->h);
|
||||
}
|
||||
|
||||
struct image *canvas;
|
||||
if (args.fast_mode) {
|
||||
canvas = image_new(args.width * 2, args.height * 3);
|
||||
|
@ -189,14 +202,18 @@ int main(int argc, char **argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (args.verbose) {
|
||||
printf("Output image canvas: %dx%d\n", canvas->w, canvas->h);
|
||||
}
|
||||
|
||||
// TODO: load palette, maybe calculate it too? k-means?
|
||||
const struct palette *palette = &cc_default_palette;
|
||||
switch (args.palette_type) {
|
||||
case PALETTE_DEFAULT: palette = &cc_default_palette; break;
|
||||
case PALETTE_DEFAULT_GRAY: palette = &cc_default_gray_palette; break;
|
||||
case PALETTE_AUTO: palette = palette_k_means(src_image, &cc_default_palette); break;
|
||||
case PALETTE_LIST: assert(0 && "Not implemented"); break;
|
||||
case PALETTE_PATH: assert(0 && "Not implemented"); break;
|
||||
case PALETTE_LIST: assert(0 && "Not implemented"); break; // TODO
|
||||
case PALETTE_PATH: assert(0 && "Not implemented"); break; // TODO
|
||||
default: assert(0 && "Unreachable");
|
||||
}
|
||||
|
||||
|
@ -206,6 +223,10 @@ int main(int argc, char **argv) {
|
|||
int new_w, new_h;
|
||||
get_size_keep_aspect(src_image->w, src_image->h, canvas->w, canvas->h, &new_w, &new_h);
|
||||
|
||||
if (args.verbose) {
|
||||
printf("Scaling down to: %dx%d\n", new_w, new_h);
|
||||
}
|
||||
|
||||
scaled_image = image_resize(src_image, new_w, new_h);
|
||||
if (!scaled_image) {
|
||||
fprintf(stderr, "Error: failed to open the file\n");
|
||||
|
@ -231,16 +252,32 @@ int main(int argc, char **argv) {
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (args.verbose) {
|
||||
printf("Converting image ");
|
||||
}
|
||||
|
||||
if (args.fast_mode) {
|
||||
if (args.verbose) {
|
||||
printf(" using fast method\n");
|
||||
}
|
||||
convert_2x3(quantized_image, characters);
|
||||
} else {
|
||||
if (args.verbose) {
|
||||
printf(" using slow method\n");
|
||||
}
|
||||
convert_6x9(quantized_image, characters);
|
||||
}
|
||||
|
||||
if (args.verbose) {
|
||||
printf("Conversion done, saving image ");
|
||||
}
|
||||
|
||||
FILE *fp = fopen(args.output_path, "wb");
|
||||
if (args.width < 256) {
|
||||
if (args.width < 256 && args.height < 256) {
|
||||
printf(" using cpiv0\n");
|
||||
save_cpi_0(fp, palette, characters, args.width, args.height);
|
||||
} else {
|
||||
printf(" using cpiv1\n");
|
||||
save_cpi_1(fp, palette, characters, args.width, args.height);
|
||||
}
|
||||
fclose(fp);
|
||||
|
@ -305,7 +342,7 @@ bool parse_cmdline(int argc, char **argv) {
|
|||
|
||||
while (true) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "hfW:H:V:p:P:", options, &option_index);
|
||||
int c = getopt_long(argc, argv, "hvfW:H:V:p:P:", options, &option_index);
|
||||
if (c == -1) break;
|
||||
if (c == 0) c = options[option_index].val;
|
||||
if (c == '?') break;
|
||||
|
@ -321,6 +358,9 @@ bool parse_cmdline(int argc, char **argv) {
|
|||
fprintf(stderr, "Warning: text mode ignores version\n");
|
||||
}
|
||||
break;
|
||||
case 'v': // --verbose
|
||||
args.verbose = true;
|
||||
break;
|
||||
case 'W': // --width
|
||||
args.width = atoi(optarg);
|
||||
break;
|
||||
|
@ -582,6 +622,14 @@ float get_color_brightness(union color clr) {
|
|||
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++) {
|
||||
if (args.verbose) {
|
||||
int sz = PROGRESS_BAR_WIDTH - (y * PROGRESS_BAR_WIDTH / h);
|
||||
printf("\r[%-" TOSTR(PROGRESS_BAR_WIDTH) ".*s|%7.3f%%|%4d/%4d]",
|
||||
PROGRESS_BAR_WIDTH - sz, progress_bar + sz,
|
||||
100.0 * (y + 1) / h,
|
||||
y + 1, h);
|
||||
fflush(stdout);
|
||||
}
|
||||
for (int x = 0; x < w; x++) {
|
||||
unsigned char darkest_i = 0, brightest_i = 0;
|
||||
float darkest_diff = 0xffffff, brightest_diff = 0;
|
||||
|
@ -632,6 +680,9 @@ void convert_2x3(const struct image_pal *img, struct cc_char *characters) {
|
|||
characters[x + y * w].fg = brightest_i;
|
||||
}
|
||||
}
|
||||
if (args.verbose) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void convert_6x9(const struct image_pal *img, struct cc_char *characters) {
|
||||
|
@ -644,6 +695,14 @@ void convert_6x9(const struct image_pal *img, struct cc_char *characters) {
|
|||
}
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
if (args.verbose) {
|
||||
int sz = PROGRESS_BAR_WIDTH - (y * PROGRESS_BAR_WIDTH / h);
|
||||
printf("\r[%-" TOSTR(PROGRESS_BAR_WIDTH) ".*s|%7.3f%%|%4d/%4d]",
|
||||
PROGRESS_BAR_WIDTH - sz, progress_bar + sz,
|
||||
100.0 * (y + 1) / h,
|
||||
y + 1, h);
|
||||
fflush(stdout);
|
||||
}
|
||||
#ifdef USE_OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
@ -687,6 +746,9 @@ void convert_6x9(const struct image_pal *img, struct cc_char *characters) {
|
|||
characters[x + y * w].fg = closest_color >> 4;
|
||||
}
|
||||
}
|
||||
if (args.verbose) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct {
|
||||
|
|
Loading…
Reference in New Issue