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

Attachment: 0001-util-wmiv-add-image-auto-orientation-detection.patch
Description: Binary data

Reply via email to