croptool

Image cropping tool
git clone git://lumidify.org/croptool.git (fast, but not encrypted)
git clone https://lumidify.org/git/croptool.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 6ac1850fa404420f18bcea62c5cefcfd7d575a1a
parent ab4ae60ad89cba4cca0d2f9b802628358fefaf0a
Author: lumidify <nobody@lumidify.org>
Date:   Tue, 21 Sep 2021 15:45:59 +0200

Allow Imlib2 cache size to be controlled with command line argument

Diffstat:
Mcroptool.1 | 5+++++
Mcroptool.c | 35++++++++++++++++++++++++++---------
2 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/croptool.1 b/croptool.1 @@ -51,6 +51,11 @@ Default: #000000. .It Fl s Ar color Set the secondary color for the cropping rectangle. Default: #FFFFFF. +.It Fl z Ar size +Set the Imlib2 in-memory cache to +.Ar size +MiB (valid values: 0-1024). +Default: 4. .El .Sh OUTPUT FORMAT The cropping commands for each image are output using the format given by diff --git a/croptool.c b/croptool.c @@ -57,6 +57,8 @@ static short SELECTION_REDRAW = 1; %f: Filename of image. */ static const char *CMD_FORMAT = "croptool_crop %wx%h+%l+%t '%f'"; +/* Size of Imlib2 in-memory cache in MiB */ +static int CACHE_SIZE = 4; extern char *optarg; extern int optind; @@ -159,7 +161,7 @@ static void button_release(void); static void button_press(XEvent event); static void key_press(XEvent event); static void queue_update(int x, int y, int w, int h); -static int parse_small_positive_int(const char *str, int *value); +static int parse_int(const char *str, int min, int max, int *value); static void usage(void) { @@ -172,7 +174,7 @@ int main(int argc, char *argv[]) { char c; - while ((c = getopt(argc, argv, "f:w:c:mrp:s:")) != -1) { + while ((c = getopt(argc, argv, "f:w:c:mrp:s:z:")) != -1) { switch (c) { case 'f': CMD_FORMAT = optarg; @@ -190,17 +192,23 @@ main(int argc, char *argv[]) { SELECTION_COLOR2 = optarg; break; case 'c': - if (parse_small_positive_int(optarg, &COLLISION_PADDING)) { + if (parse_int(optarg, 1, 99, &COLLISION_PADDING)) { fprintf(stderr, "Invalid collision padding.\n"); exit(1); } break; case 'w': - if (parse_small_positive_int(optarg, &LINE_WIDTH)) { + if (parse_int(optarg, 1, 99, &LINE_WIDTH)) { fprintf(stderr, "Invalid line width.\n"); exit(1); } break; + case 'z': + if (parse_int(optarg, 0, 1024, &CACHE_SIZE)) { + fprintf(stderr, "Invalid cache size.\n"); + exit(1); + } + break; default: usage(); exit(1); @@ -410,7 +418,13 @@ setup(int argc, char *argv[]) { cursors.bottomright = XCreateFontCursor(state.dpy, XC_bottom_right_corner); cursors.grab = XCreateFontCursor(state.dpy, XC_fleur); - imlib_set_cache_size(2048 * 2048); + /* note: since CACHE_SIZE is <= 1024, this definitely fits in long */ + long cs = (unsigned long long)CACHE_SIZE * 1024 * 1024; + if (cs > INT_MAX) { + fprintf(stderr, "Cache size would cause integer overflow.\n"); + exit(1); + } + imlib_set_cache_size((int)cs); imlib_set_color_usage(128); imlib_context_set_dither(1); imlib_context_set_display(state.dpy); @@ -511,16 +525,19 @@ print_cmd(const char *filename, int x, int y, int w, int h, int dry_run) { } } -/* Parses integer between 0 and 100 (non-inclusive). +/* Parse integer between min and max (inclusive). Returns 1 on error, 0 otherwise. - The result is stored in *value. */ + The result is stored in *value. + Based on OpenBSD's strtonum. */ static int -parse_small_positive_int(const char *str, int *value) { +parse_int(const char *str, int min, int max, int *value) { char *end; long l = strtol(str, &end, 10); + if (min > max) + return 1; if (str == end || *end != '\0') { return 1; - } else if (l <= 0 || l >= 100 || ((l == LONG_MIN || + } else if (l < min || l > max || ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE)) { return 1; }