Mercurial > hg > forks > geeqie
changeset 2501:b5cec98159e7
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.
author | Colin Clark <colin.clark@cclark.uk> |
---|---|
date | Mon, 12 Jun 2017 19:15:29 +0100 |
parents | eb2ce489ceea |
children | 728c2b544eec |
files | doc/docbook/GuideMainWindowMenus.xml plugins/rotate/geeqie-rotate src/layout_util.c src/preferences.c |
diffstat | 4 files changed, 232 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/doc/docbook/GuideMainWindowMenus.xml Thu Jun 08 20:46:52 2017 +0100 +++ b/doc/docbook/GuideMainWindowMenus.xml Mon Jun 12 19:15:29 2017 +0100 @@ -742,6 +742,35 @@ <varlistentry> <term> <menuchoice> + <guimenu>Orientation</guimenu> + <guimenuitem>Write orientation to file</guimenuitem> + </menuchoice> + </term> + <listitem> + <para> + 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. + <note> + The Preferences/Metadata option "Write altered image orientation to the metadata" must be off. + <para /> + Exiftran and mogrify must be installed. + </note> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> + <guimenu>Orientation</guimenu> + <guimenuitem>Write orientation to file (preserve timestamp)</guimenuitem> + </menuchoice> + </term> + <listitem> + <para>As above, but the file date and time are preserved.</para> + </listitem> + </varlistentry> + <varlistentry> + <term> + <menuchoice> <guimenu>Rating</guimenu> </menuchoice> </term>
--- a/plugins/rotate/geeqie-rotate Thu Jun 08 20:46:52 2017 +0100 +++ b/plugins/rotate/geeqie-rotate Mon Jun 12 19:15:29 2017 +0100 @@ -47,12 +47,83 @@ 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 @@ 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
--- a/src/layout_util.c Thu Jun 08 20:46:52 2017 +0100 +++ b/src/layout_util.c Mon Jun 12 19:15:29 2017 +0100 @@ -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 @@ 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 @@ { "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"), "<alt>Right", N_("Next Pane"), CB(layout_menu_split_pane_next_cb) }, { "SplitPreviousPane", NULL, N_("_Previous Pane"), "<alt>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 @@ " <separator/>" " <menuitem action='ExifRotate'/>" " <separator/>" +" <menuitem action='WriteRotation'/>" +" <menuitem action='WriteRotationKeepDate'/>" +" <separator/>" " </menu>" " <menu action='RatingMenu'>" " <menuitem action='Rating0'/>" @@ -2634,6 +2736,13 @@ 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));
--- a/src/preferences.c Thu Jun 08 20:46:52 2017 +0100 +++ b/src/preferences.c Mon Jun 12 19:15:29 2017 +0100 @@ -451,7 +451,11 @@ 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)