From: Colin Clark Date: Mon, 12 Jun 2017 18:15:29 +0000 (+0100) Subject: Fix #264, 274, 285, 436: Add 'Losslessly rotate image' keyboard shortcuts X-Git-Tag: v1.4~159 X-Git-Url: http://geeqie.org/cgi-bin/gitweb.cgi?p=geeqie.git;a=commitdiff_plain;h=9313974a67d3e0f2e78757d5ca979bb9de41aa03 Fix #264, 274, 285, 436: Add 'Losslessly rotate image' keyboard shortcuts https://github.com/BestImageViewer/geeqie/issues/264 https://github.com/BestImageViewer/geeqie/issues/274 https://github.com/BestImageViewer/geeqie/issues/285 https://github.com/BestImageViewer/geeqie/issues/436 Additional entries on Edit/Orientation menu: Write orientation to file Write orientation to file (preserve timestamp) Preferences/Metadata option "Write altered image orientation to the metadata" must be off. Exiftran and mogrify must be installed. --- diff --git a/doc/docbook/GuideMainWindowMenus.xml b/doc/docbook/GuideMainWindowMenus.xml index 754c5bdf..edfec796 100644 --- a/doc/docbook/GuideMainWindowMenus.xml +++ b/doc/docbook/GuideMainWindowMenus.xml @@ -739,6 +739,35 @@ Rotates the current image 180 degrees, does not modify the file on disk. + + + + Orientation + Write orientation to file + + + + + Saves the current image orientation to the disk file. This operation can only be carried out on jpeg, tiff and png files. Jpeg rotations are lossless. + + The Preferences/Metadata option "Write altered image orientation to the metadata" must be off. + + Exiftran and mogrify must be installed. + + + + + + + + Orientation + Write orientation to file (preserve timestamp) + + + + As above, but the file date and time are preserved. + + diff --git a/plugins/rotate/geeqie-rotate b/plugins/rotate/geeqie-rotate index 1c1184e0..ec82cc0c 100755 --- a/plugins/rotate/geeqie-rotate +++ b/plugins/rotate/geeqie-rotate @@ -47,12 +47,83 @@ rotate() esac } +rotate_image_file() +{ + ext=`echo "${3##*.}" |tr "[:upper:]" "[:lower:]"` + [ "x$ext" = "x" ] && return 4 #no extension + + case "$ext" in + jpg|jpeg) + exiftran -i "$1" "$3" + return 0 + ;; + + tif|tiff|png) + mogrify $2 "$3" + return 0 + ;; + + *) #not supported + return 4 + ;; + esac +} + get_sidecars= if [ "x$1" = "x-g" ] ; then get_sidecars=yes shift fi +rotate_image_file= +rotation= +if [ "x$1" = "x-r" ] ; then + rotate_image_file=yes + shift + rotation="$1" + shift +fi + +preserve_mtime= +if [ "x$1" = "x-t" ] ; then + preserve_mtime=yes + shift +fi + +if [ -n "$rotation" ] ; then + if [ "x$rotation" = "x0" ] ; then + exit 0 + fi + if [ "x$rotation" = "x2" ] ; then + mogrify_param="-flop" + exiftran_param="-F" + fi + if [ "x$rotation" = "x3" ] ; then + mogrify_param="-rotate 180" + exiftran_param="-1" + fi + if [ "x$rotation" = "x4" ] ; then + mogrify_param="-flip" + exiftran_param="-f" + fi + if [ "x$rotation" = "x5" ] ; then + mogrify_param="-transpose" + exiftran_param="-t" + fi + if [ "x$rotation" = "x6" ] ; then + mogrify_param="-rotate 90" + exiftran_param="-9" + fi + if [ "x$rotation" = "x7" ] ; then + mogrify_param="-transverse" + exiftran_param="-T" + fi + if [ "x$rotation" = "x8" ] ; then + mogrify_param="-rotate -90" + exiftran_param="-2" + fi +fi + # iterate over files on commandline for file in "$@" ; do if [ -n "$get_sidecars" ] ; then @@ -63,7 +134,25 @@ for file in "$@" ; do rotate "$sidecar" done else - rotate "$file" + if [ -n "$rotate_image_file" ] ; then + if [ -n "$preserve_mtime" ] ; then + mtime=`mktemp /tmp/geeqie-rotate.XXXXXXXXXX` || exit 3 + touch --reference="$file" "$mtime" + fi + + rotate_image_file "$exiftran_param" "$mogrify_param" "$file" + ret=$? + + if [ -n "$preserve_mtime" ] ; then + touch --reference="$mtime" "$file" + rm "$mtime" + fi + if [ $ret -eq 4 ] ; then + exit 4 + fi + else + rotate "$file" + fi fi done diff --git a/src/layout_util.c b/src/layout_util.c index 735a9e95..9cc0558f 100644 --- a/src/layout_util.c +++ b/src/layout_util.c @@ -51,6 +51,7 @@ #include "ui_tabcomp.h" #include "utilops.h" #include "view_dir.h" +#include "view_file.h" #include "window.h" #include "metadata.h" #include "desktop_file.h" @@ -59,6 +60,7 @@ #include "keymap_template.c" #define MENU_EDIT_ACTION_OFFSET 16 +#define FILE_COLUMN_POINTER 0 static gboolean layout_bar_enabled(LayoutWindow *lw); static gboolean layout_bar_sort_enabled(LayoutWindow *lw); @@ -451,6 +453,101 @@ static void layout_menu_exif_rotate_cb(GtkToggleAction *action, gpointer data) layout_image_reset_orientation(lw); } +static void layout_menu_write_rotate(GtkToggleAction *action, gpointer data, gboolean keep_date) +{ + LayoutWindow *lw = data; + GtkTreeModel *store; + GList *work; + GtkTreeSelection *selection; + GtkTreePath *tpath; + FileData *fd_n; + GtkTreeIter iter; + IconData *id; + gchar *rotation; + gchar *command; + gint run_result; + GenericDialog *gd; + GString *message; + + if (!layout_valid(&lw)) return; + + if (!lw || !lw->vf) return; + + if (lw->vf->type == FILEVIEW_ICON) + { + if (!VFICON(lw->vf)->selection) return; + work = VFICON(lw->vf)->selection; + } + else + { + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(lw->vf->listview)); + work = gtk_tree_selection_get_selected_rows(selection, &store); + } + + while (work) + { + if (lw->vf->type == FILEVIEW_ICON) + { + id = work->data; + fd_n = id->fd; + work = work->next; + } + else + { + tpath = work->data; + gtk_tree_model_get_iter(store, &iter, tpath); + gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1); + work = work->next; + } + + rotation = g_strdup_printf("%d", fd_n->user_orientation); + command = g_strconcat(GQ_BIN_DIR, "/geeqie-rotate -r ", rotation, + keep_date ? " -t " : " ", fd_n->path, NULL); + + run_result = WEXITSTATUS(runcmd(command)); + if (!run_result) + { + fd_n->user_orientation = 0; + } + else + { + message = g_string_new(""); + message = g_string_append(message, _("Operation failed:\n")); + + if (run_result == 3) + message = g_string_append(message, _("Cannot create tmp file")); + else + { + message = g_string_append(message, _("File: ")); + message = g_string_append(message, fd_n->name); + } + + gd = generic_dialog_new(_("Image orientation"), + "Image orientation", NULL, TRUE, NULL, NULL); + generic_dialog_add_message(gd, GTK_STOCK_DIALOG_ERROR, + "Image orientation", message->str); + generic_dialog_add_button(gd, GTK_STOCK_OK, NULL, NULL, TRUE); + + gtk_widget_show(gd->dialog); + + g_string_free(message, TRUE); + } + + g_free(rotation); + g_free(command); + } +} + +static void layout_menu_write_rotate_keep_date_cb(GtkToggleAction *action, gpointer data) +{ + layout_menu_write_rotate(action, data, TRUE); +} + +static void layout_menu_write_rotate_cb(GtkToggleAction *action, gpointer data) +{ + layout_menu_write_rotate(action, data, FALSE); +} + static void layout_menu_config_cb(GtkAction *action, gpointer data) { LayoutWindow *lw = data; @@ -1694,6 +1791,8 @@ static GtkActionEntry menu_entries[] = { { "StereoCycle", NULL, N_("_Cycle through stereo modes"), NULL, N_("Cycle through stereo modes"), CB(layout_menu_stereo_mode_next_cb) }, { "SplitNextPane", NULL, N_("_Next Pane"), "Right", N_("Next Pane"), CB(layout_menu_split_pane_next_cb) }, { "SplitPreviousPane", NULL, N_("_Previous Pane"), "Left", N_("Previous Pane"), CB(layout_menu_split_pane_prev_cb) }, + { "WriteRotation", NULL, N_("_Write orientation to file"), NULL, N_("Write orientation to file"), CB(layout_menu_write_rotate_cb) }, + { "WriteRotationKeepDate", NULL, N_("_Write orientation to file (preserve timestamp)"), NULL, N_("Write orientation to file (preserve timestamp)"), CB(layout_menu_write_rotate_keep_date_cb) }, }; @@ -1833,6 +1932,9 @@ static const gchar *menu_ui_description = " " " " " " +" " +" " +" " " " " " " " @@ -2634,6 +2736,13 @@ static void layout_util_sync_views(LayoutWindow *lw) action = gtk_action_group_get_action(lw->action_group, "ConnectZoomMenu"); gtk_action_set_sensitive(action, lw->split_mode != SPLIT_NONE); + action = gtk_action_group_get_action(lw->action_group, "WriteRotation"); + gtk_action_set_sensitive(action, !(runcmd("which exiftran >null") || + runcmd("which mogrify >null") || options->metadata.write_orientation)); + action = gtk_action_group_get_action(lw->action_group, "WriteRotationKeepDate"); + gtk_action_set_sensitive(action, !(runcmd("which exiftran >null") || + runcmd("which mogrify >null") || options->metadata.write_orientation)); + action = gtk_action_group_get_action(lw->action_group, "StereoAuto"); gtk_radio_action_set_current_value(GTK_RADIO_ACTION(action), layout_image_stereo_pixbuf_get(lw)); diff --git a/src/preferences.c b/src/preferences.c index 6347b7d5..aebc7689 100644 --- a/src/preferences.c +++ b/src/preferences.c @@ -451,7 +451,11 @@ static void config_window_ok_cb(GtkWidget *widget, gpointer data) static void config_window_apply_cb(GtkWidget *widget, gpointer data) { + LayoutWindow *lw; + lw = layout_window_list->data; + config_window_apply(); + layout_util_sync(lw); } static void config_window_save_cb(GtkWidget *widget, gpointer data)