4 * Copyright (C) 2009 by ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library;
18 * if not, see <http://www.gnu.org/licenses/>.
20 * @author Rafael Antognolli <antognolli@profusion.mobi>
28 #elif defined __GNUC__
29 # define alloca __builtin_alloca
31 # define alloca __alloca
32 #elif defined _MSC_VER
34 # define alloca _alloca
40 void *alloca (size_t);
49 #include <sys/types.h>
56 # define PATH_MAX 4096
60 #include <eina_safety_checks.h>
63 #include <Ecore_Evas.h>
64 #include <Ecore_File.h>
68 #include "ethumb_private.h"
69 #include "Ethumb_Plugin.h"
73 #include <libexif/exif-data.h>
76 static int _log_dom = -1;
77 #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
78 #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
79 #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
80 #define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
82 static int initcount = 0;
83 static const char *_home_thumb_dir = NULL;
84 static const char *_thumb_category_normal = NULL;
85 static const char *_thumb_category_large = NULL;
87 static const int THUMB_SIZE_NORMAL = 128;
88 static const int THUMB_SIZE_LARGE = 256;
90 static Eina_Hash *_plugins_ext = NULL;
91 static Eina_Array *_plugins = NULL;
94 _ethumb_plugin_list_cb(Eina_Module *m, void *data __UNUSED__)
98 Ethumb_Plugin *plugin;
99 Ethumb_Plugin *(*plugin_get)(void);
101 file = eina_module_file_get(m);
102 if (!eina_module_load(m))
104 ERR("could not load module \"%s\": %s",
105 file, eina_error_msg_get(eina_error_get()));
109 plugin_get = eina_module_symbol_get(m, "ethumb_plugin_get");
112 ERR("could not find ethumb_plugin_get() in module \"%s\": %s",
113 file, eina_error_msg_get(eina_error_get()));
114 eina_module_unload(m);
118 plugin = plugin_get();
121 ERR("plugin \"%s\" failed to init.", file);
122 eina_module_unload(m);
126 DBG("loaded plugin \"%s\" (%p) with extensions:", file, plugin);
127 for (ext = plugin->extensions; *ext; ext++)
129 DBG(" extension \"%s\"", *ext);
130 eina_hash_add(_plugins_ext, *ext, plugin);
137 _ethumb_plugins_load(void)
139 _plugins_ext = eina_hash_string_small_new(NULL);
140 EINA_SAFETY_ON_NULL_RETURN(_plugins_ext);
142 _plugins = eina_module_list_get(_plugins, PLUGINSDIR, 1,
143 &_ethumb_plugin_list_cb, NULL);
147 _ethumb_plugins_unload(void)
149 eina_hash_free(_plugins_ext);
151 eina_module_list_unload(_plugins);
152 eina_module_list_free(_plugins);
153 eina_array_free(_plugins);
168 fprintf(stderr, "ERROR: Could not initialize eina.\n");
171 _log_dom = eina_log_domain_register("ethumb", EINA_COLOR_GREEN);
174 EINA_LOG_ERR("Could not register log domain: ethumb");
184 home = getenv("HOME");
185 snprintf(buf, sizeof(buf), "%s/.thumbnails", home);
187 _home_thumb_dir = eina_stringshare_add(buf);
188 _thumb_category_normal = eina_stringshare_add("normal");
189 _thumb_category_large = eina_stringshare_add("large");
191 _ethumb_plugins_load();
196 ethumb_shutdown(void)
201 _ethumb_plugins_unload();
202 eina_stringshare_del(_home_thumb_dir);
203 eina_stringshare_del(_thumb_category_normal);
204 eina_stringshare_del(_thumb_category_large);
207 ecore_evas_shutdown();
209 eina_log_domain_unregister(_log_dom);
221 Ecore_Evas *ee, *sub_ee;
223 Evas_Object *o, *img;
225 ethumb = calloc(1, sizeof(Ethumb));
226 EINA_SAFETY_ON_NULL_RETURN_VAL(ethumb, NULL);
228 /* IF CHANGED, UPDATE DOCS in (Ethumb.c, Ethumb_Client.c, python...)!!! */
229 ethumb->tw = THUMB_SIZE_NORMAL;
230 ethumb->th = THUMB_SIZE_NORMAL;
231 ethumb->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
232 ethumb->crop_x = 0.5;
233 ethumb->crop_y = 0.5;
234 ethumb->quality = 80;
235 ethumb->compress = 9;
236 ethumb->video.start = 0.1;
237 ethumb->video.time = 3;
238 ethumb->video.interval = 0.05;
239 ethumb->video.ntimes = 3;
240 ethumb->video.fps = 10;
242 ee = ecore_evas_buffer_new(1, 1);
243 e = ecore_evas_get(ee);
246 ERR("could not create ecore evas buffer");
251 evas_image_cache_set(e, 0);
252 evas_font_cache_set(e, 0);
254 o = ecore_evas_object_image_new(ee);
257 ERR("could not create sub ecore evas buffer");
263 sub_ee = ecore_evas_object_ecore_evas_get(o);
264 sub_e = ecore_evas_object_evas_get(o);
266 evas_image_cache_set(sub_e, 0);
267 evas_font_cache_set(sub_e, 0);
269 img = evas_object_image_add(sub_e);
272 ERR("could not create source objects.");
280 ethumb->sub_ee = sub_ee;
281 ethumb->sub_e = sub_e;
285 DBG("ethumb=%p", ethumb);
291 _ethumb_frame_free(Ethumb_Frame *frame)
298 if (frame->swallow && frame->edje)
300 o = edje_object_part_swallow_get(frame->edje, frame->swallow);
302 edje_object_part_unswallow(frame->edje, o);
304 eina_stringshare_del(frame->file);
305 eina_stringshare_del(frame->group);
306 eina_stringshare_del(frame->swallow);
309 evas_object_del(frame->edje);
315 ethumb_free(Ethumb *ethumb)
317 EINA_SAFETY_ON_NULL_RETURN(ethumb);
319 DBG("ethumb=%p", ethumb);
322 _ethumb_frame_free(ethumb->frame);
323 ethumb_file_free(ethumb);
324 evas_object_del(ethumb->o);
325 ecore_evas_free(ethumb->ee);
326 eina_stringshare_del(ethumb->thumb_dir);
327 eina_stringshare_del(ethumb->category);
328 if (ethumb->finished_idler)
329 ecore_idler_del(ethumb->finished_idler);
334 ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s)
336 EINA_SAFETY_ON_NULL_RETURN(e);
337 EINA_SAFETY_ON_FALSE_RETURN(s == ETHUMB_THUMB_NORMAL ||
338 s == ETHUMB_THUMB_LARGE);
339 DBG("ethumb=%p, size=%d", e, s);
341 if (s == ETHUMB_THUMB_NORMAL)
343 e->tw = THUMB_SIZE_NORMAL;
344 e->th = THUMB_SIZE_NORMAL;
348 e->tw = THUMB_SIZE_LARGE;
349 e->th = THUMB_SIZE_LARGE;
352 e->format = ETHUMB_THUMB_FDO;
353 e->aspect = ETHUMB_THUMB_KEEP_ASPECT;
354 e->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
355 _ethumb_frame_free(e->frame);
357 eina_stringshare_del(e->thumb_dir);
358 eina_stringshare_del(e->category);
364 ethumb_thumb_size_set(Ethumb *e, int tw, int th)
366 EINA_SAFETY_ON_NULL_RETURN(e);
367 EINA_SAFETY_ON_FALSE_RETURN(tw > 0);
368 EINA_SAFETY_ON_FALSE_RETURN(th > 0);
370 DBG("ethumb=%p, w=%d, h=%d", e, tw, th);
376 ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th)
378 EINA_SAFETY_ON_NULL_RETURN(e);
385 ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f)
387 EINA_SAFETY_ON_NULL_RETURN(e);
388 EINA_SAFETY_ON_FALSE_RETURN(f == ETHUMB_THUMB_FDO ||
389 f == ETHUMB_THUMB_JPEG ||
390 f == ETHUMB_THUMB_EET);
392 DBG("ethumb=%p, format=%d", e, f);
396 EAPI Ethumb_Thumb_Format
397 ethumb_thumb_format_get(const Ethumb *e)
399 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
404 ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a)
406 EINA_SAFETY_ON_NULL_RETURN(e);
407 EINA_SAFETY_ON_FALSE_RETURN(a == ETHUMB_THUMB_KEEP_ASPECT ||
408 a == ETHUMB_THUMB_IGNORE_ASPECT ||
409 a == ETHUMB_THUMB_CROP);
411 DBG("ethumb=%p, aspect=%d", e, a);
415 EAPI Ethumb_Thumb_Aspect
416 ethumb_thumb_aspect_get(const Ethumb *e)
418 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
423 ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o)
425 EINA_SAFETY_ON_NULL_RETURN(e);
426 EINA_SAFETY_ON_FALSE_RETURN(o == ETHUMB_THUMB_ORIENT_NONE ||
427 o == ETHUMB_THUMB_ROTATE_90_CW ||
428 o == ETHUMB_THUMB_ROTATE_180 ||
429 o == ETHUMB_THUMB_ROTATE_90_CCW ||
430 o == ETHUMB_THUMB_FLIP_HORIZONTAL ||
431 o == ETHUMB_THUMB_FLIP_VERTICAL ||
432 o == ETHUMB_THUMB_FLIP_TRANSPOSE ||
433 o == ETHUMB_THUMB_FLIP_TRANSVERSE ||
434 o == ETHUMB_THUMB_ORIENT_ORIGINAL);
436 DBG("ethumb=%p, orientation=%d", e, o);
440 EAPI Ethumb_Thumb_Orientation
441 ethumb_thumb_orientation_get(const Ethumb *e)
443 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
444 return e->orientation;
448 ethumb_thumb_crop_align_set(Ethumb *e, float x, float y)
450 EINA_SAFETY_ON_NULL_RETURN(e);
452 DBG("ethumb=%p, x=%f, y=%f", e, x, y);
458 ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y)
460 EINA_SAFETY_ON_NULL_RETURN(e);
462 if (x) *x = e->crop_x;
463 if (y) *y = e->crop_y;
467 ethumb_thumb_quality_set(Ethumb *e, int quality)
469 EINA_SAFETY_ON_NULL_RETURN(e);
471 DBG("ethumb=%p, quality=%d", e, quality);
472 e->quality = quality;
476 ethumb_thumb_quality_get(const Ethumb *e)
478 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
483 ethumb_thumb_compress_set(Ethumb *e, int compress)
485 EINA_SAFETY_ON_NULL_RETURN(e);
487 DBG("ethumb=%p, compress=%d", e, compress);
488 e->compress = compress;
492 ethumb_thumb_compress_get(const Ethumb *e)
494 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
499 ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow)
501 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
506 DBG("ethumb=%p, theme_file=%s, group=%s, swallow=%s",
507 e, theme_file ? theme_file : "", group ? group : "",
508 swallow ? swallow : "");
512 edje_object_part_unswallow(frame->edje, e->img);
514 _ethumb_frame_free(frame);
525 frame = calloc(1, sizeof(Ethumb_Frame));
528 ERR("could not allocate Ethumb_Frame structure.");
532 frame->edje = edje_object_add(e->sub_e);
535 ERR("could not create edje frame object.");
536 _ethumb_frame_free(frame);
542 if (!edje_object_file_set(frame->edje, theme_file, group))
544 ERR("could not load frame theme.");
545 _ethumb_frame_free(frame);
550 edje_object_part_swallow(frame->edje, swallow, e->img);
551 if (!edje_object_part_swallow_get(frame->edje, swallow))
553 ERR("could not swallow image to edje frame.");
554 _ethumb_frame_free(frame);
559 eina_stringshare_replace(&frame->file, theme_file);
560 eina_stringshare_replace(&frame->group, group);
561 eina_stringshare_replace(&frame->swallow, swallow);
569 ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow)
571 EINA_SAFETY_ON_NULL_RETURN(e);
575 if (theme_file) *theme_file = e->frame->file;
576 if (group) *group = e->frame->group;
577 if (swallow) *swallow = e->frame->swallow;
581 if (theme_file) *theme_file = NULL;
582 if (group) *group = NULL;
583 if (swallow) *swallow = NULL;
588 _ethumb_build_absolute_path(const char *path, char buf[PATH_MAX])
600 else if (path[0] == '~')
602 const char *home = getenv("HOME");
614 if (!getcwd(p, PATH_MAX))
627 ethumb_thumb_dir_path_set(Ethumb *e, const char *path)
630 EINA_SAFETY_ON_NULL_RETURN(e);
632 DBG("ethumb=%p, path=%s", e, path ? path : "");
633 path = _ethumb_build_absolute_path(path, buf);
634 eina_stringshare_replace(&e->thumb_dir, path);
638 ethumb_thumb_dir_path_get(const Ethumb *e)
640 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
646 ethumb_thumb_category_set(Ethumb *e, const char *category)
648 EINA_SAFETY_ON_NULL_RETURN(e);
650 DBG("ethumb=%p, category=%s", e, category ? category : "");
651 eina_stringshare_replace(&e->category, category);
655 ethumb_thumb_category_get(const Ethumb *e)
657 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
663 ethumb_video_start_set(Ethumb *e, float start)
665 EINA_SAFETY_ON_NULL_RETURN(e);
666 EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);
667 EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);
669 DBG("ethumb=%p, video_start=%f", e, start);
670 e->video.start = start;
674 ethumb_video_start_get(const Ethumb *e)
676 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
678 return e->video.start;
682 ethumb_video_time_set(Ethumb *e, float t)
684 EINA_SAFETY_ON_NULL_RETURN(e);
686 DBG("ethumb=%p, video_start=%f", e, t);
691 ethumb_video_time_get(const Ethumb *e)
693 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
695 return e->video.time;
699 ethumb_video_interval_set(Ethumb *e, float interval)
701 EINA_SAFETY_ON_NULL_RETURN(e);
703 DBG("ethumb=%p, video_interval=%f", e, interval);
704 e->video.interval = interval;
708 ethumb_video_interval_get(const Ethumb *e)
710 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
712 return e->video.interval;
716 ethumb_video_ntimes_set(Ethumb *e, unsigned int ntimes)
718 EINA_SAFETY_ON_NULL_RETURN(e);
719 EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);
721 DBG("ethumb=%p, video_ntimes=%d", e, ntimes);
722 e->video.ntimes = ntimes;
726 ethumb_video_ntimes_get(const Ethumb *e)
728 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
730 return e->video.ntimes;
734 ethumb_video_fps_set(Ethumb *e, unsigned int fps)
736 EINA_SAFETY_ON_NULL_RETURN(e);
737 EINA_SAFETY_ON_FALSE_RETURN(fps > 0);
739 DBG("ethumb=%p, video_fps=%d", e, fps);
744 ethumb_video_fps_get(const Ethumb *e)
746 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
752 ethumb_document_page_set(Ethumb *e, unsigned int page)
754 EINA_SAFETY_ON_NULL_RETURN(e);
756 DBG("ethumb=%p, document_page=%d", e, page);
757 e->document.page = page;
761 ethumb_document_page_get(const Ethumb *e)
763 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
765 return e->document.page;
769 ethumb_file_set(Ethumb *e, const char *path, const char *key)
772 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
774 DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
775 if (path && access(path, R_OK))
777 ERR("couldn't access file \"%s\"", path);
781 path = _ethumb_build_absolute_path(path, buf);
782 eina_stringshare_replace(&e->src_path, path);
783 eina_stringshare_replace(&e->src_key, key);
784 eina_stringshare_replace(&e->thumb_path, NULL);
785 eina_stringshare_replace(&e->thumb_key, NULL);
791 ethumb_file_get(const Ethumb *e, const char **path, const char **key)
793 EINA_SAFETY_ON_NULL_RETURN(e);
795 if (path) *path = e->src_path;
796 if (key) *key = e->src_key;
799 static const char ACCEPTABLE_URI_CHARS[96] = {
800 /* ! " # $ % & ' ( ) * + , - . / */
801 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
802 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
803 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
804 /* @ A B C D E F G H I J K L M N O */
805 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
806 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
807 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
808 /* ` a b c d e f g h i j k l m n o */
809 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
810 /* p q r s t u v w x y z { | } ~ DEL */
811 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
815 _ethumb_generate_hash(const char *file)
819 char md5out[(2 * MD5_HASHBYTES) + 1];
820 unsigned char hash[MD5_HASHBYTES];
821 static const char hex[] = "0123456789abcdef";
825 const unsigned char *c;
827 #define _check_uri_char(c) \
828 ((c) >= 32 && (c) < 128 && (ACCEPTABLE_URI_CHARS[(c) - 32] & 0x08))
830 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
832 uri = alloca(3 * strlen(file) + 9);
833 memcpy(uri, "file://", sizeof("file://") - 1);
834 t = uri + sizeof("file://") - 1;
836 for (c = (const unsigned char *)file; *c != '\0'; c++)
838 if (!_check_uri_char(*c))
849 #undef _check_uri_char
852 MD5Update (&ctx, (unsigned char const*)uri, (unsigned)strlen (uri));
853 MD5Final (hash, &ctx);
855 for (n = 0; n < MD5_HASHBYTES; n++)
857 md5out[2 * n] = hex[hash[n] >> 4];
858 md5out[2 * n + 1] = hex[hash[n] & 0x0f];
860 md5out[2 * n] = '\0';
862 DBG("md5=%s, file=%s", md5out, file);
863 return eina_stringshare_add(md5out);
867 _ethumb_file_check_fdo(Ethumb *e)
869 if (!((e->tw == THUMB_SIZE_NORMAL && e->th == THUMB_SIZE_NORMAL) ||
870 (e->tw == THUMB_SIZE_LARGE && e->th == THUMB_SIZE_LARGE)))
873 if (e->format != ETHUMB_THUMB_FDO)
876 if (e->aspect != ETHUMB_THUMB_KEEP_ASPECT)
886 _ethumb_file_generate_custom_category(Ethumb *e)
889 const char *aspect, *format;
892 if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
893 aspect = "keep_aspect";
894 else if (e->aspect == ETHUMB_THUMB_IGNORE_ASPECT)
895 aspect = "ignore_aspect";
899 if (e->format == ETHUMB_THUMB_FDO)
901 else if (e->format == ETHUMB_THUMB_JPEG)
911 snprintf(buf, sizeof(buf), "%dx%d-%s%s-%s",
912 e->tw, e->th, aspect, frame, format);
914 return eina_stringshare_add(buf);
918 _ethumb_file_generate_path(Ethumb *e)
923 const char *thumb_dir, *category;
928 fdo_format = _ethumb_file_check_fdo(e);
931 thumb_dir = eina_stringshare_ref(e->thumb_dir);
933 thumb_dir = eina_stringshare_ref(_home_thumb_dir);
936 category = eina_stringshare_ref(e->category);
937 else if (!fdo_format)
938 category = _ethumb_file_generate_custom_category(e);
941 if (e->tw == THUMB_SIZE_NORMAL)
942 category = eina_stringshare_ref(_thumb_category_normal);
943 else if (e->tw == THUMB_SIZE_LARGE)
944 category = eina_stringshare_ref(_thumb_category_large);
947 ERR("fdo_format but size %d is not NORMAL (%d) or LARGE (%d)?",
948 e->tw, THUMB_SIZE_NORMAL, THUMB_SIZE_LARGE);
949 category = "unknown";
953 if (e->format == ETHUMB_THUMB_FDO)
955 else if (e->format == ETHUMB_THUMB_JPEG)
961 fullname = ecore_file_realpath(e->src_path);
962 hash = _ethumb_generate_hash(fullname);
963 snprintf(buf, sizeof(buf), "%s/%s/%s.%s", thumb_dir, category, hash, ext);
965 DBG("ethumb=%p, path=%s", e, buf);
966 eina_stringshare_replace(&e->thumb_path, buf);
967 if (e->format == ETHUMB_THUMB_EET)
968 eina_stringshare_replace(&e->thumb_key, "thumbnail");
971 eina_stringshare_del(e->thumb_key);
975 eina_stringshare_del(thumb_dir);
976 eina_stringshare_del(category);
977 eina_stringshare_del(hash);
981 ethumb_file_free(Ethumb *e)
983 EINA_SAFETY_ON_NULL_RETURN(e);
986 eina_stringshare_replace(&e->src_path, NULL);
987 eina_stringshare_replace(&e->src_key, NULL);
988 eina_stringshare_replace(&e->thumb_path, NULL);
989 eina_stringshare_replace(&e->thumb_key, NULL);
993 ethumb_thumb_path_set(Ethumb *e, const char *path, const char *key)
997 EINA_SAFETY_ON_NULL_RETURN(e);
998 DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
1002 eina_stringshare_replace(&e->thumb_path, NULL);
1003 eina_stringshare_replace(&e->thumb_key, NULL);
1007 path = _ethumb_build_absolute_path(path, buf);
1008 eina_stringshare_replace(&e->thumb_path, path);
1009 eina_stringshare_replace(&e->thumb_key, key);
1014 ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key)
1016 EINA_SAFETY_ON_NULL_RETURN(e);
1018 _ethumb_file_generate_path(e);
1020 if (path) *path = e->thumb_path;
1021 if (key) *key = e->thumb_key;
1025 ethumb_calculate_aspect_from_ratio(Ethumb *e, float ia, int *w, int *h)
1035 a = e->tw / (float)e->th;
1037 if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
1039 if ((ia > a && e->tw > 0) || e->th <= 0)
1047 ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h)
1051 ia = iw / (float)ih;
1053 ethumb_calculate_aspect_from_ratio(e, ia, w, h);
1057 ethumb_calculate_fill_from_ratio(Ethumb *e, float ia, int *fx, int *fy, int *fw, int *fh)
1069 a = e->tw / (float)e->th;
1071 if (e->aspect == ETHUMB_THUMB_CROP)
1073 if ((ia > a && e->tw > 0) || e->th <= 0)
1078 *fx = - e->crop_x * (*fw - e->tw);
1079 *fy = - e->crop_y * (*fh - e->th);
1081 else if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
1083 if ((ia > a && e->tw > 0) || e->th <= 0)
1091 ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh)
1094 ia = iw / (float)ih;
1096 ethumb_calculate_fill_from_ratio(e, ia, fx, fy, fw, fh);
1100 _ethumb_plugin_generate(Ethumb *e)
1104 Ethumb_Plugin *plugin;
1107 extp = strrchr(e->src_path, '.');
1110 ERR("could not get extension for file \"%s\"", e->src_path);
1114 for (i = 0; extp[i] != '\0'; i++)
1115 ext[i] = tolower(extp[i + 1]);
1117 plugin = eina_hash_find(_plugins_ext, ext);
1120 DBG("no plugin for extension: \"%s\"", ext);
1125 evas_object_hide(e->frame->edje);
1127 evas_object_hide(e->img);
1129 plugin->generate_thumb(e);
1135 ethumb_plugin_image_resize(Ethumb *e, int w, int h)
1143 edje_extern_object_min_size_set(img, w, h);
1144 edje_extern_object_max_size_set(img, w, h);
1145 edje_object_calc_force(e->frame->edje);
1146 evas_object_move(e->frame->edje, 0, 0);
1147 evas_object_resize(e->frame->edje, w, h);
1151 evas_object_move(img, 0, 0);
1152 evas_object_resize(img, w, h);
1155 evas_object_image_size_set(e->o, w, h);
1156 ecore_evas_resize(e->sub_ee, w, h);
1165 ethumb_image_save(Ethumb *e)
1171 evas_damage_rectangle_add(e->sub_e, 0, 0, e->rw, e->rh);
1172 evas_render(e->sub_e);
1175 _ethumb_file_generate_path(e);
1179 ERR("could not create file path...");
1183 dname = ecore_file_dir_get(e->thumb_path);
1184 r = ecore_file_mkpath(dname);
1188 ERR("could not create directory '%s'", dname);
1192 snprintf(flags, sizeof(flags), "quality=%d compress=%d",
1193 e->quality, e->compress);
1194 r = evas_object_image_save(e->o, e->thumb_path, e->thumb_key, flags);
1198 ERR("could not save image: path=%s, key=%s", e->thumb_path,
1207 _ethumb_image_orient(Ethumb *e, int orientation)
1209 Evas_Object *img = e->img, *tmp;
1210 unsigned int *data, *data2, *to, *from, *p1, *p2, pt;
1211 int x, y, w, hw, iw, ih, tw, th;
1212 const char *file, *key;
1214 evas_object_image_size_get(img, &iw, &ih);
1215 data = evas_object_image_data_get(img, 1);
1217 switch (orientation)
1219 case ETHUMB_THUMB_FLIP_HORIZONTAL:
1220 for (y = 0; y < ih; y++)
1222 p1 = data + (y * iw);
1223 p2 = data + ((y + 1) * iw) - 1;
1224 for (x = 0; x < (iw >> 1); x++)
1233 evas_object_image_data_set(img, data);
1234 evas_object_image_data_update_add(img, 0, 0, iw, ih);
1236 case ETHUMB_THUMB_FLIP_VERTICAL:
1237 for (y = 0; y < (ih >> 1); y++)
1239 p1 = data + (y * iw);
1240 p2 = data + ((ih - 1 - y) * iw);
1241 for (x = 0; x < iw; x++)
1250 evas_object_image_data_set(img, data);
1251 evas_object_image_data_update_add(img, 0, 0, iw, ih);
1253 case ETHUMB_THUMB_ROTATE_180:
1266 evas_object_image_data_set(img, data);
1267 evas_object_image_data_update_add(img, 0, 0, iw, ih);
1271 evas_object_image_load_size_get(img, &tw, &th);
1272 evas_object_image_file_get(img, &file, &key);
1273 tmp = evas_object_image_add(evas_object_evas_get(img));
1274 evas_object_image_load_size_set(tmp, tw, th);
1275 evas_object_image_file_set(tmp, file, key);
1276 data2 = evas_object_image_data_get(tmp, 0);
1283 evas_object_image_size_set(img, iw, ih);
1284 data = evas_object_image_data_get(img, 1);
1286 switch (orientation)
1288 case ETHUMB_THUMB_FLIP_TRANSPOSE:
1292 case ETHUMB_THUMB_FLIP_TRANSVERSE:
1297 case ETHUMB_THUMB_ROTATE_90_CW:
1301 case ETHUMB_THUMB_ROTATE_90_CCW:
1307 ERR("unknown orient %d", orientation);
1308 evas_object_del(tmp);
1309 evas_object_image_data_set(img, data); // give it back
1313 for (x = iw; --x >= 0;)
1315 for (y = ih; --y >= 0;)
1323 evas_object_del(tmp);
1324 evas_object_image_data_set(img, data);
1325 evas_object_image_data_update_add(img, 0, 0, iw, ih);
1329 _ethumb_image_load(Ethumb *e)
1332 Evas_Coord w, h, ww, hh, fx, fy, fw, fh;
1334 int orientation = ETHUMB_THUMB_ORIENT_NONE;
1339 evas_object_hide(e->frame->edje);
1341 evas_object_hide(img);
1342 evas_object_image_file_set(img, NULL, NULL);
1343 evas_object_image_load_size_set(img, e->tw, e->th);
1344 evas_object_image_file_set(img, e->src_path, e->src_key);
1347 evas_object_show(e->frame->edje);
1349 evas_object_show(img);
1351 error = evas_object_image_load_error_get(img);
1352 if (error != EVAS_LOAD_ERROR_NONE)
1354 ERR("could not load image '%s': %d", e->src_path, error);
1358 if (e->orientation == ETHUMB_THUMB_ORIENT_ORIGINAL)
1361 ExifData *exif = exif_data_new_from_file(e->src_path);
1362 ExifEntry *entry = NULL;
1368 entry = exif_data_get_entry(exif, EXIF_TAG_ORIENTATION);
1371 bo = exif_data_get_byte_order(exif);
1372 o = exif_get_short(entry->data, bo);
1374 exif_data_free(exif);
1378 orientation = ETHUMB_THUMB_FLIP_HORIZONTAL;
1381 orientation = ETHUMB_THUMB_ROTATE_180;
1384 orientation = ETHUMB_THUMB_FLIP_VERTICAL;
1387 orientation = ETHUMB_THUMB_FLIP_TRANSPOSE;
1390 orientation = ETHUMB_THUMB_ROTATE_90_CW;
1393 orientation = ETHUMB_THUMB_FLIP_TRANSVERSE;
1396 orientation = ETHUMB_THUMB_ROTATE_90_CCW;
1403 if (orientation != ETHUMB_THUMB_ORIENT_NONE)
1404 _ethumb_image_orient(e, orientation);
1406 evas_object_image_size_get(img, &w, &h);
1407 if ((w <= 0) || (h <= 0))
1410 ethumb_calculate_aspect(e, w, h, &ww, &hh);
1414 edje_extern_object_min_size_set(img, ww, hh);
1415 edje_extern_object_max_size_set(img, ww, hh);
1416 edje_object_calc_force(e->frame->edje);
1417 evas_object_move(e->frame->edje, 0, 0);
1418 evas_object_resize(e->frame->edje, ww, hh);
1422 evas_object_move(img, 0, 0);
1423 evas_object_resize(img, ww, hh);
1426 ethumb_calculate_fill(e, w, h, &fx, &fy, &fw, &fh);
1427 evas_object_image_fill_set(img, fx, fy, fw, fh);
1429 evas_object_image_size_set(e->o, ww, hh);
1430 ecore_evas_resize(e->sub_ee, ww, hh);
1439 _ethumb_finished_idler_cb(void *data)
1443 e->finished_cb(e->cb_data, e, e->cb_result);
1444 if (e->cb_data_free)
1445 e->cb_data_free(e->cb_data);
1446 e->finished_idler = NULL;
1447 e->finished_cb = NULL;
1449 e->cb_data_free = NULL;
1455 ethumb_finished_callback_call(Ethumb *e, int result)
1457 EINA_SAFETY_ON_NULL_RETURN(e);
1459 e->cb_result = result;
1460 if (e->finished_idler)
1461 ecore_idler_del(e->finished_idler);
1462 e->finished_idler = ecore_idler_add(_ethumb_finished_idler_cb, e);
1466 ethumb_generate(Ethumb *e, Ethumb_Generate_Cb finished_cb, const void *data, Eina_Free_Cb free_data)
1470 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
1471 EINA_SAFETY_ON_NULL_RETURN_VAL(finished_cb, 0);
1472 DBG("ethumb=%p, finished_cb=%p, data=%p, free_data=%p, path=%s, key=%s",
1473 e, finished_cb, data, free_data,
1474 e->src_path ? e->src_path : "", e->src_key ? e->src_key : "");
1476 if (e->finished_idler)
1478 ERR("thumbnail generation already in progress.");
1481 e->finished_cb = finished_cb;
1482 e->cb_data = (void *)data;
1483 e->cb_data_free = free_data;
1487 ERR("no file set.");
1488 ethumb_finished_callback_call(e, 0);
1492 r = _ethumb_plugin_generate(e);
1496 if (!_ethumb_image_load(e))
1498 ERR("could not load input image.");
1499 ethumb_finished_callback_call(e, 0);
1503 r = ethumb_image_save(e);
1505 ethumb_finished_callback_call(e, r);
1511 ethumb_exists(Ethumb *e)
1513 struct stat thumb, src;
1515 Eina_Bool r = EINA_FALSE;
1517 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
1518 EINA_SAFETY_ON_NULL_RETURN_VAL(e->src_path, 0);
1519 DBG("ethumb=%p, path=%s", e, e->src_path ? e->src_path : "");
1522 _ethumb_file_generate_path(e);
1524 EINA_SAFETY_ON_NULL_RETURN_VAL(e->thumb_path, 0);
1526 r_thumb = stat(e->thumb_path, &thumb);
1527 r_src = stat(e->src_path, &src);
1529 EINA_SAFETY_ON_TRUE_RETURN_VAL(r_src, 0);
1531 if (r_thumb && errno != ENOENT)
1532 ERR("could not access file \"%s\": %s", e->thumb_path, strerror(errno));
1533 else if (!r_thumb && thumb.st_mtime > src.st_mtime)
1540 ethumb_evas_get(const Ethumb *e)
1542 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
1548 ethumb_ecore_evas_get(const Ethumb *e)
1550 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
1556 ethumb_dup(const Ethumb *e)
1566 r = malloc(sizeof (Ethumb));
1567 if (!r) return NULL;
1569 memcpy(r, e, sizeof (Ethumb));
1571 r->thumb_dir = eina_stringshare_ref(e->thumb_dir);
1572 r->category = eina_stringshare_ref(e->category);
1573 r->src_path = eina_stringshare_ref(e->src_path);
1574 r->src_key = eina_stringshare_ref(e->src_key);
1575 r->thumb_path = eina_stringshare_ref(e->thumb_path);
1576 r->thumb_key = eina_stringshare_ref(e->thumb_key);
1578 ee = ecore_evas_buffer_new(1, 1);
1579 ev = ecore_evas_get(ee);
1582 ERR("could not create ecore evas buffer");
1587 evas_image_cache_set(ev, 0);
1588 evas_font_cache_set(ev, 0);
1590 o = ecore_evas_object_image_new(ee);
1593 ERR("could not create sub ecore evas buffer");
1594 ecore_evas_free(ee);
1599 sub_ee = ecore_evas_object_ecore_evas_get(o);
1600 sub_ev = ecore_evas_object_evas_get(o);
1602 evas_image_cache_set(sub_ev, 0);
1603 evas_font_cache_set(sub_ev, 0);
1605 img = evas_object_image_add(sub_ev);
1608 ERR("could not create source objects.");
1609 ecore_evas_free(ee);
1622 r->finished_idler = NULL;
1623 r->finished_cb = NULL;
1625 r->cb_data_free = NULL;
1631 #define CHECK_DELTA(Param) \
1632 if (e1->Param != e2->Param) \
1636 ethumb_cmp(const Ethumb *e1, const Ethumb *e2)
1638 CHECK_DELTA(thumb_dir);
1639 CHECK_DELTA(category);
1642 CHECK_DELTA(format);
1643 CHECK_DELTA(aspect);
1644 CHECK_DELTA(orientation);
1645 CHECK_DELTA(crop_x);
1646 CHECK_DELTA(crop_y);
1647 CHECK_DELTA(quality);
1648 CHECK_DELTA(compress);
1651 CHECK_DELTA(video.start);
1652 CHECK_DELTA(video.time);
1653 CHECK_DELTA(video.interval);
1654 CHECK_DELTA(video.ntimes);
1655 CHECK_DELTA(video.fps);
1656 CHECK_DELTA(document.page);