diff --git a/legacy/ethumb/configure.ac b/legacy/ethumb/configure.ac index ddb64f6e22..62b8a11a92 100644 --- a/legacy/ethumb/configure.ac +++ b/legacy/ethumb/configure.ac @@ -121,6 +121,29 @@ if $USE_MODULE_ETHUMBD ; then ] ) fi +AC_ARG_ENABLE([libexif], + [AC_HELP_STRING([--disable-libexif], [disable libexif support. Default is enabled.])], + [ + if test "x${enableval}" = "xyes" ; then + _iv_enable_libexif="yes" + else + _iv_enable_libexif="no" + fi + ], + [_iv_enable_libexif="yes"] +) + +AC_MSG_CHECKING([whether libexif is built]) +AC_MSG_RESULT([${_iv_enable_libexif}]) + +HAVE_LIBEXIF="no" + +if test "x${_iv_enable_libexif}" = "xyes" ; then + AC_ETH_CHECK_PKG(LIBEXIF, libexif) +fi + +AM_CONDITIONAL(HAVE_LIBEXIF, test $HAVE_LIBEXIF = yes) +AC_SUBST(HAVE_LIBEXIF) AC_SUBST(requirement_ethumb) AC_SUBST(requirement_ethumb_client) diff --git a/legacy/ethumb/src/lib/Ethumb.c b/legacy/ethumb/src/lib/Ethumb.c index 5bee1dd363..b592639507 100644 --- a/legacy/ethumb/src/lib/Ethumb.c +++ b/legacy/ethumb/src/lib/Ethumb.c @@ -69,6 +69,10 @@ void *alloca (size_t); #include "Ethumb_Plugin.h" #include "md5.h" +#ifdef HAVE_LIBEXIF + #include +#endif + static int _log_dom = -1; #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__) @@ -224,6 +228,7 @@ ethumb_new(void) /* IF CHANGED, UPDATE DOCS in (Ethumb.c, Ethumb_Client.c, python...)!!! */ ethumb->tw = THUMB_SIZE_NORMAL; ethumb->th = THUMB_SIZE_NORMAL; + ethumb->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL; ethumb->crop_x = 0.5; ethumb->crop_y = 0.5; ethumb->quality = 80; @@ -345,6 +350,7 @@ ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s) e->format = ETHUMB_THUMB_FDO; e->aspect = ETHUMB_THUMB_KEEP_ASPECT; + e->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL; _ethumb_frame_free(e->frame); e->frame = NULL; eina_stringshare_del(e->thumb_dir); @@ -412,6 +418,31 @@ ethumb_thumb_aspect_get(const Ethumb *e) return e->aspect; } +EAPI void +ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o) +{ + EINA_SAFETY_ON_NULL_RETURN(e); + EINA_SAFETY_ON_FALSE_RETURN(o == ETHUMB_THUMB_ORIENT_NONE || + o == ETHUMB_THUMB_ROTATE_90_CW || + o == ETHUMB_THUMB_ROTATE_180 || + o == ETHUMB_THUMB_ROTATE_90_CCW || + o == ETHUMB_THUMB_FLIP_HORIZONTAL || + o == ETHUMB_THUMB_FLIP_VERTICAL || + o == ETHUMB_THUMB_FLIP_TRANSPOSE || + o == ETHUMB_THUMB_FLIP_TRANSVERSE || + o == ETHUMB_THUMB_ORIENT_ORIGINAL); + + DBG("ethumb=%p, orientation=%d", e, o); + e->orientation = o; +} + +EAPI Ethumb_Thumb_Orientation +ethumb_thumb_orientation_get(const Ethumb *e) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0); + return e->orientation; +} + EAPI void ethumb_thumb_crop_align_set(Ethumb *e, float x, float y) { @@ -1171,12 +1202,135 @@ ethumb_image_save(Ethumb *e) return EINA_TRUE; } +static void +_ethumb_image_orient(Ethumb *e, int orientation) +{ + Evas_Object *img = e->img, *tmp; + unsigned int *data, *data2, *to, *from, *p1, *p2, pt; + int x, y, w, hw, iw, ih, tw, th; + const char *file, *key; + + evas_object_image_size_get(img, &iw, &ih); + data = evas_object_image_data_get(img, 1); + + switch (orientation) + { + case ETHUMB_THUMB_FLIP_HORIZONTAL: + for (y = 0; y < ih; y++) + { + p1 = data + (y * iw); + p2 = data + ((y + 1) * iw) - 1; + for (x = 0; x < (iw >> 1); x++) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2--; + } + } + evas_object_image_data_set(img, data); + evas_object_image_data_update_add(img, 0, 0, iw, ih); + return; + case ETHUMB_THUMB_FLIP_VERTICAL: + for (y = 0; y < (ih >> 1); y++) + { + p1 = data + (y * iw); + p2 = data + ((ih - 1 - y) * iw); + for (x = 0; x < iw; x++) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2++; + } + } + evas_object_image_data_set(img, data); + evas_object_image_data_update_add(img, 0, 0, iw, ih); + return; + case ETHUMB_THUMB_ROTATE_180: + hw = iw * ih; + x = (hw / 2); + p1 = data; + p2 = data + hw - 1; + for (; --x > 0;) + { + pt = *p1; + *p1 = *p2; + *p2 = pt; + p1++; + p2--; + } + evas_object_image_data_set(img, data); + evas_object_image_data_update_add(img, 0, 0, iw, ih); + return; + } + + evas_object_image_load_size_get(img, &tw, &th); + evas_object_image_file_get(img, &file, &key); + tmp = evas_object_image_add(evas_object_evas_get(img)); + evas_object_image_load_size_set(tmp, tw, th); + evas_object_image_file_set(tmp, file, key); + data2 = evas_object_image_data_get(tmp, 0); + + w = ih; + ih = iw; + iw = w; + hw = w * ih; + + evas_object_image_size_set(img, iw, ih); + data = evas_object_image_data_get(img, 1); + + switch (orientation) + { + case ETHUMB_THUMB_FLIP_TRANSPOSE: + to = data; + hw = -hw + 1; + break; + case ETHUMB_THUMB_FLIP_TRANSVERSE: + to = data + hw - 1; + w = -w; + hw = hw - 1; + break; + case ETHUMB_THUMB_ROTATE_90_CW: + to = data + w - 1; + hw = -hw - 1; + break; + case ETHUMB_THUMB_ROTATE_90_CCW: + to = data + hw - w; + w = -w; + hw = hw + 1; + break; + default: + ERR("unknown orient %d", orientation); + evas_object_del(tmp); + evas_object_image_data_set(img, data); // give it back + return; + } + from = data2; + for (x = iw; --x >= 0;) + { + for (y = ih; --y >= 0;) + { + *to = *from; + from++; + to += w; + } + to += hw; + } + evas_object_del(tmp); + evas_object_image_data_set(img, data); + evas_object_image_data_update_add(img, 0, 0, iw, ih); +} + static int _ethumb_image_load(Ethumb *e) { int error; Evas_Coord w, h, ww, hh, fx, fy, fw, fh; Evas_Object *img; + int orientation = ETHUMB_THUMB_ORIENT_NONE; img = e->img; @@ -1200,6 +1354,54 @@ _ethumb_image_load(Ethumb *e) return 0; } + if (e->orientation == ETHUMB_THUMB_ORIENT_ORIGINAL) + { +#ifdef HAVE_LIBEXIF + ExifData *exif = exif_data_new_from_file(e->src_path); + ExifEntry *entry = NULL; + ExifByteOrder bo; + int o; + + if (exif) + { + entry = exif_data_get_entry(exif, EXIF_TAG_ORIENTATION); + if (entry) + { + bo = exif_data_get_byte_order(exif); + o = exif_get_short(entry->data, bo); + } + exif_data_free(exif); + switch (o) + { + case 2: + orientation = ETHUMB_THUMB_FLIP_HORIZONTAL; + break; + case 3: + orientation = ETHUMB_THUMB_ROTATE_180; + break; + case 4: + orientation = ETHUMB_THUMB_FLIP_VERTICAL; + break; + case 5: + orientation = ETHUMB_THUMB_FLIP_TRANSPOSE; + break; + case 6: + orientation = ETHUMB_THUMB_ROTATE_90_CW; + break; + case 7: + orientation = ETHUMB_THUMB_FLIP_TRANSVERSE; + break; + case 8: + orientation = ETHUMB_THUMB_ROTATE_90_CCW; + break; + } + } +#endif + } + + if (orientation != ETHUMB_THUMB_ORIENT_NONE) + _ethumb_image_orient(e, orientation); + evas_object_image_size_get(img, &w, &h); if ((w <= 0) || (h <= 0)) return 0; diff --git a/legacy/ethumb/src/lib/Ethumb.h b/legacy/ethumb/src/lib/Ethumb.h index 37e5ba3194..b9c0c86413 100644 --- a/legacy/ethumb/src/lib/Ethumb.h +++ b/legacy/ethumb/src/lib/Ethumb.h @@ -119,16 +119,32 @@ typedef enum _Ethumb_Thumb_Aspect ETHUMB_THUMB_CROP /**< keep aspect but crop (cut) the largest dimension */ } Ethumb_Thumb_Aspect; +typedef enum _Ethumb_Thumb_Orientation +{ + ETHUMB_THUMB_ORIENT_NONE, /**< keep orientation as pixel data is */ + ETHUMB_THUMB_ROTATE_90_CW, /**< rotate 90° clockwise */ + ETHUMB_THUMB_ROTATE_180, /**< rotate 180° */ + ETHUMB_THUMB_ROTATE_90_CCW, /**< rotate 90° counter-clockwise */ + ETHUMB_THUMB_FLIP_HORIZONTAL, /**< flip horizontally */ + ETHUMB_THUMB_FLIP_VERTICAL, /**< flip vertically */ + ETHUMB_THUMB_FLIP_TRANSPOSE, /**< transpose */ + ETHUMB_THUMB_FLIP_TRANSVERSE, /**< transverse */ + ETHUMB_THUMB_ORIENT_ORIGINAL /**< use orientation from metadata (EXIF-only currently) */ +} Ethumb_Thumb_Orientation; + EAPI void ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s) EINA_ARG_NONNULL(1); EAPI void ethumb_thumb_size_set(Ethumb *e, int tw, int th) EINA_ARG_NONNULL(1); EAPI void ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th) EINA_ARG_NONNULL(1); -EAPI void ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f) EINA_ARG_NONNULL(1); -EAPI Ethumb_Thumb_Format ethumb_thumb_format_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; +EAPI void ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f) EINA_ARG_NONNULL(1); +EAPI Ethumb_Thumb_Format ethumb_thumb_format_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; -EAPI void ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a) EINA_ARG_NONNULL(1); -EAPI Ethumb_Thumb_Aspect ethumb_thumb_aspect_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; +EAPI void ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a) EINA_ARG_NONNULL(1); +EAPI Ethumb_Thumb_Aspect ethumb_thumb_aspect_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; + +EAPI void ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o) EINA_ARG_NONNULL(1); +EAPI Ethumb_Thumb_Orientation ethumb_thumb_orientation_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; EAPI void ethumb_thumb_crop_align_set(Ethumb *e, float x, float y) EINA_ARG_NONNULL(1); EAPI void ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y) EINA_ARG_NONNULL(1); diff --git a/legacy/ethumb/src/lib/Makefile.am b/legacy/ethumb/src/lib/Makefile.am index c521a0bfe6..66796a43fa 100644 --- a/legacy/ethumb/src/lib/Makefile.am +++ b/legacy/ethumb/src/lib/Makefile.am @@ -9,6 +9,10 @@ AM_CPPFLAGS = \ @EINA_CFLAGS@ @EVAS_CFLAGS@ @ECORE_EVAS_CFLAGS@ @ECORE_FILE_CFLAGS@ @EDJE_CFLAGS@ \ @EFL_ETHUMB_BUILD@ +if HAVE_LIBEXIF +AM_CPPFLAGS += @LIBEXIF_CFLAGS@ +endif + includes_HEADERS = Ethumb.h Ethumb_Plugin.h includesdir = $(includedir)/ethumb-@VMAJ@ @@ -24,6 +28,9 @@ libethumb_la_LIBADD = \ @EDJE_LIBS@ @ECORE_FILE_LIBS@ @ECORE_EVAS_LIBS@ @EVAS_LIBS@ libethumb_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ +if HAVE_LIBEXIF +libethumb_la_LIBADD += @LIBEXIF_LIBS@ +endif if USE_MODULE_ETHUMBD SUBDIRS += client diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.c b/legacy/ethumb/src/lib/client/Ethumb_Client.c index 2985e2f121..e67fbf250d 100644 --- a/legacy/ethumb/src/lib/client/Ethumb_Client.c +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.c @@ -844,7 +844,7 @@ ethumb_client_ethumb_setup(Ethumb_Client *client) DBusMessageIter iter, aiter, diter, viter, vaiter; Ethumb *e = client->ethumb; const char *entry; - dbus_int32_t tw, th, format, aspect, quality, compress; + dbus_int32_t tw, th, format, aspect, orientation, quality, compress; float cx, cy; double t; const char *theme_file, *group, *swallow; @@ -900,6 +900,11 @@ ethumb_client_ethumb_setup(Ethumb_Client *client) dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &aspect); _close_variant_iter(viter); + _open_variant_iter("orientation", "i", viter); + orientation = ethumb_thumb_orientation_get(e); + dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &orientation); + _close_variant_iter(viter); + _open_variant_iter("crop", "(dd)", viter); dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter); ethumb_thumb_crop_align_get(e, &cx, &cy); @@ -1487,6 +1492,48 @@ ethumb_client_aspect_get(const Ethumb_Client *client) return ethumb_thumb_aspect_get(client->ethumb); } +/** + * Configure orientation to use for future requests. + * + * Default value is #ETHUMB_THUMB_ORIENT_ORIGINAL: metadata from the file + * will be used to orient pixel data. + * + * @param client the client instance to use. Must @b not be @c + * NULL. May be pending connected (can be called before @c + * connected_cb) + * @param f format identifier to use, either #ETHUMB_THUMB_ORIENT_NONE (0), + * #ETHUMB_THUMB_ROTATE_90_CW (1), #ETHUMB_THUMB_ROTATE_180 (2), + * #ETHUMB_THUMB_ROTATE_90_CCW (3), #ETHUMB_THUMB_FLIP_HORIZONTAL (4), + * #ETHUMB_THUMB_FLIP_VERTICAL (5), #ETHUMB_THUMB_FLIP_TRANSPOSE (6), + * #ETHUMB_THUMB_FLIP_TRANSVERSE (7) or #ETHUMB_THUMB_ORIENT_ORIGINAL + * (8). Default is ORIGINAL. + */ +EAPI void +ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_orientation_set(client->ethumb, o); +} + +/** + * Get current orientation in use for requests. + * + * @param client the client instance to use. Must @b not be @c + * NULL. May be pending connected (can be called before @c + * connected_cb) + * + * @return orientation in use for future requests. + */ +EAPI Ethumb_Thumb_Orientation +ethumb_client_orientation_get(const Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + return ethumb_thumb_orientation_get(client->ethumb); +} + /** * Configure crop alignment in use for future requests. * diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.h b/legacy/ethumb/src/lib/client/Ethumb_Client.h index 7762480d1e..355ecadc1f 100644 --- a/legacy/ethumb/src/lib/client/Ethumb_Client.h +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.h @@ -122,7 +122,7 @@ EAPI void ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb /** * @defgroup Ethumb_Client_Setup Ethumb Client Fine Tune Setup * - * How to fine tune thumbnail generation, setting size, aspect, + * How to fine tune thumbnail generation, setting size, aspect, orientation, * frames, quality and so on. * * @{ @@ -135,6 +135,8 @@ EAPI void ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f) EAPI Ethumb_Thumb_Format ethumb_client_format_get(const Ethumb_Client *client); EAPI void ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a); EAPI Ethumb_Thumb_Aspect ethumb_client_aspect_get(const Ethumb_Client *client); +EAPI void ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o); +EAPI Ethumb_Thumb_Orientation ethumb_client_orientation_get(const Ethumb_Client *client); EAPI void ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y); EAPI void ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y); EAPI void ethumb_client_quality_set(Ethumb_Client *client, int quality); diff --git a/legacy/ethumb/src/lib/ethumb_private.h b/legacy/ethumb/src/lib/ethumb_private.h index a647c5b27a..873b97991d 100644 --- a/legacy/ethumb/src/lib/ethumb_private.h +++ b/legacy/ethumb/src/lib/ethumb_private.h @@ -20,6 +20,7 @@ struct _Ethumb int tw, th; int format; int aspect; + int orientation; float crop_x, crop_y; int quality; int compress;