This patch is less intrusive than the previous one, almost all is done in wmiv, the exif metadata handling is based on libexif.
Based on libexif feature, this patch is adding orientation
detection and provides 2 more shortcuts for live
right/left rotation. Internal version was bumped to 0.7.
---
configure.ac | 6 ++
m4/wm_libexif.m4 | 34 ++++++++++
util/Makefile.am | 2 +-
util/wmiv.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++----
4 files changed, 220 insertions(+), 15 deletions(-)
create mode 100644 m4/wm_libexif.m4
diff --git a/configure.ac b/configure.ac
index 4ea1e32..2b9fe6b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -640,6 +640,12 @@ dnl ===============================================
dnl End of stuff that uses X
dnl ===============================================
+dnl EXIF Support
+dnl ===========
+WM_CHECK_LIBEXIF
+AS_IF([test "x$LIBEXIF" != "x"],
+ [AC_DEFINE(HAVE_EXIF, 1, [Define if EXIF can be used])])
+
dnl PNG Support
dnl ===========
AC_ARG_ENABLE([png],
diff --git a/m4/wm_libexif.m4 b/m4/wm_libexif.m4
new file mode 100644
index 0000000..ac501bb
--- /dev/null
+++ b/m4/wm_libexif.m4
@@ -0,0 +1,34 @@
+# wm_libexif.m4 - Macros to check proper libexif
+#
+# Copyright (c) 2014 Window Maker Team
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# WM_CHECK_LIBEXIF
+# -------------
+#
+# Checks the needed library link flags
+# Sets variable LIBEXIF with the appropriates flags
+AC_DEFUN_ONCE([WM_CHECK_LIBEXIF],
+[AC_CHECK_HEADER([libexif/exif-data.h],
+ [AC_CHECK_FUNC(exif_data_new_from_file,
+ [LIBEXIF=],
+ [AC_CHECK_LIB(exif, [exif_data_new_from_file],
+ [LIBEXIF=-lexif],
+ [AC_MSG_WARN(Could not find EXIF library, you may experience problems)
+ LIBEXIF=] )] )],
+ [AC_MSG_WARN([header for EXIF library not found])])
+AC_SUBST(LIBEXIF) dnl
+])
diff --git a/util/Makefile.am b/util/Makefile.am
index 5cde3ee..b5c9d04 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -73,7 +73,7 @@ wmmenugen_SOURCES = wmmenugen.c wmmenugen.h wmmenugen_misc.c \
wmiv_LDADD = \
$(top_builddir)/wrlib/libwraster.la \
@XLFLAGS@ @XLIBS@ \
- @GFXLIBS@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+ @GFXLIBS@ $(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(LIBEXIF)
wmiv_SOURCES = wmiv.c wmiv.h
diff --git a/util/wmiv.c b/util/wmiv.c
index 2eab5d3..9810b5c 100755
--- a/util/wmiv.c
+++ b/util/wmiv.c
@@ -21,6 +21,7 @@
#if !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif
+
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#include <X11/Xatom.h>
@@ -34,6 +35,11 @@
#include <unistd.h>
#include <sys/stat.h>
#include "config.h"
+
+#ifdef HAVE_EXIF
+#include <libexif/exif-data.h>
+#endif
+
#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif
@@ -57,7 +63,7 @@ Pixmap pix;
const char *APPNAME = "wmiv";
int APPVERSION_MAJOR = 0;
-int APPVERSION_MINOR = 6;
+int APPVERSION_MINOR = 7;
int NEXT = 0;
int PREV = 1;
float zoom_factor = 0;
@@ -66,6 +72,7 @@ int max_height = 0;
Bool fullscreen_flag = False;
Bool focus = False;
+Bool back_from_fullscreen = False;
#ifdef HAVE_PTHREAD
Bool diaporama_flag = False;
@@ -98,6 +105,90 @@ typedef struct linked_list {
linked_list_t list;
link_t *current_link;
+
+/*
+ load_oriented_image: used to load an image and optionally
+ get its orientation if libexif is available
+ return the image on success, NULL on failure
+*/
+RImage *load_oriented_image(RContext *context, const char *file, int index)
+{
+ RImage *image;
+#ifdef HAVE_EXIF
+ int orientation = 0;
+#endif
+ image = RLoadImage(context, file, index);
+ if (!image)
+ return NULL;
+#ifdef HAVE_EXIF
+ ExifData *exifData = exif_data_new_from_file(file);
+ if (exifData) {
+ ExifByteOrder byteOrder = exif_data_get_byte_order(exifData);
+ ExifEntry *exifEntry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
+ if (exifEntry)
+ orientation = exif_get_short(exifEntry->data, byteOrder);
+
+ exif_data_free(exifData);
+ }
+
+/*
+ 0th Row 0th Column
+ 1 top left side
+ 2 top right side
+ 3 bottom right side
+ 4 bottom left side
+ 5 left side top
+ 6 right side top
+ 7 right side bottom
+ 8 left side bottom
+*/
+
+ if (image && (orientation > 1)) {
+ RImage *tmp = NULL;
+ switch (orientation) {
+ case 2:
+ tmp = RHorizontalFlipImage(image);
+ break;
+ case 3:
+ tmp = RRotateImage(image, 180);
+ break;
+ case 4:
+ tmp = RVerticalFlipImage(image);
+ break;
+ case 5: {
+ RImage *tmp2;
+ tmp2 = RVerticalFlipImage(image);
+ if (tmp2) {
+ tmp = RRotateImage(tmp2, 90);
+ RReleaseImage(tmp2);
+ }
+ }
+ break;
+ case 6:
+ tmp = RRotateImage(image, 90);
+ break;
+ case 7: {
+ RImage *tmp2;
+ tmp2 = RVerticalFlipImage(image);
+ if (tmp2) {
+ tmp = RRotateImage(tmp2, 270);
+ RReleaseImage(tmp2);
+ }
+ }
+ break;
+ case 8:
+ tmp = RRotateImage(image, 270);
+ break;
+ }
+ if (tmp) {
+ RReleaseImage(image);
+ image = tmp;
+ }
+ }
+#endif
+ return image;
+}
+
/*
change_title: used to change window title
return EXIT_SUCCESS on success, 1 on failure
@@ -212,6 +303,59 @@ int merge_with_background(RImage *i)
}
/*
+ turn_image: rotate the image by the angle passed
+ return EXIT_SUCCESS on success, EXIT_FAILURE on failure
+*/
+int turn_image(float angle)
+{
+ RImage *tmp;
+
+ if (!img)
+ return EXIT_FAILURE;
+
+ tmp = RRotateImage(img, angle);
+ if (!tmp)
+ return EXIT_FAILURE;
+
+ if (!fullscreen_flag) {
+ if (img->width != tmp->width || img->height != tmp->height)
+ XResizeWindow(dpy, win, tmp->width, tmp->height);
+ }
+
+ RReleaseImage(img);
+ img = tmp;
+
+ rescale_image();
+ if (!fullscreen_flag) {
+ XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0, img->width, img->height, 0, 0);
+ } else {
+ XClearWindow(dpy, win);
+ XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0,
+ img->width, img->height, max_width/2-img->width/2,
max_height/2-img->height/2);
+ }
+
+ return EXIT_SUCCESS;
+}
+
+/*
+ turn_image_right: rotate the image by 90 degree
+ return EXIT_SUCCESS on success, EXIT_FAILURE on failure
+*/
+int turn_image_right(void)
+{
+ return turn_image(90.0);
+}
+
+/*
+ turn_image_left: rotate the image by -90 degree
+ return EXIT_SUCCESS on success, 1 on failure
+*/
+int turn_image_left(void)
+{
+ return turn_image(-90.0);
+}
+
+/*
draw_failed_image: create a red crossed image to indicate an error
loading file
return the image on success, NULL on failure
@@ -250,6 +394,7 @@ int full_screen(void)
if (fullscreen_flag) {
fullscreen_flag = False;
zoom_factor = 0;
+ back_from_fullscreen = True;
} else {
fullscreen_flag = True;
zoom_factor = 1000;
@@ -279,7 +424,7 @@ int full_screen(void)
int zoom_in_out(int z)
{
RImage *old_img = img;
- RImage *tmp = RLoadImage(ctx, current_link->data, 0);
+ RImage *tmp = load_oriented_image(ctx, current_link->data, 0);
if (!tmp)
return EXIT_FAILURE;
@@ -368,7 +513,7 @@ int change_image(int way)
}
if (DEBUG)
fprintf(stderr, "current file is> %s\n", (char *)current_link->data);
- img = RLoadImage(ctx, current_link->data, 0);
+ img = load_oriented_image(ctx, current_link->data, 0);
if (!img) {
fprintf(stderr, "Error: %s %s\n", (char *)current_link->data,
@@ -453,7 +598,7 @@ int linked_list_add(linked_list_t *list, const void *data)
/* calloc sets the "next" field to zero. */
link = calloc(1, sizeof(link_t));
if (!link) {
- fprintf(stderr, "calloc failed.\n");
+ fprintf(stderr, "Error: memory allocation failed\n");
return EXIT_FAILURE;
}
link->data = data;
@@ -572,7 +717,9 @@ int main(int argc, char **argv)
#ifdef HAVE_PTHREAD
"d: launch diaporama mode\n"
#endif
+ "l: rotate image on the left\n"
"q: quit\n"
+ "r: rotate image on the right\n"
"right: next image\n"
"left: previous image\n"
"up: first image\n"
@@ -618,7 +765,7 @@ int main(int argc, char **argv)
}
}
- img = RLoadImage(ctx, reading_filename, 0);
+ img = load_oriented_image(ctx, reading_filename, 0);
if (!img) {
fprintf(stderr, "Error: %s %s\n", reading_filename,
RMessageForError(RErrorCode));
@@ -703,21 +850,33 @@ int main(int argc, char **argv)
XConfigureEvent xce = e.xconfigure;
if (xce.width != img->width || xce.height != img->height) {
RImage *old_img = img;
- img = RLoadImage(ctx, current_link->data, 0);
+ img = load_oriented_image(ctx, current_link->data, 0);
if (!img) {
/* keep the old img and window size */
img = old_img;
XResizeWindow(dpy, win, img->width, img->height);
} else {
- img = RScaleImage(img, xce.width, xce.height);
- if (!img) {
- img = old_img;
- XResizeWindow(dpy, win, img->width, img->height);
- } else {
- merge_with_background(img);
- if (RConvertImage(ctx, img, &pix))
- RReleaseImage(old_img);
+ RImage *tmp2;
+ if (!back_from_fullscreen)
+ /* manually resized window */
+ tmp2 = RScaleImage(img, xce.width, xce.height);
+ else {
+ /* back from fullscreen mode, maybe img was rotated */
+ tmp2 = img;
+ back_from_fullscreen = False;
+ XClearWindow(dpy, win);
+ }
+ merge_with_background(tmp2);
+ if (RConvertImage(ctx, tmp2, &pix)) {
+ RReleaseImage(old_img);
+ img = RCloneImage(tmp2);
+ RReleaseImage(tmp2);
+ change_title(&title_property, (char *)current_link->data);
+ XSync(dpy, True);
XResizeWindow(dpy, win, img->width, img->height);
+ XCopyArea(dpy, pix, win, ctx->copy_gc, 0, 0,
+ img->width, img->height, 0, 0);
+
}
}
}
@@ -814,6 +973,12 @@ int main(int argc, char **argv)
case XK_f:
full_screen();
break;
+ case XK_r:
+ turn_image_right();
+ break;
+ case XK_l:
+ turn_image_left();
+ break;
}
}
--
1.8.3.2
0001-util-wmiv-add-image-auto-orientation-detection.patch
Description: Binary data
