From 20f4aac1aca7f8c3027bbd415abff98429476994 Mon Sep 17 00:00:00 2001 From: Maurizio De Santis Date: Sun, 10 Dec 2023 18:58:03 +0100 Subject: [PATCH 1/2] Ensure height stays positive during resizing --- src/load_image.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/load_image.cc b/src/load_image.cc index e913a9c..067f3f5 100644 --- a/src/load_image.cc +++ b/src/load_image.cc @@ -142,7 +142,8 @@ void maybe_resize(cimg_library::CImg& img, const LoadOpts& option } int new_width = options.desired_width; double ratio = ((double) img.height()) / img.width(); - int new_height = ratio * (double) new_width; + /* Scale height, ensuring it's at least 1px. */ + int new_height = std::max((int) (ratio * (double) new_width), 1); img.resize(new_width, new_height); } else if (resize_height) { /* Resize without affecting aspect ratio. */ From 735920c268743da860e078ac384590ce4df95049 Mon Sep 17 00:00:00 2001 From: Maurizio De Santis Date: Sun, 10 Dec 2023 19:02:41 +0100 Subject: [PATCH 2/2] Preserve aspect ratio when both dimensions are present --- docs/imgcat.1 | 9 ++++++--- docs/imgcat.1.md | 7 +++++-- src/imgcat.c | 24 ++++++++++++++++-------- src/load_image.cc | 23 +++++++++++++++++++++++ src/load_image.h | 1 + src/print_image.c | 1 + src/print_image.h | 1 + 7 files changed, 53 insertions(+), 13 deletions(-) diff --git a/docs/imgcat.1 b/docs/imgcat.1 index e444e7f..ff560c6 100644 --- a/docs/imgcat.1 +++ b/docs/imgcat.1 @@ -1,6 +1,6 @@ .\" Automatically generated by Pandoc 2.9.2.1 .\" -.TH "IMGCAT" "1" "October 31, 2023" "imgcat User Manual" "meow" +.TH "IMGCAT" "1" "December 10, 2023" "imgcat User Manual" "meow" .hy .SH NAME .PP @@ -26,8 +26,8 @@ This can be overridden using \f[B]-w\f[R] to adjust the maximum width or the terminal; and \f[B]-d\f[R] to explicitly set the color depth. You may also use \f[B]-r\f[R] to adjust the height (\[lq]r\[rq] for \[lq]number of rows\[rq]). -If only one of \f[B]-w\f[R] or \f[B]-r\f[R] is provided, the image will -be scaled without affecting the aspect ratio, if possible. +The image will be scaled without affecting the aspect ratio, unless +\f[B]-P\f[R] is provided. .PP Setting \f[B]-H\f[R] enables the use of half-height block drawing characters (as opposed to \[lq]full height\[rq] spaces used in the @@ -76,6 +76,9 @@ Does nothing if \f[B]\[en]no-resize\f[R] is provided. Maintains the original image\[cq]s aspect ratio if \f[B]\[en]width\f[R] is NOT provided. .TP +\f[B]-P\f[R], \f[B]\[en]no-preserve-aspect-ratio\f[R] +Does not preserve aspect ratio during image resizing. +.TP \f[B]-R\f[R], \f[B]\[en]no-resize\f[R] Does not resize the image to fit the terminal\[cq]s width. Overrides both \f[B]\[en]width\f[R] and \f[B]\[en]height\f[R]. diff --git a/docs/imgcat.1.md b/docs/imgcat.1.md index 807ad90..6c6a998 100644 --- a/docs/imgcat.1.md +++ b/docs/imgcat.1.md @@ -21,8 +21,8 @@ detected for your terminal. This can be overridden using **-w** to adjust the maximum width or **-R** to prevent resizing, even if the image is too big to fit in the terminal; and **-d** to explicitly set the color depth. You may also use **-r** to adjust the height ("r" for -"number of rows"). If only one of **-w** or **-r** is provided, the -image will be scaled without affecting the aspect ratio, if possible. +"number of rows"). The image will be scaled without affecting the aspect +ratio, unless **-P** is provided. Setting **-H** enables the use of half-height block drawing characters (as opposed to "full height" spaces used in the default mode). This @@ -69,6 +69,9 @@ you're having a problem with this. Does nothing if **--no-resize** is provided. Maintains the original image's aspect ratio if **--width** is NOT provided. +**-P**, **--no-preserve-aspect-ratio** + ~ Does not preserve aspect ratio during image resizing. + **-R**, **--no-resize** ~ Does not resize the image to fit the terminal's width. Overrides both **--width** and **--height**. diff --git a/src/imgcat.c b/src/imgcat.c index 26a73d7..f37b0df 100644 --- a/src/imgcat.c +++ b/src/imgcat.c @@ -64,6 +64,7 @@ static struct { int height; bool use_half_height; bool use_fake_terminal; + bool should_preserve_aspect_ratio; } options = { .format = F_UNSET, /* Default: autodetect highest fidelity. */ .should_resize = true, /* Default: yes! */ @@ -71,6 +72,7 @@ static struct { .height = HEIGHT_UNSET, .use_half_height = false, .use_fake_terminal = false, + .should_preserve_aspect_ratio = true }; /** @@ -96,13 +98,14 @@ static char tempfile_name_template[NAME_MAX + 1]; /* Long options */ static struct option long_options[] = { /* Options affecting output colour depth. */ - { "depth", required_argument, NULL, 'd' }, + { "depth", required_argument, NULL, 'd' }, /* Options affecting size. */ - { "no-resize", no_argument, NULL, 'R' }, - { "width", required_argument, NULL, 'w' }, - { "height", required_argument, NULL, 'r' }, - { "half-height", no_argument, NULL, 'H' }, + { "no-resize", no_argument, NULL, 'R' }, + { "width", required_argument, NULL, 'w' }, + { "height", required_argument, NULL, 'r' }, + { "half-height", no_argument, NULL, 'H' }, + { "no-preserve-aspect-ratio", no_argument, NULL, 'P' }, /* Abbreviated options. */ { "8", no_argument, (int*) &options.format, F_8_COLOR }, @@ -198,7 +201,8 @@ int main(int argc, char **argv) { .max_width = terminal->width, .max_height = terminal->height, .half_height = options.use_half_height, - .format = color_format + .format = color_format, + .preserve_aspect_ratio = options.should_preserve_aspect_ratio }; status = print_image(&request); @@ -324,7 +328,7 @@ static void usage(FILE *dest) { const int field_width = strlen(program_name); fprintf(dest, "Usage:\n"); fprintf(dest, - "\t%s" " [--width= --height=|--no-resize]\n" + "\t%s" " [--width= --height=|--no-resize] [--no-preserve-aspect-ratio]\n" "\t%*c" " [--half-height] [--depth=(8|256|24bit|iterm2)] IMAGE\n", program_name, field_width, ' '); fprintf(dest, "\t" @@ -385,7 +389,7 @@ static const char* parse_args(int argc, char **argv) { opterr = 0; while (1) { - c = getopt_long(argc, argv, "w:r:d:RHhv", long_options, NULL); + c = getopt_long(argc, argv, "w:r:d:PRHhv", long_options, NULL); if (c == -1) { break; } @@ -414,6 +418,10 @@ static const char* parse_args(int argc, char **argv) { } break; + case 'P': /* --no-preserve-aspect-ratio */ + options.should_preserve_aspect_ratio = false; + break; + case 'R': /* --no-resize */ options.should_resize = false; break; diff --git a/src/load_image.cc b/src/load_image.cc index 067f3f5..bf53575 100644 --- a/src/load_image.cc +++ b/src/load_image.cc @@ -134,6 +134,29 @@ void maybe_resize(cimg_library::CImg& img, const LoadOpts& option /* Make sure the image is never smaller than 1x1 pixels. */ int new_width = std::max(options.desired_width, 1); int new_height = std::max(options.desired_height, 1); + + /* Resize preserving aspect ratio. */ + if (options.preserve_aspect_ratio) { + int max_width = new_width; + int max_height = new_height; + new_width = img.width(); + new_height = img.height(); + + if (new_width > max_width) { + new_width = max_width; + double ratio = ((double) img.height()) / img.width(); + /* Scale height, ensuring it's at least 1px. */ + new_height = std::max((int) (ratio * (double) new_width), 1); + } + + if (new_height > max_height) { + new_height = max_height; + double ratio = ((double) img.width()) / img.height(); + /* Scale width, ensuring it's at least 1px. */ + new_width = std::max((int) (ratio * (double) new_height), 1); + } + } + img.resize(new_width, new_height); } else if (resize_width) { /* Only resize if the image is strictly greater than the source width. */ diff --git a/src/load_image.h b/src/load_image.h index 23601be..a563f26 100644 --- a/src/load_image.h +++ b/src/load_image.h @@ -55,6 +55,7 @@ struct LoadOpts { int max_height; int desired_width; int desired_height; + bool preserve_aspect_ratio; }; /** diff --git a/src/print_image.c b/src/print_image.c index 49164b0..a442c86 100644 --- a/src/print_image.c +++ b/src/print_image.c @@ -88,6 +88,7 @@ static bool print_iterate(PrintRequest *request) { .max_height = request->max_height, .desired_width = request->desired_width, .desired_height = request->desired_height, + .preserve_aspect_ratio = request->preserve_aspect_ratio, }; assert(format != F_UNSET); diff --git a/src/print_image.h b/src/print_image.h index 57205af..bb42ad2 100644 --- a/src/print_image.h +++ b/src/print_image.h @@ -44,6 +44,7 @@ typedef struct { int desired_width; int desired_height; bool half_height; + bool preserve_aspect_ratio; Format format; } PrintRequest;