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 ab4ae60ad89cba4cca0d2f9b802628358fefaf0a
parent b89bcf2956326f4ff6f11e2f105f8301b8adc3ba
Author: lumidify <nobody@lumidify.org>
Date:   Tue, 21 Sep 2021 14:47:41 +0200

Don't allow coordinates below 0; allow rectangle to be kept when going backwards

Diffstat:
MCHANGELOG | 1+
MLICENSE | 2+-
MTODO | 2++
Mcroptool.1 | 5++++-
Mcroptool.c | 48+++++++++++++++++++++++++++++++++---------------
Mcroptool_crop.c | 2+-
6 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG @@ -2,6 +2,7 @@ * Rewrite using Xlib and Imlib2 * Add command-line options and man pages * Add automatic resizing of image when resizing window +* Allow the rectangle to be kept when going backwards (Shift + Return) * Add croptool_crop 1.0 -> 1.1 diff --git a/LICENSE b/LICENSE @@ -1,6 +1,6 @@ Copyright (c) 2021 lumidify <nobody@lumidify.org> -Permission to use, copy, modify, and distribute this software for any +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/TODO b/TODO @@ -1,3 +1,5 @@ * Proper path handling (allow paths including "'", etc.) * Draw pixmap on exposure events instead of doing the expensive image resizing each time +* Maybe add zooming support +* Maybe optionally show rectangle coordinates on screen diff --git a/croptool.1 b/croptool.1 @@ -1,4 +1,4 @@ -.Dd April 1, 2021 +.Dd September 21, 2021 .Dt CROPTOOL 1 .Os .Sh NAME @@ -94,6 +94,9 @@ that is printed for the cropping command. In other words, when switching to an image that is a different size and thus scaled differently, the displayed rectangle will stay the same even though the pixels covered in the original image are different. +.It SHIFT + RETURN +Go to the last image, copying the current cropping rectangle. +The same caveat as above applies. .It TAB Switch the color of the cropping rectangle between the primary and secondary colors. .It DELETE diff --git a/croptool.c b/croptool.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2021 lumidify <nobody@lumidify.org> * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * @@ -144,8 +144,8 @@ static int collide_line(int x, int y, int x0, int y0, int x1, int y1); static int collide_rect(int x, int y, struct Rect rect); static void switch_color(void); static void clear_selection(void); -static void last_picture(void); static void next_picture(int copy_box); +static void last_picture(int copy_box); static void change_picture(Imlib_Image new_image, int new_selection, int copy_box); static void get_scaled_size(int orig_w, int orig_h, int *scaled_w, int *scaled_h); static void set_selection( @@ -860,9 +860,19 @@ static void drag_motion(XEvent event) { if (state.cur_selection < 0 || !state.selections[state.cur_selection].valid) return; - struct Rect *rect = &state.selections[state.cur_selection].rect; - state.cursor_x = event.xbutton.x; - state.cursor_y = event.xbutton.y; + struct Selection *sel = &state.selections[state.cur_selection]; + struct Rect *rect = &sel->rect; + + /* don't allow coordinates to go below 0 */ + if (event.xbutton.x >= 0) + state.cursor_x = event.xbutton.x; + else + state.cursor_x = 0; + if (event.xbutton.y >= 0) + state.cursor_y = event.xbutton.y; + else + state.cursor_y = 0; + int x0 = rect->x0, x1 = rect->x1; int y0 = rect->y0, y1 = rect->y1; sort_coordinates(&x0, &y0, &x1, &y1); @@ -872,10 +882,13 @@ drag_motion(XEvent event) { if (state.moving) { int x_delta = state.cursor_x - state.move_handle.x; int y_delta = state.cursor_y - state.move_handle.y; - rect->x0 += x_delta; - rect->y0 += y_delta; - rect->x1 += x_delta; - rect->y1 += y_delta; + /* don't allow coordinates to go below 0 */ + int x_realdelta = x0 + x_delta >= 0 ? x_delta : -x0; + int y_realdelta = y0 + y_delta >= 0 ? y_delta : -y0; + rect->x0 += x_realdelta; + rect->x1 += x_realdelta; + rect->y0 += y_realdelta; + rect->y1 += y_realdelta; state.move_handle.x = state.cursor_x; state.move_handle.y = state.cursor_y; } else if (state.resizing) { @@ -1011,6 +1024,7 @@ next_picture(int copy_box) { state.filenames[tmp_cur_selection] = NULL; } } + /* immediately exit program if no loadable image is found on startup */ if (state.cur_selection < 0 && !tmp_image) { fprintf(stderr, "No loadable images found.\n"); cleanup(); @@ -1022,9 +1036,10 @@ next_picture(int copy_box) { change_picture(tmp_image, tmp_cur_selection, copy_box); } -/* show the previous image in the argument list - unloadable files are skipped */ +/* show the previous image in the argument list - unloadable files are skipped + * copy_box determines whether the current selection is copied */ static void -last_picture(void) { +last_picture(int copy_box) { if (state.cur_selection <= 0) return; Imlib_Image tmp_image = NULL; @@ -1047,7 +1062,7 @@ last_picture(void) { if (!tmp_image) return; - change_picture(tmp_image, tmp_cur_selection, 0); + change_picture(tmp_image, tmp_cur_selection, copy_box); } static void @@ -1075,13 +1090,16 @@ key_press(XEvent event) { XLookupString(&event.xkey, buf, sizeof(buf), &sym, NULL); switch (sym) { case XK_Left: - last_picture(); + last_picture(0); break; case XK_Right: next_picture(0); break; case XK_Return: - next_picture(1); + if (event.xkey.state & ShiftMask) + last_picture(1); + else + next_picture(1); break; case XK_Delete: clear_selection(); @@ -1092,7 +1110,7 @@ key_press(XEvent event) { case XK_space: XGetWindowAttributes(state.dpy, state.win, &attrs); resize_window(attrs.width, attrs.height); - /* queue update separately to it also redraws when + /* queue update separately so it also redraws when size didn't change */ queue_update(0, 0, state.window_w, state.window_h); break; diff --git a/croptool_crop.c b/croptool_crop.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2021 lumidify <nobody@lumidify.org> * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. *