summaryrefslogtreecommitdiff
path: root/src/lib/ethumb
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2013-01-12 01:15:45 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2013-01-12 01:15:45 +0000
commit34f53151414bcdf44ec81e582b007f74da595694 (patch)
tree863058f0d94e9d39998774a375aa6d242d8714a4 /src/lib/ethumb
parentae51833bac7ba5f72bd40a96beb13081c8d573f6 (diff)
merge ethumb.
This one was a painful bitch. The edbus2 port was quite broken, mainly leaking eina_stringshare and also not adding the '\0' to the strings that are represented as bytearray (paths cannot be utf8 to avoid translations). Emotion plugin was also quite bogus and the video thumbnail as edje (animated) is not working yet due bug in Edje_Edit api -- someone needs to investigate this, seems strange. Emotion plugin also had a bug that it was deleting the object from inside object callback. Now it seems to work. Please report if it does not. SVN revision: 82675
Diffstat (limited to 'src/lib/ethumb')
-rw-r--r--src/lib/ethumb/Ethumb.h279
-rw-r--r--src/lib/ethumb/Ethumb_Plugin.h27
-rw-r--r--src/lib/ethumb/client/Ethumb_Client.h220
-rw-r--r--src/lib/ethumb/client/ethumb_client.c2251
-rw-r--r--src/lib/ethumb/ethumb.c1863
-rw-r--r--src/lib/ethumb/ethumb_private.h57
-rw-r--r--src/lib/ethumb/md5.c251
-rw-r--r--src/lib/ethumb/md5.h24
8 files changed, 4972 insertions, 0 deletions
diff --git a/src/lib/ethumb/Ethumb.h b/src/lib/ethumb/Ethumb.h
new file mode 100644
index 0000000000..fd4dff708a
--- /dev/null
+++ b/src/lib/ethumb/Ethumb.h
@@ -0,0 +1,279 @@
1#ifndef __ETHUMB_H__
2#define __ETHUMB_H__ 1
3
4#include <Eina.h>
5
6#ifdef EAPI
7# undef EAPI
8#endif
9
10#ifdef _WIN32
11# ifdef EFL_ETHUMB_BUILD
12# ifdef DLL_EXPORT
13# define EAPI __declspec(dllexport)
14# else
15# define EAPI
16# endif /* ! DLL_EXPORT */
17# else
18# define EAPI __declspec(dllimport)
19# endif /* ! EFL_ETHUMB_BUILD */
20#else
21# ifdef __GNUC__
22# if __GNUC__ >= 4
23# define EAPI __attribute__ ((visibility("default")))
24# else
25# define EAPI
26# endif
27# else
28# define EAPI
29# endif
30#endif /* ! _WIN32 */
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36#define ETHUMB_VERSION_MAJOR 1
37#define ETHUMB_VERSION_MINOR 8
38
39 typedef struct _Ethumb_Version
40 {
41 int major;
42 int minor;
43 int micro;
44 int revision;
45 } Ethumb_Version;
46
47 EAPI extern Ethumb_Version *ethumb_version;
48
49/**
50 * @page ethumb_main Ethumb
51 *
52 * @date 2009 (created)
53 *
54 * @section toc Table of Contents
55 *
56 * @li @ref ethumb_main_intro
57 * @li @ref ethumb_main_compiling
58 * @li @ref ethumb_main_next_steps
59 *
60 * @section ethumb_main_intro Introduction
61 *
62 * Ethumb will use @ref Evas to generate thumbnail images of given
63 * files. The API allows great customization of the generated files
64 * and also helps compling to FreeDesktop.Org Thumbnail Specification
65 * (http://specifications.freedesktop.org/thumbnail-spec/thumbnail-spec-latest.html)
66 *
67 * However, thumbnailing can be an expensive process that will impact
68 * your application experience, blocking animations and user
69 * interaction during the generation. Another problem is that one
70 * should try to cache the thumbnails in a place that other
71 * applications can benefit from the file.
72 *
73 * @ref Ethumb_Client exists to solve this. It will communicate with a
74 * server using standard D-Bus protocol. The server will use @ref
75 * Ethumb itself to generate the thumbnail images and cache them using
76 * FreeDesktop.Org standard. It is recommended that most applications
77 * use @ref Ethumb_Client instead of @ref Ethumb directly.
78 *
79 * @section ethumb_main_compiling How to compile
80 *
81 * Ethumb is a library your application links to. The procedure for
82 * this is very simple. Note that usually you want the D-Bus client
83 * library. You simply have to compile your application with the
84 * appropriate compiler flags that the @c pkg-config script
85 * outputs. For example:
86 *
87 * Compiling C or C++ files into object files:
88 *
89 * @verbatim
90 gcc -c -o main.o main.c `pkg-config --cflags ethumb_client`
91 @endverbatim
92 *
93 * Linking object files into a binary executable:
94 *
95 * @verbatim
96 gcc -o my_application main.o `pkg-config --libs ethumb_client`
97 @endverbatim
98 *
99 * See @ref pkgconfig
100 *
101 * @section ethumb_main_next_steps Next Steps
102 *
103 * After you understood what Ethumb is and installed it in your system
104 * you should proceed understanding the programming interface.
105 *
106 * Recommended reading:
107 *
108 * @li @ref Ethumb_Client to generate thumbnails using a server
109 * (recommended).
110 * @li @ref Ethumb to generate thumbnails in the local process.
111 *
112 */
113
114/**
115 * @defgroup Ethumb Ethumb
116 *
117 * @{
118 */
119/**
120 * @defgroup Ethumb_Basics Ethumb Basics
121 *
122 * Functions that all users must know of to use Ethumb.
123 *
124 * @{
125 */
126
127/**
128 * @brief thumbnailer handle.
129 *
130 * The handle is returned by ethumb_new() and destroyed by ethumb_free().
131 */
132typedef struct _Ethumb Ethumb;
133
134/**
135 * @brief reports results of ethumb_generate().
136 *
137 * @param data extra context given to ethumb_generate().
138 * @param e handle of the current thumbnailer.
139 * @param success @c EINA_TRUE if generated or @c EINA_FALSE on errors.
140 */
141typedef void (*Ethumb_Generate_Cb)(void *data, Ethumb *e, Eina_Bool success);
142
143EAPI int ethumb_init(void);
144EAPI int ethumb_shutdown(void);
145
146EAPI Ethumb * ethumb_new(void) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
147EAPI void ethumb_free(Ethumb *e);
148
149/**
150 * @}
151 */
152
153/**
154 * @defgroup Ethumb_Setup Ethumb Fine Tune Setup
155 *
156 * How to fine tune thumbnail generation, setting size, aspect,
157 * frames, quality and so on.
158 *
159 * @{
160 */
161
162EAPI Eina_Bool ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow) EINA_ARG_NONNULL(1);
163EAPI void ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow) EINA_ARG_NONNULL(1);
164
165EAPI void ethumb_thumb_dir_path_set(Ethumb *e, const char *path) EINA_ARG_NONNULL(1);
166EAPI const char *ethumb_thumb_dir_path_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
167
168EAPI void ethumb_thumb_category_set(Ethumb *e, const char *category) EINA_ARG_NONNULL(1);
169EAPI const char *ethumb_thumb_category_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
170
171EAPI void ethumb_thumb_path_set(Ethumb *e, const char *path, const char *key) EINA_ARG_NONNULL(1);
172EAPI void ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key) EINA_ARG_NONNULL(1);
173EAPI void ethumb_thumb_hash(Ethumb *e) EINA_ARG_NONNULL(1);
174EAPI void ethumb_thumb_hash_copy(Ethumb *dst, const Ethumb *src) EINA_ARG_NONNULL(1, 2);
175
176typedef enum _Ethumb_Thumb_FDO_Size
177{
178 ETHUMB_THUMB_NORMAL, /**< 128x128 as defined by FreeDesktop.Org standard */
179 ETHUMB_THUMB_LARGE /**< 256x256 as defined by FreeDesktop.Org standard */
180} Ethumb_Thumb_FDO_Size;
181
182typedef enum _Ethumb_Thumb_Format
183{
184 ETHUMB_THUMB_FDO, /**< PNG as defined by FreeDesktop.Org standard */
185 ETHUMB_THUMB_JPEG, /**< JPEGs are often smaller and faster to read/write */
186 ETHUMB_THUMB_EET /**< EFL's own storage system, supports key parameter */
187} Ethumb_Thumb_Format;
188
189typedef enum _Ethumb_Thumb_Aspect
190{
191 ETHUMB_THUMB_KEEP_ASPECT, /**< keep original proportion between width and height */
192 ETHUMB_THUMB_IGNORE_ASPECT, /**< ignore aspect and foce it to match thumbnail's width and height */
193 ETHUMB_THUMB_CROP /**< keep aspect but crop (cut) the largest dimension */
194} Ethumb_Thumb_Aspect;
195
196typedef enum _Ethumb_Thumb_Orientation
197{
198 ETHUMB_THUMB_ORIENT_NONE, /**< keep orientation as pixel data is */
199 ETHUMB_THUMB_ROTATE_90_CW, /**< rotate 90° clockwise */
200 ETHUMB_THUMB_ROTATE_180, /**< rotate 180° */
201 ETHUMB_THUMB_ROTATE_90_CCW, /**< rotate 90° counter-clockwise */
202 ETHUMB_THUMB_FLIP_HORIZONTAL, /**< flip horizontally */
203 ETHUMB_THUMB_FLIP_VERTICAL, /**< flip vertically */
204 ETHUMB_THUMB_FLIP_TRANSPOSE, /**< transpose */
205 ETHUMB_THUMB_FLIP_TRANSVERSE, /**< transverse */
206 ETHUMB_THUMB_ORIENT_ORIGINAL /**< use orientation from metadata (EXIF-only currently) */
207} Ethumb_Thumb_Orientation;
208
209EAPI void ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s) EINA_ARG_NONNULL(1);
210
211EAPI void ethumb_thumb_size_set(Ethumb *e, int tw, int th) EINA_ARG_NONNULL(1);
212EAPI void ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th) EINA_ARG_NONNULL(1);
213
214EAPI void ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f) EINA_ARG_NONNULL(1);
215EAPI Ethumb_Thumb_Format ethumb_thumb_format_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
216
217EAPI void ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a) EINA_ARG_NONNULL(1);
218EAPI Ethumb_Thumb_Aspect ethumb_thumb_aspect_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
219
220EAPI void ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o) EINA_ARG_NONNULL(1);
221EAPI Ethumb_Thumb_Orientation ethumb_thumb_orientation_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
222
223EAPI void ethumb_thumb_crop_align_set(Ethumb *e, float x, float y) EINA_ARG_NONNULL(1);
224EAPI void ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y) EINA_ARG_NONNULL(1);
225
226EAPI void ethumb_thumb_quality_set(Ethumb *e, int quality) EINA_ARG_NONNULL(1);
227EAPI int ethumb_thumb_quality_get(const Ethumb *e) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
228
229EAPI void ethumb_thumb_compress_set(Ethumb *e, int compress) EINA_ARG_NONNULL(1);
230EAPI int ethumb_thumb_compress_get(const Ethumb *e) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
231
232EAPI void ethumb_video_start_set(Ethumb *e, float start) EINA_ARG_NONNULL(1);
233EAPI float ethumb_video_start_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
234EAPI void ethumb_video_time_set(Ethumb *e, float time) EINA_ARG_NONNULL(1);
235EAPI float ethumb_video_time_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
236EAPI void ethumb_video_interval_set(Ethumb *e, float interval) EINA_ARG_NONNULL(1);
237EAPI float ethumb_video_interval_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
238EAPI void ethumb_video_ntimes_set(Ethumb *e, unsigned int ntimes) EINA_ARG_NONNULL(1);
239EAPI unsigned int ethumb_video_ntimes_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
240EAPI void ethumb_video_fps_set(Ethumb *e, unsigned int fps) EINA_ARG_NONNULL(1);
241EAPI unsigned int ethumb_video_fps_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
242
243
244EAPI void ethumb_document_page_set(Ethumb *e, unsigned int page) EINA_ARG_NONNULL(1);
245EAPI unsigned int ethumb_document_page_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
246/**
247 * @}
248 */
249
250/**
251 * @addtogroup Ethumb_Basics Ethumb Basics
252 * @{
253 */
254EAPI Eina_Bool ethumb_file_set(Ethumb *e, const char *path, const char *key) EINA_ARG_NONNULL(1, 2);
255EAPI void ethumb_file_get(const Ethumb *e, const char **path, const char **key) EINA_ARG_NONNULL(1);
256EAPI void ethumb_file_free(Ethumb *e) EINA_ARG_NONNULL(1);
257
258EAPI Eina_Bool ethumb_generate(Ethumb *e, Ethumb_Generate_Cb finished_cb, const void *data, Eina_Free_Cb free_data) EINA_ARG_NONNULL(1, 2);
259EAPI Eina_Bool ethumb_exists(Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
260
261EAPI Ethumb *ethumb_dup(const Ethumb *e) EINA_ARG_NONNULL(1);
262EAPI Eina_Bool ethumb_cmp(const Ethumb *e1, const Ethumb *e2) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT EINA_PURE;
263EAPI int ethumb_hash(const void *key, int key_length) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
264EAPI int ethumb_key_cmp(const void *key1, int key1_length,
265 const void *key2, int key2_length) EINA_ARG_NONNULL(1, 3) EINA_WARN_UNUSED_RESULT EINA_PURE;
266EAPI unsigned int ethumb_length(const void *key) EINA_PURE EINA_WARN_UNUSED_RESULT;
267
268 /**
269 * @}
270 */
271
272/**
273 * @}
274 */
275
276#ifdef __cplusplus
277}
278#endif
279#endif /* __ETHUMB_H__ */
diff --git a/src/lib/ethumb/Ethumb_Plugin.h b/src/lib/ethumb/Ethumb_Plugin.h
new file mode 100644
index 0000000000..3eb6f020cd
--- /dev/null
+++ b/src/lib/ethumb/Ethumb_Plugin.h
@@ -0,0 +1,27 @@
1#ifndef _ETHUMB_PLUGIN_H_
2#define _ETHUMB_PLUGIN_H_
3
4#include <Evas.h>
5#include <Ecore_Evas.h>
6#include <Ethumb.h>
7
8typedef struct _Ethumb_Plugin Ethumb_Plugin;
9
10struct _Ethumb_Plugin
11{
12 const char **extensions;
13 void *(*thumb_generate)(Ethumb *);
14 void (*thumb_cancel)(Ethumb *, void *);
15};
16
17EAPI void ethumb_calculate_aspect_from_ratio(Ethumb *e, float ia, int *w, int *h);
18EAPI void ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h);
19EAPI void ethumb_calculate_fill_from_ratio(Ethumb *e, float ia, int *fx, int *fy, int *fw, int *fh);
20EAPI void ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh);
21EAPI Eina_Bool ethumb_plugin_image_resize(Ethumb *e, int w, int h);
22EAPI Eina_Bool ethumb_image_save(Ethumb *e);
23EAPI void ethumb_finished_callback_call(Ethumb *e, int result);
24EAPI Evas * ethumb_evas_get(const Ethumb *e);
25EAPI Ecore_Evas * ethumb_ecore_evas_get(const Ethumb *e);
26
27#endif /* _ETHUMB_PLUGIN_H_ */
diff --git a/src/lib/ethumb/client/Ethumb_Client.h b/src/lib/ethumb/client/Ethumb_Client.h
new file mode 100644
index 0000000000..3c3f95d87e
--- /dev/null
+++ b/src/lib/ethumb/client/Ethumb_Client.h
@@ -0,0 +1,220 @@
1#ifndef __ETHUMB_CLIENT_H__
2#define __ETHUMB_CLIENT_H__ 1
3
4#include <Ethumb.h>
5
6#ifdef EAPI
7# undef EAPI
8#endif
9
10#ifdef _WIN32
11# ifdef EFL_ETHUMB_CLIENT_BUILD
12# ifdef DLL_EXPORT
13# define EAPI __declspec(dllexport)
14# else
15# define EAPI
16# endif /* ! DLL_EXPORT */
17# else
18# define EAPI __declspec(dllimport)
19# endif /* ! EFL_ETHUMB_CLIENT_BUILD */
20#else
21# ifdef __GNUC__
22# if __GNUC__ >= 4
23# define EAPI __attribute__ ((visibility("default")))
24# else
25# define EAPI
26# endif
27# else
28# define EAPI
29# endif
30#endif /* ! _WIN32 */
31
32#ifdef __cplusplus
33extern "C" {
34#endif
35
36/**
37 * @defgroup Ethumb_Client Ethumb Client
38 * @ingroup Ethumb
39 *
40 * @{
41 */
42
43/**
44 * @defgroup Ethumb_Client_Basics Ethumb Client Basics
45 *
46 * Functions that all users must know of to use Ethumb_Client.
47 *
48 * @{
49 */
50
51/**
52 * @brief client handle.
53 *
54 * The client handle is created by ethumb_client_connect() and
55 * destroyed by ethumb_client_disconnect(). The connection and
56 * requests are asynchronous and callbacks should be used to report
57 * both success and failure of calls.
58 */
59typedef struct _Ethumb_Client Ethumb_Client;
60
61/**
62 * @brief client exists request handle.
63 *
64 * The exists request handle is created by ethumb_client_thumb_exists(),
65 * automatically destroyed when it end and cancelled when requested by
66 * ethumb_client_thumb_exists_cancel().
67 */
68typedef struct _Ethumb_Exists Ethumb_Exists;
69
70/**
71 * @brief reports results of ethumb_client_connect()
72 *
73 * @param data extra context given to ethumb_client_connect().
74 * @param client handle of the current connection to server.
75 * @param success @c EINA_TRUE if connected or @c EINA_FALSE if it was
76 * not possible.
77 */
78typedef void (*Ethumb_Client_Connect_Cb)(void *data, Ethumb_Client *client, Eina_Bool success);
79
80/**
81 * @brief reports server connection ended.
82 *
83 * Functions of this type may be called if they are set with
84 * ethumb_client_on_server_die_callback_set().
85 *
86 * @param data extra context given to ethumb_client_on_server_die_callback_set().
87 * @param client handle of the current connection to server.
88 */
89typedef void (*Ethumb_Client_Die_Cb)(void *data, Ethumb_Client *client);
90
91/**
92 * @brief reports results of ethumb_client_generate().
93 *
94 * @param data extra context given to ethumb_client_generate().
95 * @param client handle of the current connection to server.
96 * @param id identifier returned by ethumb_client_generate().
97 * @param file path set with ethumb_client_file_set().
98 * @param key value set with ethumb_client_file_set() or @c NULL.
99 * @param thumb_path where thumbnail was stored, either set with
100 * ethumb_client_thumb_path_set() or automatically calculated
101 * using parameters.
102 * @param thumb_key key inside thumb_path where thumbnail was stored or @c NULL.
103 * @param success @c EINA_TRUE if generated or @c EINA_FALSE on errors.
104 */
105typedef void (*Ethumb_Client_Generate_Cb)(void *data, Ethumb_Client *client, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success);
106
107/**
108 * @brief report results of ethumb_client_thumb_exists().
109 *
110 * @param client handle of the current connection to server.
111 * @param exists EINA_TRUE if the thumbnail exists.
112 * @param data extra context given to ethumb_client_thumb_exists().
113 *
114 * During the execution of the callback the state of the @p client is
115 * temporarily realy restored to what it was when the call to
116 * ethumb_client_thumb_exists() was done.
117 */
118typedef void (*Ethumb_Client_Thumb_Exists_Cb)(void *data, Ethumb_Client *client, Ethumb_Exists *thread, Eina_Bool exists);
119
120/**
121 * @brief reports results of ethumb_client_generate_cancel()
122 *
123 * @param data extra context given to ethumb_client_generate_cancel()
124 * @param client handle of the current connection to server.
125 */
126typedef void (*Ethumb_Client_Generate_Cancel_Cb)(void *data, Eina_Bool success);
127
128EAPI int ethumb_client_init(void);
129EAPI int ethumb_client_shutdown(void);
130
131EAPI Ethumb_Client *ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_data);
132EAPI void ethumb_client_disconnect(Ethumb_Client *client);
133EAPI void ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data);
134
135/**
136 * @}
137 */
138
139/**
140 * @defgroup Ethumb_Client_Setup Ethumb Client Fine Tune Setup
141 *
142 * How to fine tune thumbnail generation, setting size, aspect, orientation,
143 * frames, quality and so on.
144 *
145 * @{
146 */
147
148EAPI void ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s);
149EAPI void ethumb_client_size_set(Ethumb_Client *client, int tw, int th);
150EAPI void ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th);
151EAPI void ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f);
152EAPI Ethumb_Thumb_Format ethumb_client_format_get(const Ethumb_Client *client);
153EAPI void ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a);
154EAPI Ethumb_Thumb_Aspect ethumb_client_aspect_get(const Ethumb_Client *client);
155EAPI void ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o);
156EAPI Ethumb_Thumb_Orientation ethumb_client_orientation_get(const Ethumb_Client *client);
157EAPI void ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y);
158EAPI void ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y);
159EAPI void ethumb_client_quality_set(Ethumb_Client *client, int quality);
160EAPI int ethumb_client_quality_get(const Ethumb_Client *client);
161EAPI void ethumb_client_compress_set(Ethumb_Client *client, int compress);
162EAPI int ethumb_client_compress_get(const Ethumb_Client *client);
163EAPI Eina_Bool ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow);
164EAPI void ethumb_client_dir_path_set(Ethumb_Client *client, const char *path);
165EAPI const char * ethumb_client_dir_path_get(const Ethumb_Client *client);
166EAPI void ethumb_client_category_set(Ethumb_Client *client, const char *category);
167EAPI const char * ethumb_client_category_get(const Ethumb_Client *client);
168EAPI void ethumb_client_video_time_set(Ethumb_Client *client, float time);
169EAPI void ethumb_client_video_start_set(Ethumb_Client *client, float start);
170EAPI void ethumb_client_video_interval_set(Ethumb_Client *client, float interval);
171EAPI void ethumb_client_video_ntimes_set(Ethumb_Client *client, unsigned int ntimes);
172EAPI void ethumb_client_video_fps_set(Ethumb_Client *client, unsigned int fps);
173EAPI void ethumb_client_document_page_set(Ethumb_Client *client, unsigned int page);
174
175EAPI void ethumb_client_ethumb_setup(Ethumb_Client *client);
176
177EAPI void ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key);
178EAPI void ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key);
179/**
180 * @}
181 */
182
183/**
184 * @addtogroup Ethumb_Client_Basics Ethumb Client Basics
185 * @{
186 */
187EAPI Eina_Bool ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key);
188EAPI void ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key);
189EAPI void ethumb_client_file_free(Ethumb_Client *client);
190
191EAPI Ethumb_Exists *ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data);
192EAPI void ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists);
193EAPI Eina_Bool ethumb_client_thumb_exists_check(Ethumb_Exists *exists);
194EAPI int ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data);
195EAPI void ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data);
196EAPI void ethumb_client_generate_cancel_all(Ethumb_Client *client);
197
198typedef void (*Ethumb_Client_Async_Done_Cb)(Ethumb_Client *ethumbd, const char *thumb_path, const char *thumb_key, void *data);
199typedef void (*Ethumb_Client_Async_Error_Cb)(Ethumb_Client *ethumbd, void *data);
200
201typedef struct _Ethumb_Client_Async Ethumb_Client_Async;
202
203EAPI Ethumb_Client_Async *ethumb_client_thumb_async_get(Ethumb_Client *client,
204 Ethumb_Client_Async_Done_Cb done,
205 Ethumb_Client_Async_Error_Cb error,
206 const void *data);
207EAPI void ethumb_client_thumb_async_cancel(Ethumb_Client *client, Ethumb_Client_Async *request);
208 /**
209 * @}
210 */
211
212/**
213 * @}
214 */
215
216
217#ifdef __cplusplus
218}
219#endif
220#endif /* __ETHUMB_CLIENT_H__ */
diff --git a/src/lib/ethumb/client/ethumb_client.c b/src/lib/ethumb/client/ethumb_client.c
new file mode 100644
index 0000000000..7b9836625f
--- /dev/null
+++ b/src/lib/ethumb/client/ethumb_client.c
@@ -0,0 +1,2251 @@
1/**
2 * @file
3 *
4 * This is the client-server thumbnail library, see @ref
5 * tutorial_ethumb_client.
6 *
7 * Copyright (C) 2009 by ProFUSION embedded systems
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library;
21 * if not, see <http://www.gnu.org/licenses/>.
22 *
23 * @author Rafael Antognolli <antognolli@profusion.mobi>
24 * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
25 */
26
27/**
28 * @page tutorial_ethumb_client Client-Server Thumbnailing Tutorial
29 *
30 * @section tutorial_ethumb_client_intro Introduction
31 *
32 * Ethumb provides both in process and client-server generation
33 * methods. The advantage of the client-server method is that current
34 * process will not do the heavy operations that may block, stopping
35 * animations and other user interactions. Instead the client library
36 * will configure a local #Ethumb instance and mirrors/controls a
37 * remote process using DBus. The simple operations like most setters
38 * and getters as well as checking for thumbnail existence
39 * (ethumb_client_thumb_exists()) is done locally, while expensive
40 * (ethumb_client_generate()) are done on server and then reported
41 * back to application when it is finished (both success or failure).
42 *
43 * @section tutorial_ethumb_client_connect Connecting to Server
44 *
45 * TODO
46 *
47 * @section tutorial_ethumb_client_generate Requesting Thumbnail Generation
48 *
49 * TODO
50 *
51 * @section tutorial_ethumb_client_setup Setup Extra Thumbnail Parameters
52 *
53 * TODO
54 *
55 * @section tutorial_ethumb_client_server_died Handle Server Disconnection
56 *
57 * TODO
58 */
59
60/**
61 * @cond LOCAL
62 */
63
64#ifdef HAVE_CONFIG_H
65# include "config.h"
66#endif
67
68#include <stdio.h>
69#include <stdlib.h>
70#include <limits.h>
71#include <string.h>
72#include <unistd.h>
73#include <errno.h>
74#include <sys/types.h>
75#include <stdbool.h>
76
77#include <Eina.h>
78#include <eina_safety_checks.h>
79#include <EDBus.h>
80#include <Ethumb.h>
81#include <Ecore.h>
82
83#include "Ethumb_Client.h"
84
85#ifndef PATH_MAX
86#define PATH_MAX 4096
87#endif
88
89#define MAX_ID 2000000
90
91static int _log_dom = -1;
92#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
93#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
94#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
95#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
96#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
97
98struct _Ethumb_Client
99{
100 Ethumb *ethumb;
101 int id_count;
102 Ethumb *old_ethumb_conf;
103 EDBus_Connection *conn;
104 struct
105 {
106 Ethumb_Client_Connect_Cb cb;
107 void *data;
108 Eina_Free_Cb free_data;
109 } connect;
110 Eina_List *pending_add;
111 Eina_List *pending_remove;
112 Eina_List *pending_gen;
113 struct
114 {
115 Ethumb_Client_Die_Cb cb;
116 void *data;
117 Eina_Free_Cb free_data;
118 } die;
119 EDBus_Proxy *proxy;
120 EINA_REFCOUNT;
121 Eina_Bool connected : 1;
122 Eina_Bool server_started : 1;
123};
124
125struct _ethumb_pending_add
126{
127 int32_t id;
128 const char *file;
129 const char *key;
130 const char *thumb;
131 const char *thumb_key;
132 Ethumb_Client_Generate_Cb generated_cb;
133 void *data;
134 Eina_Free_Cb free_data;
135 EDBus_Pending *pending_call;
136 Ethumb_Client *client;
137};
138
139struct _ethumb_pending_remove
140{
141 int32_t id;
142 Ethumb_Client_Generate_Cancel_Cb cancel_cb;
143 void *data;
144 Eina_Free_Cb free_data;
145 Ethumb_Client *client;
146};
147
148struct _ethumb_pending_gen
149{
150 int32_t id;
151 const char *file;
152 const char *key;
153 const char *thumb;
154 const char *thumb_key;
155 Ethumb_Client_Generate_Cb generated_cb;
156 void *data;
157 Eina_Free_Cb free_data;
158};
159
160typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists;
161
162struct _Ethumb_Async_Exists
163{
164 const char *path;
165
166 Ethumb *dup; /* We will work on that one to prevent race and lock */
167
168 Eina_List *callbacks;
169 Ecore_Thread *thread;
170};
171
172struct _Ethumb_Exists
173{
174 Ethumb_Async_Exists *parent;
175 Ethumb_Client *client;
176 Ethumb *dup; /* We don't want to loose parameters so keep them around */
177
178 Ethumb_Client_Thumb_Exists_Cb exists_cb;
179 const void *data;
180};
181
182static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
183static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
184static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
185static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
186
187static int _initcount = 0;
188static Eina_Hash *_exists_request = NULL;
189
190static void _ethumb_client_generated_cb(void *data, const EDBus_Message *msg);
191static void _ethumb_client_call_new(Ethumb_Client *client);
192static void _ethumb_client_name_owner_changed(void *context, const char *bus, const char *old_id, const char *new_id);
193
194static void
195_ethumb_client_free(Ethumb_Client *client)
196{
197 void *data;
198 EDBus_Object *obj;
199
200 if (!client->connected)
201 goto end_connection;
202
203 EINA_LIST_FREE(client->pending_add, data)
204 {
205 struct _ethumb_pending_add *pending = data;
206 edbus_pending_cancel(pending->pending_call);
207 }
208
209 EINA_LIST_FREE(client->pending_gen, data)
210 {
211 struct _ethumb_pending_gen *pending = data;
212 eina_stringshare_del(pending->file);
213 eina_stringshare_del(pending->key);
214 eina_stringshare_del(pending->thumb);
215 eina_stringshare_del(pending->thumb_key);
216 if (pending->free_data)
217 pending->free_data(pending->data);
218 free(pending);
219 }
220
221 EINA_LIST_FREE(client->pending_remove, data)
222 {
223 struct _ethumb_pending_remove *pending = data;
224 if (pending->free_data)
225 pending->free_data(pending->data);
226 free(pending);
227 }
228
229end_connection:
230 if (client->old_ethumb_conf)
231 ethumb_free(client->old_ethumb_conf);
232
233 ethumb_free(client->ethumb);
234
235 edbus_name_owner_changed_callback_del(client->conn, _ethumb_dbus_bus_name,
236 _ethumb_client_name_owner_changed,
237 client);
238 obj = edbus_proxy_object_get(client->proxy);
239 edbus_proxy_unref(client->proxy);
240 edbus_object_unref(obj);
241 edbus_connection_unref(client->conn);
242
243 if (client->connect.free_data)
244 client->connect.free_data(client->connect.data);
245 if (client->die.free_data)
246 client->die.free_data(client->die.data);
247
248 free(client);
249}
250
251static void
252_ethumb_async_delete(void *data)
253{
254 Ethumb_Async_Exists *async = data;
255
256 EINA_SAFETY_ON_FALSE_RETURN(async->callbacks == NULL);
257 EINA_SAFETY_ON_FALSE_RETURN(async->thread == NULL);
258
259 ethumb_free(async->dup);
260 eina_stringshare_del(async->path);
261
262 free(async);
263}
264
265static void
266_ethumb_client_name_owner_changed(void *context, const char *bus EINA_UNUSED, const char *old_id, const char *new_id)
267{
268 Ethumb_Client *client = context;
269 DBG("NameOwnerChanged from=[%s] to=[%s]", old_id, new_id);
270 if (new_id[0])
271 {
272 if (client->connected)
273 return;
274
275 client->connected = EINA_TRUE;
276 _ethumb_client_call_new(client);
277 return;
278 }
279 ERR("server exit!!!");
280 client->connected = EINA_FALSE;
281 if (client->die.cb)
282 {
283 client->die.cb(client->die.data, client);
284 client->die.cb = NULL;
285 }
286 if (client->die.free_data)
287 {
288 client->die.free_data(client->die.data);
289 client->die.free_data = NULL;
290 client->die.data = NULL;
291 }
292}
293
294static void
295_ethumb_client_report_connect(Ethumb_Client *client, Eina_Bool success)
296{
297 if (!client->connect.cb)
298 {
299 ERR("already called?!");
300 return;
301 }
302
303 client->connect.cb(client->connect.data, client, success);
304 if (client->connect.free_data)
305 {
306 client->connect.free_data(client->connect.data);
307 client->connect.free_data = NULL;
308 }
309 client->connect.cb = NULL;
310 client->connect.data = NULL;
311}
312
313static void
314_ethumb_client_new_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
315{
316 const char *errname, *errmsg;
317 const char *opath;
318 Ethumb_Client *client = data;
319 EDBus_Object *obj;
320
321 if (edbus_message_error_get(msg, &errname, &errmsg))
322 {
323 ERR("Error: %s %s", errname, errmsg);
324 return;
325 }
326
327 if (!edbus_message_arguments_get(msg, "o", &opath))
328 {
329 ERR("Error: could not get entry contents");
330 _ethumb_client_report_connect(client, 0);
331 return;
332 }
333
334 obj = edbus_object_get(client->conn, _ethumb_dbus_bus_name, opath);
335 client->proxy = edbus_proxy_get(obj, _ethumb_dbus_objects_interface);
336 edbus_proxy_signal_handler_add(client->proxy, "generated",
337 _ethumb_client_generated_cb, client);
338 _ethumb_client_report_connect(client, 1);
339}
340
341static void
342_ethumb_client_call_new(Ethumb_Client *client)
343{
344 EDBus_Message *msg;
345 msg = edbus_message_method_call_new(_ethumb_dbus_bus_name,
346 _ethumb_dbus_path,
347 _ethumb_dbus_interface, "new");
348 edbus_connection_send(client->conn, msg, _ethumb_client_new_cb, client, -1);
349 edbus_message_unref(msg);
350}
351
352static void
353_ethumb_client_exists_heavy(void *data, Ecore_Thread *thread EINA_UNUSED)
354{
355 Ethumb_Async_Exists *async = data;
356
357 ethumb_thumb_hash(async->dup);
358}
359
360static void
361_ethumb_client_exists_end(void *data, Ecore_Thread *thread EINA_UNUSED)
362{
363 Ethumb_Async_Exists *async = data;
364 Ethumb_Exists *cb;
365
366 EINA_LIST_FREE(async->callbacks, cb)
367 {
368 Ethumb *tmp;
369
370 ethumb_thumb_hash_copy(cb->dup, async->dup);
371 tmp = cb->client->ethumb;
372 cb->client->ethumb = cb->dup;
373
374 cb->exists_cb((void *)cb->data,
375 cb->client, cb,
376 ethumb_exists(cb->client->ethumb));
377
378 cb->client->ethumb = tmp;
379 EINA_REFCOUNT_UNREF(cb->client)
380 _ethumb_client_free(cb->client);
381 ethumb_free(cb->dup);
382 free(cb);
383 }
384
385 async->thread = NULL;
386
387 eina_hash_del(_exists_request, async->path, async);
388}
389
390/**
391 * @endcond
392 */
393
394/**
395 * @brief Initialize the Ethumb_Client library.
396 *
397 * @return 1 or greater on success, 0 on error.
398 *
399 * This function sets up all the Ethumb_Client module dependencies. It
400 * returns 0 on failure (that is, when one of the dependency fails to
401 * initialize), otherwise it returns the number of times it has
402 * already been called.
403 *
404 * When Ethumb_Client is not used anymore, call
405 * ethumb_client_shutdown() to shut down the Ethumb_Client library.
406 *
407 * @see ethumb_client_shutdown()
408 * @see ethumb_client_connect()
409 * @see @ref tutorial_ethumb_client
410 */
411EAPI int
412ethumb_client_init(void)
413{
414 if (_initcount)
415 return ++_initcount;
416
417 if (!eina_init())
418 {
419 fprintf(stderr, "ERROR: Could not initialize log module.\n");
420 return 0;
421 }
422 _log_dom = eina_log_domain_register("ethumb_client", EINA_COLOR_YELLOW);
423 if (_log_dom < 0)
424 {
425 EINA_LOG_ERR("Could not register log domain: ethumb_client");
426 eina_shutdown();
427 return 0;
428 }
429
430 ethumb_init();
431 edbus_init();
432
433 _exists_request = eina_hash_stringshared_new(_ethumb_async_delete);
434
435 return ++_initcount;
436}
437
438/**
439 * @brief Shut down the Ethumb_Client library.
440 *
441 * @return 0 when everything is shut down, 1 or greater if there are
442 * other users of the Ethumb_Client library pending shutdown.
443 *
444 * This function shuts down the Ethumb_Client library. It returns 0
445 * when it has been called the same number of times than
446 * ethumb_client_init(). In that case it shut down all the
447 * Ethumb_Client modules dependencies.
448 *
449 * Once this function succeeds (that is, @c 0 is returned), you must
450 * not call any of the Eina function anymore. You must call
451 * ethumb_client_init() again to use the Ethumb_Client functions
452 * again.
453 */
454EAPI int
455ethumb_client_shutdown(void)
456{
457 _initcount--;
458 if (_initcount > 0)
459 return _initcount;
460
461 /* should find a non racy solution to closing all pending exists request */
462 eina_hash_free(_exists_request);
463 _exists_request = NULL;
464
465 edbus_shutdown();
466 ethumb_shutdown();
467 eina_log_domain_unregister(_log_dom);
468 _log_dom = -1;
469 eina_shutdown();
470 return _initcount;
471}
472
473/**
474 * Connects to Ethumb server and return the client instance.
475 *
476 * This is the "constructor" of Ethumb_Client, where everything
477 * starts.
478 *
479 * If server was down, it is tried to start it using DBus activation,
480 * then the connection is retried.
481 *
482 * This call is asynchronous and will not block, instead it will be in
483 * "not connected" state until @a connect_cb is called with either
484 * success or failure. On failure, then no methods should be
485 * called. On success you're now able to setup and then ask generation
486 * of thumbnails.
487 *
488 * Usually you should listen for server death/disconenction with
489 * ethumb_client_on_server_die_callback_set().
490 *
491 * @param connect_cb function to call to report connection success or
492 * failure. Do not call any other ethumb_client method until
493 * this function returns. The first received parameter is the
494 * given argument @a data. Must @b not be @c NULL. This
495 * function will not be called if user explicitly calls
496 * ethumb_client_disconnect().
497 * @param data context to give back to @a connect_cb. May be @c NULL.
498 * @param free_data function used to release @a data resources, if
499 * any. May be @c NULL. If this function exists, it will be
500 * called immediately after @a connect_cb is called or if user
501 * explicitly calls ethumb_client_disconnect() before such
502 * (that is, don't rely on @a data after @a connect_cb was
503 * called!)
504 *
505 * @return client instance or NULL if failed. If @a connect_cb is
506 * missing it returns @c NULL. If it fail for other
507 * conditions, @c NULL is also returned and @a connect_cb is
508 * called with @c success=EINA_FALSE. The client instance is
509 * not ready to be used until @a connect_cb is called.
510 */
511EAPI Ethumb_Client *
512ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_data)
513{
514 Ethumb_Client *eclient;
515
516 EINA_SAFETY_ON_NULL_RETURN_VAL(connect_cb, NULL);
517
518 eclient = calloc(1, sizeof(*eclient));
519 if (!eclient)
520 {
521 ERR("could not allocate Ethumb_Client structure.");
522 goto err;
523 }
524
525 eclient->old_ethumb_conf = NULL;
526 eclient->connect.cb = connect_cb;
527 eclient->connect.data = (void *)data;
528 eclient->connect.free_data = free_data;
529
530 eclient->ethumb = ethumb_new();
531 if (!eclient->ethumb)
532 {
533 ERR("could not create ethumb handler.");
534 goto ethumb_new_err;
535 }
536
537 eclient->conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
538 if (!eclient->conn)
539 {
540 ERR("could not connect to session bus.");
541 goto connection_err;
542 }
543
544 edbus_name_start(eclient->conn, _ethumb_dbus_bus_name, 0, NULL, NULL);
545 edbus_name_owner_changed_callback_add(eclient->conn, _ethumb_dbus_bus_name,
546 _ethumb_client_name_owner_changed,
547 eclient, EINA_TRUE);
548 EINA_REFCOUNT_INIT(eclient);
549
550 return eclient;
551
552connection_err:
553 ethumb_free(eclient->ethumb);
554ethumb_new_err:
555 free(eclient);
556err:
557 connect_cb((void *)data, NULL, EINA_FALSE);
558 if (free_data)
559 free_data((void *)data);
560 return NULL;
561}
562
563/**
564 * Disconnect the client, releasing all client resources.
565 *
566 * This is the destructor of Ethumb_Client, after it's disconnected
567 * the client handle is now gone and should not be used.
568 *
569 * @param client client instance to be destroyed. Must @b not be @c
570 * NULL.
571 */
572EAPI void
573ethumb_client_disconnect(Ethumb_Client *client)
574{
575 EINA_SAFETY_ON_NULL_RETURN(client);
576
577 EINA_REFCOUNT_UNREF(client)
578 _ethumb_client_free(client);
579}
580
581/**
582 * Sets the callback to report server died.
583 *
584 * When server dies there is nothing you can do, just release
585 * resources with ethumb_client_disconnect() and probably try to
586 * connect again.
587 *
588 * Usually you should set this callback and handle this case, it does
589 * happen!
590 *
591 * @param client the client instance to monitor. Must @b not be @c
592 * NULL.
593 * @param server_die_cb function to call back when server dies. The
594 * first parameter will be the argument @a data. May be @c
595 * NULL.
596 * @param data context to give back to @a server_die_cb. May be @c
597 * NULL.
598 * @param free_data used to release @a data resources after @a
599 * server_die_cb is called or user calls
600 * ethumb_client_disconnect().
601 */
602EAPI void
603ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data)
604{
605 EINA_SAFETY_ON_NULL_RETURN(client);
606
607 if (client->die.free_data)
608 client->die.free_data(client->die.data);
609
610 client->die.cb = server_die_cb;
611 client->die.data = (void *)data;
612 client->die.free_data = free_data;
613}
614
615/**
616 * @cond LOCAL
617 */
618
619static void
620_ethumb_client_ethumb_setup_cb(void *data EINA_UNUSED, const EDBus_Message *msg, EDBus_Pending *pending EINA_UNUSED)
621{
622 const char *errname, *errmsg;
623 Eina_Bool result = 0;
624
625 if (edbus_message_error_get(msg, &errname, &errmsg))
626 {
627 ERR("Error: %s %s\n", errname, errmsg);
628 return;
629 }
630
631 if (!edbus_message_arguments_get(msg, "b", &result))
632 {
633 ERR("Error getting arguments");
634 return;
635 }
636 EINA_SAFETY_ON_FALSE_RETURN(result);
637}
638
639static const char *
640_ethumb_client_dbus_get_bytearray(EDBus_Message_Iter *array)
641{
642 int length;
643 const char *result;
644
645 if (edbus_message_iter_fixed_array_get(array, 'y', &result, &length))
646 return eina_stringshare_add_length(result, length);
647 else
648 {
649 ERR("Not byte array. Signature: %s",
650 edbus_message_iter_signature_get(array));
651 return NULL;
652 }
653}
654
655static void
656_ethumb_client_dbus_append_bytearray(EDBus_Message_Iter *parent, const char *string)
657{
658 int i, size;
659 EDBus_Message_Iter *array;
660
661 if (!string)
662 string = "";
663
664 array = edbus_message_iter_container_new(parent, 'a', "y");
665 size = strlen(string) + 1;
666 for (i = 0; i < size; i++)
667 edbus_message_iter_basic_append(array, 'y', string[i]);
668 edbus_message_iter_container_close(parent, array);
669}
670
671/**
672 * @endcond
673 */
674
675static EDBus_Message_Iter *
676_setup_iterator_open(EDBus_Message_Iter *array, EDBus_Message_Iter **entry, const char *key, const char *type)
677{
678 EDBus_Message_Iter *variant, *_struct;
679 edbus_message_iter_arguments_append(array, "{sv}", &_struct);
680 edbus_message_iter_basic_append(_struct, 's', key);
681 variant = edbus_message_iter_container_new(_struct, 'v', type);
682
683 *entry = _struct;
684 return variant;
685}
686
687static void
688_setup_iterator_close(EDBus_Message_Iter *array, EDBus_Message_Iter *entry, EDBus_Message_Iter *variant)
689{
690 edbus_message_iter_container_close(entry, variant);
691 edbus_message_iter_container_close(array, entry);
692}
693
694/**
695 * Send setup to server.
696 *
697 * This method is called automatically by ethumb_client_generate() if
698 * any property was changed. No need to call it manually.
699 *
700 * @param client client instance. Must @b not be @c NULL and client
701 * must be connected (after connected_cb is called).
702 */
703EAPI void
704ethumb_client_ethumb_setup(Ethumb_Client *client)
705{
706 EDBus_Message *msg;
707 EDBus_Message_Iter *array, *main_iter;
708 EDBus_Message_Iter *entry, *variant;
709 EDBus_Message_Iter *sub_struct;
710 Ethumb *e = client->ethumb;
711 int tw, th, format, aspect, orientation, quality, compress;
712 float cx, cy;
713 const char *theme_file, *group, *swallow;
714 const char *directory, *category;
715 double video_time, video_start, video_interval;
716 unsigned int video_ntimes, video_fps, document_page;
717
718 EINA_SAFETY_ON_NULL_RETURN(client);
719 EINA_SAFETY_ON_FALSE_RETURN(client->connected);
720
721 msg = edbus_proxy_method_call_new(client->proxy, "ethumb_setup");
722 main_iter = edbus_message_iter_get(msg);
723 edbus_message_iter_arguments_append(main_iter, "a{sv}", &array);
724
725 /* starting array elements */
726 variant = _setup_iterator_open(array, &entry, "size", "(ii)");
727 edbus_message_iter_arguments_append(variant, "(ii)", &sub_struct);
728 ethumb_thumb_size_get(e, &tw, &th);
729 edbus_message_iter_arguments_append(sub_struct, "ii", tw, th);
730 edbus_message_iter_container_close(variant, sub_struct);
731 _setup_iterator_close(array, entry, variant);
732
733 variant = _setup_iterator_open(array, &entry, "format", "i");
734 format = ethumb_thumb_format_get(e);
735 edbus_message_iter_arguments_append(variant, "i", format);
736 _setup_iterator_close(array, entry, variant);
737
738 variant = _setup_iterator_open(array, &entry, "aspect", "i");
739 aspect = ethumb_thumb_aspect_get(e);
740 edbus_message_iter_arguments_append(variant, "i", aspect);
741 _setup_iterator_close(array, entry, variant);
742
743 variant = _setup_iterator_open(array, &entry, "orientation", "i");
744 orientation = ethumb_thumb_orientation_get(e);
745 edbus_message_iter_arguments_append(variant, "i", orientation);
746 _setup_iterator_close(array, entry, variant);
747
748 variant = _setup_iterator_open(array, &entry, "crop", "(dd)");
749 edbus_message_iter_arguments_append(variant, "(dd)", &sub_struct);
750 ethumb_thumb_crop_align_get(e, &cx, &cy);
751 edbus_message_iter_arguments_append(sub_struct, "dd", (double)cx, (double)cy);
752 edbus_message_iter_container_close(variant, sub_struct);
753 _setup_iterator_close(array, entry, variant);
754
755 variant = _setup_iterator_open(array, &entry, "quality", "i");
756 quality = ethumb_thumb_quality_get(e);
757 edbus_message_iter_arguments_append(variant, "i", quality);
758 _setup_iterator_close(array, entry, variant);
759
760 variant = _setup_iterator_open(array, &entry, "compress", "i");
761 compress = ethumb_thumb_quality_get(e);
762 edbus_message_iter_arguments_append(variant, "i", compress);
763 _setup_iterator_close(array, entry, variant);
764
765 variant = _setup_iterator_open(array, &entry, "frame", "(ayayay)");
766 edbus_message_iter_arguments_append(variant, "(ayayay)", &sub_struct);
767 ethumb_frame_get(e, &theme_file, &group, &swallow);
768 _ethumb_client_dbus_append_bytearray(sub_struct, theme_file);
769 _ethumb_client_dbus_append_bytearray(sub_struct, group);
770 _ethumb_client_dbus_append_bytearray(sub_struct, swallow);
771 edbus_message_iter_container_close(variant, sub_struct);
772 _setup_iterator_close(array, entry, variant);
773
774 variant = _setup_iterator_open(array, &entry, "directory", "ay");
775 directory = ethumb_thumb_dir_path_get(e);
776 _ethumb_client_dbus_append_bytearray(variant, directory);
777 _setup_iterator_close(array, entry, variant);
778
779 variant = _setup_iterator_open(array, &entry, "category", "ay");
780 category = ethumb_thumb_category_get(e);
781 _ethumb_client_dbus_append_bytearray(variant, category);
782 _setup_iterator_close(array, entry, variant);
783
784 variant = _setup_iterator_open(array, &entry, "video_time", "d");
785 video_time = ethumb_video_time_get(e);
786 edbus_message_iter_arguments_append(variant, "d", video_time);
787 _setup_iterator_close(array, entry, variant);
788
789 variant = _setup_iterator_open(array, &entry, "video_start", "d");
790 video_start = ethumb_video_start_get(e);
791 edbus_message_iter_arguments_append(variant, "d", video_start);
792 _setup_iterator_close(array, entry, variant);
793
794 variant = _setup_iterator_open(array, &entry, "video_interval", "d");
795 video_interval = ethumb_video_interval_get(e);
796 edbus_message_iter_arguments_append(variant, "d", video_interval);
797 _setup_iterator_close(array, entry, variant);
798
799 variant = _setup_iterator_open(array, &entry, "video_ntimes", "u");
800 video_ntimes = ethumb_video_ntimes_get(e);
801 edbus_message_iter_arguments_append(variant, "u", video_ntimes);
802 _setup_iterator_close(array, entry, variant);
803
804 variant = _setup_iterator_open(array, &entry, "video_fps", "u");
805 video_fps = ethumb_video_fps_get(e);
806 edbus_message_iter_arguments_append(variant, "u", video_fps);
807 _setup_iterator_close(array, entry, variant);
808
809 variant = _setup_iterator_open(array, &entry, "document_page", "u");
810 document_page = ethumb_document_page_get(e);
811 edbus_message_iter_arguments_append(variant, "u", document_page);
812 _setup_iterator_close(array, entry, variant);
813
814 edbus_message_iter_container_close(main_iter, array);
815
816 edbus_proxy_send(client->proxy, msg, _ethumb_client_ethumb_setup_cb,
817 client, -1);
818 edbus_message_unref(msg);
819}
820
821/**
822 * @cond LOCAL
823 */
824static void
825_ethumb_client_generated_cb(void *data, const EDBus_Message *msg)
826{
827 int id = -1;
828 Ethumb_Client *client = data;
829 EDBus_Message_Iter *thumb_iter;
830 EDBus_Message_Iter *thumb_key_iter;
831 Eina_Bool success;
832 int found;
833 struct _ethumb_pending_gen *pending;
834 Eina_List *l;
835
836 if (!edbus_message_arguments_get(msg, "iayayb", &id, &thumb_iter,
837 &thumb_key_iter, &success))
838 {
839 ERR("Error getting data from signal.");
840 return;
841 }
842
843 found = 0;
844 l = client->pending_gen;
845 while (l)
846 {
847 pending = l->data;
848 if (pending->id == id)
849 {
850 found = 1;
851 break;
852 }
853 l = l->next;
854 }
855
856 if (found)
857 {
858 const char *thumb = _ethumb_client_dbus_get_bytearray(thumb_iter);
859 const char *thumb_key = _ethumb_client_dbus_get_bytearray(thumb_key_iter);
860
861 client->pending_gen = eina_list_remove_list(client->pending_gen, l);
862 if (pending->generated_cb)
863 pending->generated_cb(pending->data, client, id,
864 pending->file, pending->key,
865 thumb, thumb_key,
866 success);
867 if (pending->free_data)
868 pending->free_data(pending->data);
869 eina_stringshare_del(pending->file);
870 eina_stringshare_del(pending->key);
871 eina_stringshare_del(pending->thumb);
872 eina_stringshare_del(pending->thumb_key);
873 eina_stringshare_del(thumb);
874 eina_stringshare_del(thumb_key);
875 free(pending);
876 }
877}
878
879static void
880_ethumb_client_queue_add_cb(void *data, const EDBus_Message *msg, EDBus_Pending *edbus_pending EINA_UNUSED)
881{
882 const char *errname, *errmsg;
883 int32_t id;
884 struct _ethumb_pending_add *pending = data;
885 struct _ethumb_pending_gen *generating;
886 Ethumb_Client *client = pending->client;
887
888 client->pending_add = eina_list_remove(client->pending_add, pending);
889
890 //in case of error or when user cancel
891 if (edbus_message_error_get(msg, &errname, &errmsg))
892 {
893 ERR("Error: %s %s\n", errname, errmsg);
894 goto end;
895 }
896
897 if (!edbus_message_arguments_get(msg, "i", &id))
898 {
899 ERR("Error getting arguments.");
900 goto end;
901 }
902
903 generating = calloc(1, sizeof(*generating));
904 generating->id = id;
905 generating->file = pending->file;
906 generating->key = pending->key;
907 generating->thumb = pending->thumb;
908 generating->thumb_key = pending->thumb_key;
909 generating->generated_cb = pending->generated_cb;
910 generating->data = pending->data;
911 generating->free_data = pending->free_data;
912 client->pending_gen = eina_list_append(client->pending_gen, generating);
913
914 free(pending);
915 return;
916
917end:
918 eina_stringshare_del(pending->file);
919 eina_stringshare_del(pending->key);
920 eina_stringshare_del(pending->thumb);
921 eina_stringshare_del(pending->thumb_key);
922 if (pending->free_data)
923 pending->free_data(pending->data);
924 free(pending);
925}
926
927static int
928_ethumb_client_queue_add(Ethumb_Client *client, const char *file, const char *key, const char *thumb, const char *thumb_key, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
929{
930 EDBus_Message *msg;
931 EDBus_Message_Iter *main_itr;
932 struct _ethumb_pending_add *pending;
933
934 pending = calloc(1, sizeof(*pending));
935 pending->id = client->id_count;
936 pending->file = eina_stringshare_add(file);
937 pending->key = eina_stringshare_add(key);
938 pending->thumb = eina_stringshare_add(thumb);
939 pending->thumb_key = eina_stringshare_add(thumb_key);
940 pending->generated_cb = generated_cb;
941 pending->data = (void *)data;
942 pending->free_data = free_data;
943 pending->client = client;
944
945 client->id_count = (client->id_count + 1) % MAX_ID;
946
947 msg = edbus_proxy_method_call_new(client->proxy, "queue_add");
948 main_itr = edbus_message_iter_get(msg);
949 edbus_message_iter_basic_append(main_itr, 'i', pending->id);
950 _ethumb_client_dbus_append_bytearray(main_itr, file);
951 _ethumb_client_dbus_append_bytearray(main_itr, key);
952 _ethumb_client_dbus_append_bytearray(main_itr, thumb);
953 _ethumb_client_dbus_append_bytearray(main_itr, thumb_key);
954
955 pending->pending_call = edbus_proxy_send(client->proxy, msg,
956 _ethumb_client_queue_add_cb,
957 pending, -1);
958 client->pending_add = eina_list_append(client->pending_add, pending);
959 edbus_message_unref(msg);
960
961 return pending->id;
962}
963
964static void
965_ethumb_client_queue_remove_cb(void *data, const EDBus_Message *msg, EDBus_Pending *edbus_pending EINA_UNUSED)
966{
967 Eina_Bool success;
968 struct _ethumb_pending_remove *pending = data;
969 Ethumb_Client *client = pending->client;
970 const char *errname, *errmsg;
971
972 client->pending_remove = eina_list_remove(client->pending_remove, pending);
973
974 if (edbus_message_error_get(msg, &errname, &errmsg))
975 {
976 ERR("Error: %s %s\n", errname, errmsg);
977 goto end;
978 }
979
980 if (edbus_message_arguments_get(msg, "b", &success))
981 {
982 ERR("Error getting arguments.");
983 goto end;
984 }
985
986end:
987 if (pending->cancel_cb)
988 pending->cancel_cb(pending->data, success);
989 if (pending->free_data)
990 pending->free_data(pending->data);
991 free(pending);
992}
993
994/**
995 * @endcond
996 */
997
998/**
999 * Ask server to cancel generation of thumbnail.
1000 *
1001 * @param client client instance. Must @b not be @c NULL and client
1002 * must be connected (after connected_cb is called).
1003 * @param id valid id returned by ethumb_client_generate()
1004 * @param cancel_cb function to report cancellation results.
1005 * @param data context argument to give back to @a cancel_cb. May be
1006 * @c NULL.
1007 * @param data context to give back to @a cancel_cb. May be @c
1008 * NULL.
1009 * @param free_data used to release @a data resources after @a
1010 * cancel_cb is called or user calls
1011 * ethumb_client_disconnect().
1012 */
1013EAPI void
1014ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data)
1015{
1016 struct _ethumb_pending_remove *pending;
1017 Eina_List *l;
1018 int found;
1019 int32_t id32 = id;
1020 EINA_SAFETY_ON_NULL_RETURN(client);
1021 EINA_SAFETY_ON_FALSE_RETURN(id >= 0);
1022
1023 pending = calloc(1, sizeof(*pending));
1024 pending->id = id;
1025 pending->cancel_cb = cancel_cb;
1026 pending->data = (void *)data;
1027 pending->free_data = free_data;
1028 pending->client = client;
1029
1030 edbus_proxy_call(client->proxy, "queue_remove",
1031 _ethumb_client_queue_remove_cb, pending, -1, "i", pending->id);
1032 client->pending_remove = eina_list_append(client->pending_remove, pending);
1033
1034 /*
1035 * Check if answer was not received yet cancel it
1036 * callback of queue_add will be called with a error msg
1037 * and data will be freed
1038 */
1039 found = 0;
1040 l = client->pending_add;
1041 while (l)
1042 {
1043 struct _ethumb_pending_add *pending_add = l->data;
1044 if (pending_add->id != id32)
1045 {
1046 l = l->next;
1047 continue;
1048 }
1049 edbus_pending_cancel(pending_add->pending_call);
1050 found = 1;
1051 break;
1052 }
1053
1054 if (found)
1055 return;
1056
1057 //if already received answer only free memory
1058 l = client->pending_gen;
1059 while (l)
1060 {
1061 struct _ethumb_pending_gen *pending_gen = l->data;
1062 if (pending_gen->id != id32)
1063 {
1064 l = l->next;
1065 continue;
1066 }
1067 client->pending_gen = eina_list_remove_list(client->pending_gen, l);
1068 eina_stringshare_del(pending_gen->file);
1069 eina_stringshare_del(pending_gen->key);
1070 eina_stringshare_del(pending_gen->thumb);
1071 eina_stringshare_del(pending_gen->thumb_key);
1072 if (pending_gen->free_data)
1073 pending_gen->free_data(pending_gen->data);
1074 free(pending_gen);
1075 break;
1076 }
1077}
1078
1079/**
1080 * @endcond
1081 */
1082
1083/**
1084 * Ask server to cancel generation of all thumbnails.
1085 *
1086 * @param client client instance. Must @b not be @c NULL and client
1087 * must be connected (after connected_cb is called).
1088 *
1089 * @see ethumb_client_generate_cancel()
1090 */
1091EAPI void
1092ethumb_client_generate_cancel_all(Ethumb_Client *client)
1093{
1094 void *data;
1095 EINA_SAFETY_ON_NULL_RETURN(client);
1096
1097 EINA_LIST_FREE(client->pending_add, data)
1098 {
1099 struct _ethumb_pending_add *pending = data;
1100 edbus_pending_cancel(pending->pending_call);
1101 }
1102
1103 EINA_LIST_FREE(client->pending_gen, data)
1104 {
1105 struct _ethumb_pending_gen *pending = data;
1106 eina_stringshare_del(pending->file);
1107 eina_stringshare_del(pending->key);
1108 eina_stringshare_del(pending->thumb);
1109 eina_stringshare_del(pending->thumb_key);
1110 if (pending->free_data)
1111 pending->free_data(pending->data);
1112 free(pending);
1113 }
1114
1115 edbus_proxy_call(client->proxy, "queue_clear", NULL, NULL, -1, "");
1116}
1117
1118/**
1119 * Configure future requests to use FreeDesktop.Org preset.
1120 *
1121 * This is a preset to provide freedesktop.org (fdo) standard
1122 * compliant thumbnails. That is, files are stored as JPEG under
1123 * ~/.thumbnails/SIZE, with size being either normal (128x128) or
1124 * large (256x256).
1125 *
1126 * @param client the client instance to use. Must @b not be @c
1127 * NULL. May be pending connected (can be called before @c
1128 * connected_cb)
1129 * @param s size identifier, either #ETHUMB_THUMB_NORMAL (0) or
1130 * #ETHUMB_THUMB_LARGE (1).
1131 *
1132 * @see ethumb_client_size_set()
1133 * @see ethumb_client_aspect_set()
1134 * @see ethumb_client_crop_align_set()
1135 * @see ethumb_client_category_set()
1136 * @see ethumb_client_dir_path_set()
1137 */
1138EAPI void
1139ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s)
1140{
1141 EINA_SAFETY_ON_NULL_RETURN(client);
1142
1143 if (!client->old_ethumb_conf)
1144 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1145 ethumb_thumb_fdo_set(client->ethumb, s);
1146}
1147
1148/**
1149 * Configure future request to use custom size.
1150 *
1151 * @param client the client instance to use. Must @b not be @c
1152 * NULL. May be pending connected (can be called before @c
1153 * connected_cb)
1154 * @param tw width, default is 128.
1155 * @param th height, default is 128.
1156 */
1157EAPI void
1158ethumb_client_size_set(Ethumb_Client *client, int tw, int th)
1159{
1160 EINA_SAFETY_ON_NULL_RETURN(client);
1161
1162 if (!client->old_ethumb_conf)
1163 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1164 ethumb_thumb_size_set(client->ethumb, tw, th);
1165}
1166
1167/**
1168 * Retrieve future request to use custom size.
1169 *
1170 * @param client the client instance to use. Must @b not be @c
1171 * NULL. May be pending connected (can be called before @c
1172 * connected_cb)
1173 * @param tw where to return width. May be @c NULL.
1174 * @param th where to return height. May be @c NULL.
1175 */
1176EAPI void
1177ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th)
1178{
1179 if (tw) *tw = 0;
1180 if (th) *th = 0;
1181 EINA_SAFETY_ON_NULL_RETURN(client);
1182
1183 ethumb_thumb_size_get(client->ethumb, tw, th);
1184}
1185
1186/**
1187 * Configure format to use for future requests.
1188 *
1189 * @param client the client instance to use. Must @b not be @c
1190 * NULL. May be pending connected (can be called before @c
1191 * connected_cb)
1192 * @param f format identifier to use, either #ETHUMB_THUMB_FDO (0),
1193 * #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2). Default is FDO.
1194 */
1195EAPI void
1196ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f)
1197{
1198 EINA_SAFETY_ON_NULL_RETURN(client);
1199
1200 if (!client->old_ethumb_conf)
1201 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1202 ethumb_thumb_format_set(client->ethumb, f);
1203}
1204
1205/**
1206 * Retrieve format to use for future requests.
1207 *
1208 * @param client the client instance to use. Must @b not be @c
1209 * NULL. May be pending connected (can be called before @c
1210 * connected_cb)
1211 *
1212 * @return format identifier to use, either #ETHUMB_THUMB_FDO (0),
1213 * #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2).
1214 */
1215EAPI Ethumb_Thumb_Format
1216ethumb_client_format_get(const Ethumb_Client *client)
1217{
1218 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1219
1220 return ethumb_thumb_format_get(client->ethumb);
1221}
1222
1223/**
1224 * Configure aspect mode to use.
1225 *
1226 * If aspect is kept (#ETHUMB_THUMB_KEEP_ASPECT), then image will be
1227 * rescaled so the largest dimension is not bigger than it's specified
1228 * size (see ethumb_client_size_get()) and the other dimension is
1229 * resized in the same proportion. Example: size is 256x256, image is
1230 * 1000x500, resulting thumbnail is 256x128.
1231 *
1232 * If aspect is ignored (#ETHUMB_THUMB_IGNORE_ASPECT), then image will
1233 * be distorted to match required thumbnail size. Example: size is
1234 * 256x256, image is 1000x500, resulting thumbnail is 256x256.
1235 *
1236 * If crop is required (#ETHUMB_THUMB_CROP), then image will be
1237 * cropped so the smallest dimension is not bigger than its specified
1238 * size (see ethumb_client_size_get()) and the other dimension will
1239 * overflow, not being visible in the final image. How it will
1240 * overflow is speficied by ethumb_client_crop_align_set()
1241 * alignment. Example: size is 256x256, image is 1000x500, crop
1242 * alignment is 0.5, 0.5, resulting thumbnail is 256x256 with 250
1243 * pixels from left and 250 pixels from right being lost, that is just
1244 * the 500x500 central pixels of image will be considered for scaling.
1245 *
1246 * @param client the client instance to use. Must @b not be @c
1247 * NULL. May be pending connected (can be called before @c
1248 * connected_cb)
1249 * @param a aspect mode identifier, either #ETHUMB_THUMB_KEEP_ASPECT (0),
1250 * #ETHUMB_THUMB_IGNORE_ASPECT (1) or #ETHUMB_THUMB_CROP (2).
1251 */
1252EAPI void
1253ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a)
1254{
1255 EINA_SAFETY_ON_NULL_RETURN(client);
1256
1257 if (!client->old_ethumb_conf)
1258 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1259 ethumb_thumb_aspect_set(client->ethumb, a);
1260}
1261
1262/**
1263 * Get current aspect in use for requests.
1264 *
1265 * @param client the client instance to use. Must @b not be @c
1266 * NULL. May be pending connected (can be called before @c
1267 * connected_cb)
1268 *
1269 * @return aspect in use for future requests.
1270 */
1271EAPI Ethumb_Thumb_Aspect
1272ethumb_client_aspect_get(const Ethumb_Client *client)
1273{
1274 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1275
1276 return ethumb_thumb_aspect_get(client->ethumb);
1277}
1278
1279/**
1280 * Configure orientation to use for future requests.
1281 *
1282 * Default value is #ETHUMB_THUMB_ORIENT_ORIGINAL: metadata from the file
1283 * will be used to orient pixel data.
1284 *
1285 * @param client the client instance to use. Must @b not be @c
1286 * NULL. May be pending connected (can be called before @c
1287 * connected_cb)
1288 * @param o format identifier to use, either #ETHUMB_THUMB_ORIENT_NONE (0),
1289 * #ETHUMB_THUMB_ROTATE_90_CW (1), #ETHUMB_THUMB_ROTATE_180 (2),
1290 * #ETHUMB_THUMB_ROTATE_90_CCW (3), #ETHUMB_THUMB_FLIP_HORIZONTAL (4),
1291 * #ETHUMB_THUMB_FLIP_VERTICAL (5), #ETHUMB_THUMB_FLIP_TRANSPOSE (6),
1292 * #ETHUMB_THUMB_FLIP_TRANSVERSE (7) or #ETHUMB_THUMB_ORIENT_ORIGINAL
1293 * (8). Default is ORIGINAL.
1294 */
1295EAPI void
1296ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o)
1297{
1298 EINA_SAFETY_ON_NULL_RETURN(client);
1299
1300 if (!client->old_ethumb_conf)
1301 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1302 ethumb_thumb_orientation_set(client->ethumb, o);
1303}
1304
1305/**
1306 * Get current orientation in use for requests.
1307 *
1308 * @param client the client instance to use. Must @b not be @c
1309 * NULL. May be pending connected (can be called before @c
1310 * connected_cb)
1311 *
1312 * @return orientation in use for future requests.
1313 */
1314EAPI Ethumb_Thumb_Orientation
1315ethumb_client_orientation_get(const Ethumb_Client *client)
1316{
1317 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1318
1319 return ethumb_thumb_orientation_get(client->ethumb);
1320}
1321
1322/**
1323 * Configure crop alignment in use for future requests.
1324 *
1325 * @param client the client instance to use. Must @b not be @c
1326 * NULL. May be pending connected (can be called before @c
1327 * connected_cb)
1328 * @param x horizontal alignment. 0.0 means left side will be visible
1329 * or right side is being lost. 1.0 means right side will be
1330 * visible or left side is being lost. 0.5 means just center is
1331 * visible, both sides will be lost. Default is 0.5.
1332 * @param y vertical alignment. 0.0 is top visible, 1.0 is bottom
1333 * visible, 0.5 is center visible. Default is 0.5
1334 */
1335EAPI void
1336ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y)
1337{
1338 EINA_SAFETY_ON_NULL_RETURN(client);
1339
1340 if (!client->old_ethumb_conf)
1341 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1342 ethumb_thumb_crop_align_set(client->ethumb, x, y);
1343}
1344
1345/**
1346 * Get current crop alignment in use for requests.
1347 *
1348 * @param client the client instance to use. Must @b not be @c
1349 * NULL. May be pending connected (can be called before @c
1350 * connected_cb)
1351 * @param x where to return horizontal alignment. May be @c NULL.
1352 * @param y where to return vertical alignment. May be @c NULL.
1353 */
1354EAPI void
1355ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y)
1356{
1357 if (x) *x = 0.0;
1358 if (y) *y = 0.0;
1359 EINA_SAFETY_ON_NULL_RETURN(client);
1360
1361 ethumb_thumb_crop_align_get(client->ethumb, x, y);
1362}
1363
1364/**
1365 * Configure quality to be used in thumbnails.
1366 *
1367 * @param client the client instance to use. Must @b not be @c
1368 * NULL. May be pending connected (can be called before @c
1369 * connected_cb)
1370 * @param quality value from 0 to 100, default is 80. The effect
1371 * depends on the format being used, PNG will not use it.
1372 */
1373EAPI void
1374ethumb_client_quality_set(Ethumb_Client *client, int quality)
1375{
1376 EINA_SAFETY_ON_NULL_RETURN(client);
1377
1378 ethumb_thumb_quality_set(client->ethumb, quality);
1379}
1380
1381/**
1382 * Get quality to be used in thumbnails.
1383 *
1384 * @param client the client instance to use. Must @b not be @c
1385 * NULL. May be pending connected (can be called before @c
1386 * connected_cb)
1387 *
1388 * @return quality value from 0 to 100, default is 80. The effect
1389 * depends on the format being used, PNG will not use it.
1390 */
1391EAPI int
1392ethumb_client_quality_get(const Ethumb_Client *client)
1393{
1394 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1395
1396 return ethumb_thumb_quality_get(client->ethumb);
1397}
1398
1399/**
1400 * Configure compression level used in requests.
1401 *
1402 * @param client the client instance to use. Must @b not be @c
1403 * NULL. May be pending connected (can be called before @c
1404 * connected_cb)
1405 * @param compress value from 0 to 9, default is 9. The effect
1406 * depends on the format being used, JPEG will not use it.
1407 */
1408EAPI void
1409ethumb_client_compress_set(Ethumb_Client *client, int compress)
1410{
1411 EINA_SAFETY_ON_NULL_RETURN(client);
1412
1413 ethumb_thumb_compress_set(client->ethumb, compress);
1414}
1415
1416/**
1417 * Get compression level used in requests.
1418 *
1419 * @param client the client instance to use. Must @b not be @c
1420 * NULL. May be pending connected (can be called before @c
1421 * connected_cb)
1422 *
1423 * @return compress value from 0 to 9, default is 9. The effect
1424 * depends on the format being used, JPEG will not use it.
1425 */
1426EAPI int
1427ethumb_client_compress_get(const Ethumb_Client *client)
1428{
1429 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1430
1431 return ethumb_thumb_compress_get(client->ethumb);
1432}
1433
1434/**
1435 * Set frame to apply to future thumbnails.
1436 *
1437 * This will create an edje object that will have image swallowed
1438 * in. This can be used to simulate Polaroid or wood frames in the
1439 * generated image. Remeber it is bad to modify the original contents
1440 * of thumbnails, but sometimes it's useful to have it composited and
1441 * avoid runtime overhead.
1442 *
1443 * @param client the client instance to use. Must @b not be @c
1444 * NULL. May be pending connected (can be called before @c
1445 * connected_cb)
1446 * @param file file path to edje.
1447 * @param group group inside edje to use.
1448 * @param swallow name of swallow part.
1449 *
1450 * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1451 */
1452EAPI Eina_Bool
1453ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow)
1454{
1455 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1456
1457 if (!client->old_ethumb_conf)
1458 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1459 return ethumb_frame_set(client->ethumb, file, group, swallow);
1460}
1461
1462/**
1463 * Configure where to store thumbnails in future requests.
1464 *
1465 * This value will be used to generate thumbnail paths, that is, it
1466 * will be used when ethumb_client_thumb_path_set() was not called
1467 * after last ethumb_client_file_set().
1468 *
1469 * Note that this is the base, a category is added to this path as a
1470 * sub directory. This is not the final directory where files are
1471 * stored, the thumbnail system will account @b category as well, see
1472 * ethumb_client_category_set().
1473 *
1474 * As other options, this value will only be applied to future
1475 * requests.
1476 *
1477 * @param client the client instance to use. Must @b not be @c
1478 * NULL. May be pending connected (can be called before @c
1479 * connected_cb)
1480 * @param path base directory where to store thumbnails. Default is
1481 * ~/.thumbnails
1482 *
1483 * @see ethumb_client_category_set()
1484 */
1485EAPI void
1486ethumb_client_dir_path_set(Ethumb_Client *client, const char *path)
1487{
1488 EINA_SAFETY_ON_NULL_RETURN(client);
1489
1490 if (!client->old_ethumb_conf)
1491 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1492 ethumb_thumb_dir_path_set(client->ethumb, path);
1493}
1494
1495/**
1496 * Get base directory path where to store thumbnails.
1497 *
1498 * @param client the client instance to use. Must @b not be @c
1499 * NULL. May be pending connected (can be called before @c
1500 * connected_cb)
1501 *
1502 * @return pointer to internal string with current path. This string
1503 * should not be modified or freed.
1504 *
1505 * @see ethumb_client_dir_path_set()
1506 */
1507EAPI const char *
1508ethumb_client_dir_path_get(const Ethumb_Client *client)
1509{
1510 EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
1511
1512 return ethumb_thumb_dir_path_get(client->ethumb);
1513}
1514
1515/**
1516 * Category directory to store thumbnails.
1517 *
1518 * This value will be used to generate thumbnail paths, that is, it
1519 * will be used when ethumb_client_thumb_path_set() was not called
1520 * after last ethumb_client_file_set().
1521 *
1522 * This is a sub-directory inside base directory
1523 * (ethumb_client_dir_path_set()) that creates a namespace to avoid
1524 * different options resulting in the same file.
1525 *
1526 * As other options, this value will only be applied to future
1527 * requests.
1528 *
1529 * @param client the client instance to use. Must @b not be @c
1530 * NULL. May be pending connected (can be called before @c
1531 * connected_cb)
1532 * @param category category sub directory to store thumbnail. Default
1533 * is either "normal" or "large" for FDO compliant thumbnails
1534 * or WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT. It can be a string
1535 * or @c NULL to use auto generated names.
1536 *
1537 * @see ethumb_client_dir_path_set()
1538 */
1539EAPI void
1540ethumb_client_category_set(Ethumb_Client *client, const char *category)
1541{
1542 EINA_SAFETY_ON_NULL_RETURN(client);
1543
1544 if (!client->old_ethumb_conf)
1545 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1546 ethumb_thumb_category_set(client->ethumb, category);
1547}
1548
1549/**
1550 * Get category sub-directory where to store thumbnails.
1551 *
1552 * @param client the client instance to use. Must @b not be @c
1553 * NULL. May be pending connected (can be called before @c
1554 * connected_cb)
1555 *
1556 * @return pointer to internal string with current path. This string
1557 * should not be modified or freed.
1558 *
1559 * @see ethumb_client_category_set()
1560 */
1561EAPI const char *
1562ethumb_client_category_get(const Ethumb_Client *client)
1563{
1564 EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
1565
1566 return ethumb_thumb_category_get(client->ethumb);
1567}
1568
1569/**
1570 * Set the video time (duration) in seconds.
1571 *
1572 * @param client the client instance to use. Must @b not be @c
1573 * NULL. May be pending connected (can be called before @c
1574 * connected_cb)
1575 * @param t duration (in seconds). Defaults to 3 seconds.
1576 */
1577EAPI void
1578ethumb_client_video_time_set(Ethumb_Client *client, float t)
1579{
1580 EINA_SAFETY_ON_NULL_RETURN(client);
1581
1582 if (!client->old_ethumb_conf)
1583 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1584 ethumb_video_time_set(client->ethumb, t);
1585}
1586
1587/**
1588 * Set initial video position to start thumbnailing, in percentage.
1589 *
1590 * This is useful to avoid thumbnailing the company/producer logo or
1591 * movie opening.
1592 *
1593 * @param client the client instance to use. Must @b not be @c
1594 * NULL. May be pending connected (can be called before @c
1595 * connected_cb)
1596 * @param start initial video positon to thumbnail, in percentage (0.0
1597 * to 1.0, inclusive). Defaults to 10% (0.1).
1598 */
1599EAPI void
1600ethumb_client_video_start_set(Ethumb_Client *client, float start)
1601{
1602 EINA_SAFETY_ON_NULL_RETURN(client);
1603 EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);
1604 EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);
1605
1606 if (!client->old_ethumb_conf)
1607 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1608 ethumb_video_start_set(client->ethumb, start);
1609}
1610
1611/**
1612 * Set the video frame interval, in seconds.
1613 *
1614 * This is useful for animated thumbnail and will define skip time
1615 * before going to the next frame. Note that video backends might not
1616 * be able to precisely skip that amount as it will depend on various
1617 * factors, including video encoding.
1618 *
1619 * Although this seems similar to ethumb_client_video_fps_set(), this
1620 * one is the time that will be used to seek. The math is simple, for
1621 * each new frame the video position will be set to:
1622 * ((video_length * start_time) + (interval * current_frame_number)).
1623 *
1624 * @param client the client instance to use. Must @b not be @c
1625 * NULL. May be pending connected (can be called before @c
1626 * connected_cb)
1627 * @param interval time between frames, in seconds. Defaults to 0.05
1628 * seconds.
1629 */
1630EAPI void
1631ethumb_client_video_interval_set(Ethumb_Client *client, float interval)
1632{
1633 EINA_SAFETY_ON_NULL_RETURN(client);
1634
1635 if (!client->old_ethumb_conf)
1636 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1637 ethumb_video_interval_set(client->ethumb, interval);
1638}
1639
1640/**
1641 * Set the number of frames to thumbnail.
1642 *
1643 * This is useful for animated thumbnail and will define how many
1644 * frames the generated file will have.
1645 *
1646 * @param client the client instance to use. Must @b not be @c
1647 * NULL. May be pending connected (can be called before @c
1648 * connected_cb)
1649 * @param ntimes number of times, must be greater than zero.
1650 * Defaults to 3.
1651 */
1652EAPI void
1653ethumb_client_video_ntimes_set(Ethumb_Client *client, unsigned int ntimes)
1654{
1655 EINA_SAFETY_ON_NULL_RETURN(client);
1656 EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);
1657
1658 if (!client->old_ethumb_conf)
1659 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1660 ethumb_video_ntimes_set(client->ethumb, ntimes);
1661}
1662
1663/**
1664 * Set the number of frames per second to thumbnail the video.
1665 *
1666 * This configures the number of times per seconds the thumbnail will
1667 * use to create thumbnails.
1668 *
1669 * Although this is similar to ethumb_client_video_interval_set(), it
1670 * is the delay used between calling functions thata generates frames,
1671 * while the other is the time used to skip inside the video.
1672 *
1673 * @param client the client instance to use. Must @b not be @c
1674 * NULL. May be pending connected (can be called before @c
1675 * connected_cb)
1676 * @param fps number of frames per second to thumbnail. Must be greater
1677 * than zero. Defaults to 10.
1678 */
1679EAPI void
1680ethumb_client_video_fps_set(Ethumb_Client *client, unsigned int fps)
1681{
1682 EINA_SAFETY_ON_NULL_RETURN(client);
1683 EINA_SAFETY_ON_FALSE_RETURN(fps > 0);
1684
1685 if (!client->old_ethumb_conf)
1686 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1687 ethumb_video_fps_set(client->ethumb, fps);
1688}
1689
1690/**
1691 * Set the page number to thumbnail in paged documents.
1692 *
1693 * @param client the client instance to use. Must @b not be @c
1694 * NULL. May be pending connected (can be called before @c
1695 * connected_cb)
1696 * @param page page number, defaults to 0 (first).
1697 */
1698EAPI void
1699ethumb_client_document_page_set(Ethumb_Client *client, unsigned int page)
1700{
1701 EINA_SAFETY_ON_NULL_RETURN(client);
1702
1703 if (!client->old_ethumb_conf)
1704 client->old_ethumb_conf = ethumb_dup(client->ethumb);
1705 ethumb_document_page_set(client->ethumb, page);
1706}
1707
1708/**
1709 * Set source file to be thumbnailed.
1710 *
1711 * Calling this function has the side effect of resetting values set
1712 * with ethumb_client_thumb_path_set() or auto-generated with
1713 * ethumb_client_thumb_exists().
1714 *
1715 * @param client the client instance to use. Must @b not be @c
1716 * NULL. May be pending connected (can be called before @c
1717 * connected_cb)
1718 * @param path the filesystem path to use. May be @c NULL.
1719 * @param key the extra argument/key inside @a path to read image
1720 * from. This is only used for formats that allow multiple
1721 * resources in one file, like EET or Edje (group name).
1722 *
1723 * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1724 */
1725EAPI Eina_Bool
1726ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key)
1727{
1728 EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1729
1730 return ethumb_file_set(client->ethumb, path, key);
1731}
1732
1733/**
1734 * Get values set with ethumb_client_file_get()
1735 *
1736 * @param client the client instance to use. Must @b not be @c
1737 * NULL. May be pending connected (can be called before @c
1738 * connected_cb)
1739 * @param path where to return configured path. May be @c NULL. If
1740 * not @c NULL, then it will be a pointer to a stringshared
1741 * instance, but @b no references are added (do it with
1742 * eina_stringshare_ref())!
1743 * @param key where to return configured key. May be @c NULL.If not @c
1744 * NULL, then it will be a pointer to a stringshared instance,
1745 * but @b no references are added (do it with
1746 * eina_stringshare_ref())!
1747 */
1748EAPI void
1749ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key)
1750{
1751 if (path) *path = NULL;
1752 if (key) *key = NULL;
1753 EINA_SAFETY_ON_NULL_RETURN(client);
1754
1755 ethumb_file_get(client->ethumb, path, key);
1756}
1757
1758/**
1759 * Reset previously set file to @c NULL.
1760 *
1761 * @param client the client instance to use. Must @b not be @c
1762 * NULL. May be pending connected (can be called before @c
1763 * connected_cb)
1764 */
1765EAPI void
1766ethumb_client_file_free(Ethumb_Client *client)
1767{
1768 EINA_SAFETY_ON_NULL_RETURN(client);
1769
1770 ethumb_file_free(client->ethumb);
1771}
1772
1773/**
1774 * Set a defined path and key to store the thumbnail.
1775 *
1776 * If not explicitly given, the thumbnail path will be auto-generated
1777 * by ethumb_client_thumb_exists() or server using configured
1778 * parameters like size, aspect and category.
1779 *
1780 * Set these to @c NULL to forget previously given values. After
1781 * ethumb_client_file_set() these values will be reset to @c NULL.
1782 *
1783 * @param client the client instance to use. Must @b not be @c
1784 * NULL. May be pending connected (can be called before @c
1785 * connected_cb)
1786 * @param path force generated thumbnail to the exact given path. If
1787 * @c NULL, then reverts back to auto-generation.
1788 * @param key force generated thumbnail to the exact given key. If
1789 * @c NULL, then reverts back to auto-generation.
1790 */
1791EAPI void
1792ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key)
1793{
1794 EINA_SAFETY_ON_NULL_RETURN(client);
1795
1796 ethumb_thumb_path_set(client->ethumb, path, key);
1797}
1798
1799/**
1800 * Get the configured thumbnail path.
1801 *
1802 * This returns the value set with ethumb_client_thumb_path_set() or
1803 * auto-generated by ethumb_client_thumb_exists() if it was not set.
1804 *
1805 * @param client the client instance to use. Must @b not be @c
1806 * NULL. May be pending connected (can be called before @c
1807 * connected_cb)
1808 * @param path where to return configured path. May be @c NULL. If
1809 * there was no path configured with
1810 * ethumb_client_thumb_path_set() and
1811 * ethumb_client_thumb_exists() was not called, then it will
1812 * probably return @c NULL. If not @c NULL, then it will be a
1813 * pointer to a stringshared instance, but @b no references are
1814 * added (do it with eina_stringshare_ref())!
1815 * @param key where to return configured key. May be @c NULL. If
1816 * there was no key configured with
1817 * ethumb_client_thumb_key_set() and
1818 * ethumb_client_thumb_exists() was not called, then it will
1819 * probably return @c NULL. If not @c NULL, then it will be a
1820 * pointer to a stringshared instance, but @b no references are
1821 * added (do it with eina_stringshare_ref())!
1822 */
1823EAPI void
1824ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key)
1825{
1826 if (path) *path = NULL;
1827 if (key) *key = NULL;
1828 EINA_SAFETY_ON_NULL_RETURN(client);
1829
1830 ethumb_thumb_path_get(client->ethumb, path, key);
1831}
1832
1833/**
1834 * Checks whenever file already exists (locally!)
1835 *
1836 * This will check locally (not calling server) if thumbnail already
1837 * exists or not, also calculating the thumbnail path. See
1838 * ethumb_client_thumb_path_get(). Path must be configured with
1839 * ethumb_client_file_set() before using it and the last set file will
1840 * be used!
1841 *
1842 * @param client client instance. Must @b not be @c NULL and client
1843 * must be configured with ethumb_client_file_set().
1844 *
1845 * @return @c EINA_TRUE if it exists, @c EINA_FALSE otherwise.
1846 */
1847EAPI Ethumb_Exists *
1848ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)
1849{
1850 const char *path = NULL;
1851 Ethumb_Async_Exists *async = NULL;
1852 Ethumb_Exists *cb = NULL;
1853 Ecore_Thread *t;
1854
1855 EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
1856
1857 ethumb_file_get(client->ethumb, &path, NULL);
1858 if (!path) goto on_error;
1859
1860 async = eina_hash_find(_exists_request, path);
1861 if (!async)
1862 {
1863 async = malloc(sizeof (Ethumb_Async_Exists));
1864 if (!async) goto on_error;
1865
1866 async->path = eina_stringshare_ref(path);
1867 async->callbacks = NULL;
1868 async->dup = ethumb_dup(client->ethumb);
1869
1870 if (!async->dup) goto on_error;
1871
1872 cb = malloc(sizeof (Ethumb_Exists));
1873 if (!cb) goto on_error;
1874
1875 EINA_REFCOUNT_REF(client);
1876 cb->client = client;
1877 cb->dup = ethumb_dup(client->ethumb);
1878 cb->exists_cb = exists_cb;
1879 cb->data = data;
1880 cb->parent = async;
1881
1882 async->callbacks = eina_list_append(async->callbacks, cb);
1883
1884 /* spawn a thread here */
1885 t = ecore_thread_run(_ethumb_client_exists_heavy,
1886 _ethumb_client_exists_end,
1887 _ethumb_client_exists_end,
1888 async);
1889 if (!t) return NULL;
1890 async->thread = t;
1891
1892 eina_hash_direct_add(_exists_request, async->path, async);
1893
1894 return cb;
1895 }
1896
1897 cb = malloc(sizeof (Ethumb_Exists));
1898 if (!cb)
1899 {
1900 async = NULL;
1901 goto on_error;
1902 }
1903
1904 EINA_REFCOUNT_REF(client);
1905 cb->client = client;
1906 cb->dup = ethumb_dup(client->ethumb);
1907 cb->exists_cb = exists_cb;
1908 cb->data = data;
1909 cb->parent = async;
1910
1911 async->callbacks = eina_list_append(async->callbacks, cb);
1912
1913 return cb;
1914
1915on_error:
1916 exists_cb((void *)data, client, NULL, EINA_FALSE);
1917
1918 if (async)
1919 {
1920 eina_stringshare_del(async->path);
1921 if (async->dup) ethumb_free(async->dup);
1922 free(async);
1923 }
1924 return NULL;
1925}
1926
1927/**
1928 * Cancel an ongoing exists request.
1929 *
1930 * @param exists the request to cancel.
1931 */
1932EAPI void
1933ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists)
1934{
1935 Ethumb_Async_Exists *async = exists->parent;
1936
1937 async->callbacks = eina_list_remove(async->callbacks, exists);
1938 if (eina_list_count(async->callbacks) <= 0)
1939 ecore_thread_cancel(async->thread);
1940
1941 ethumb_free(exists->dup);
1942 EINA_REFCOUNT_UNREF(exists->client)
1943 _ethumb_client_free(exists->client);
1944 free(exists);
1945}
1946
1947/**
1948 * Check if an exists request was cancelled.
1949 *
1950 * @param exists the request to check.
1951 * @result return EINA_TRUE if the request was cancelled.
1952 */
1953EAPI Eina_Bool
1954ethumb_client_thumb_exists_check(Ethumb_Exists *exists)
1955{
1956 Ethumb_Async_Exists *async = exists->parent;
1957
1958 if (!async) return EINA_TRUE;
1959
1960 if (async->callbacks) return EINA_FALSE;
1961
1962 return ecore_thread_check(async->thread);
1963}
1964
1965/**
1966 * Ask server to generate thumbnail.
1967 *
1968 * This process is asynchronous and will report back from main loop
1969 * using @a generated_cb. One can cancel this request by calling
1970 * ethumb_client_generate_cancel() or
1971 * ethumb_client_generate_cancel_all(), but not that request might be
1972 * processed by server already and no generated files will be removed
1973 * if that is the case.
1974 *
1975 * This will not check if file already exists, this should be done by
1976 * explicitly calling ethumb_client_thumb_exists(). That is, this
1977 * function will override any existing thumbnail.
1978 *
1979 * @param client client instance. Must @b not be @c NULL and client
1980 * must be connected (after connected_cb is called).
1981 * @param generated_cb function to report generation results.
1982 * @param data context argument to give back to @a generated_cb. May
1983 * be @c NULL.
1984 * @param data context to give back to @a generate_cb. May be @c
1985 * NULL.
1986 * @param free_data used to release @a data resources after @a
1987 * generated_cb is called or user calls
1988 * ethumb_client_disconnect().
1989 *
1990 * @return identifier or -1 on error. If -1 is returned (error) then
1991 * @a free_data is @b not called!
1992 *
1993 * @see ethumb_client_connect()
1994 * @see ethumb_client_file_set()
1995 * @see ethumb_client_thumb_exists()
1996 * @see ethumb_client_generate_cancel()
1997 * @see ethumb_client_generate_cancel_all()
1998 */
1999EAPI int
2000ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
2001{
2002 const char *file, *key, *thumb, *thumb_key;
2003 int id;
2004 EINA_SAFETY_ON_NULL_RETURN_VAL(client, -1);
2005 EINA_SAFETY_ON_FALSE_RETURN_VAL(client->connected, -1);
2006
2007 ethumb_file_get(client->ethumb, &file, &key);
2008 if (!file)
2009 {
2010 ERR("no file set.");
2011 return -1;
2012 }
2013
2014 ethumb_thumb_path_get(client->ethumb, &thumb, &thumb_key);
2015
2016 if (client->old_ethumb_conf &&
2017 ethumb_cmp(client->old_ethumb_conf, client->ethumb))
2018 {
2019 ethumb_client_ethumb_setup(client);
2020 ethumb_free(client->old_ethumb_conf);
2021 client->old_ethumb_conf = NULL;
2022 }
2023 id = _ethumb_client_queue_add(client, file, key, thumb, thumb_key,
2024 generated_cb, data, free_data);
2025 return id;
2026}
2027
2028struct _Ethumb_Client_Async
2029{
2030 Ethumb_Exists *exists;
2031 Ethumb_Client *client;
2032 Ethumb *dup;
2033
2034 Ethumb_Client_Async_Done_Cb done;
2035 Ethumb_Client_Async_Error_Cb error;
2036 const void *data;
2037
2038 int id;
2039};
2040
2041static Ecore_Idler *idler[2] = { NULL, NULL };
2042static Eina_List *pending = NULL;
2043static Eina_List *idle_tasks[2] = { NULL, NULL };
2044
2045static void
2046_ethumb_client_async_free(Ethumb_Client_Async *async)
2047{
2048 EINA_REFCOUNT_UNREF(async->client)
2049 _ethumb_client_free(async->client);
2050 ethumb_free(async->dup);
2051 free(async);
2052}
2053
2054static void
2055_ethumb_client_thumb_finish(void *data,
2056 Ethumb_Client *client, int id,
2057 const char *file EINA_UNUSED, const char *key EINA_UNUSED,
2058 const char *thumb_path, const char *thumb_key,
2059 Eina_Bool success)
2060{
2061 Ethumb_Client_Async *async = data;
2062
2063 EINA_SAFETY_ON_FALSE_RETURN(async->id == id);
2064
2065 if (success)
2066 {
2067 async->done(client, thumb_path, thumb_key, (void *)async->data);
2068 }
2069 else
2070 {
2071 async->error(client, (void *)async->data);
2072 }
2073
2074 pending = eina_list_remove(pending, async);
2075 _ethumb_client_async_free(async);
2076}
2077
2078static Eina_Bool
2079_ethumb_client_thumb_generate_idler(void *data EINA_UNUSED)
2080{
2081 Ethumb_Client_Async *async;
2082 Eina_List *l1, *l2;
2083
2084 EINA_LIST_FOREACH_SAFE (idle_tasks[1], l1, l2, async)
2085 {
2086 Ethumb *tmp;
2087
2088 idle_tasks[1] = eina_list_remove_list(idle_tasks[1], l1);
2089
2090 tmp = async->client->ethumb;
2091 async->client->ethumb = async->dup;
2092
2093 async->id = ethumb_client_generate(async->client, _ethumb_client_thumb_finish, async, NULL);
2094 if (async->id == -1)
2095 {
2096 async->error(async->client, (void *)async->data);
2097 async->client->ethumb = tmp;
2098 _ethumb_client_async_free(async);
2099 }
2100 else
2101 {
2102 async->client->ethumb = tmp;
2103 }
2104
2105 pending = eina_list_append(pending, async);
2106
2107 if (ecore_time_get() - ecore_loop_time_get() > ecore_animator_frametime_get() * 0.5)
2108 return EINA_TRUE;
2109 }
2110
2111 idler[1] = NULL;
2112 return EINA_FALSE;
2113}
2114
2115static void
2116_ethumb_client_thumb_exists(void *data, Ethumb_Client *client, Ethumb_Exists *request, Eina_Bool exists)
2117{
2118 Ethumb_Client_Async *async = data;
2119
2120 if (request == NULL)
2121 return;
2122
2123 EINA_SAFETY_ON_FALSE_RETURN(async->exists == request);
2124
2125 async->exists = NULL;
2126 pending = eina_list_remove(pending, async);
2127
2128 if (exists)
2129 {
2130 const char *thumb_path;
2131 const char *thumb_key;
2132
2133 ethumb_client_thumb_path_get(client, &thumb_path, &thumb_key);
2134 async->done(client, thumb_path, thumb_key, (void *)async->data);
2135 _ethumb_client_async_free(async);
2136 }
2137 else
2138 {
2139 idle_tasks[1] = eina_list_append(idle_tasks[1], async);
2140
2141 if (!idler[1])
2142 idler[1] = ecore_idler_add(_ethumb_client_thumb_generate_idler, NULL);
2143 }
2144}
2145
2146static Eina_Bool
2147_ethumb_client_thumb_exists_idler(void *data EINA_UNUSED)
2148{
2149 Ethumb_Client_Async *async;
2150 Eina_List *l1, *l2;
2151
2152 EINA_LIST_FOREACH_SAFE (idle_tasks[0], l1, l2, async)
2153 {
2154 Ethumb *tmp;
2155
2156 idle_tasks[0] = eina_list_remove_list(idle_tasks[0], l1);
2157
2158 tmp = async->client->ethumb;
2159 async->client->ethumb = async->dup;
2160
2161 async->exists = ethumb_client_thumb_exists(async->client, _ethumb_client_thumb_exists, async);
2162 if (!async->exists)
2163 {
2164 async->error(async->client, (void *)async->data);
2165 async->client->ethumb = tmp;
2166 _ethumb_client_async_free(async);
2167 continue;
2168 }
2169
2170 async->client->ethumb = tmp;
2171
2172 pending = eina_list_append(pending, async);
2173
2174 if (ecore_time_get() - ecore_loop_time_get() > ecore_animator_frametime_get() * 0.5)
2175 return EINA_TRUE;
2176 }
2177
2178 idler[0] = NULL;
2179 return EINA_FALSE;
2180}
2181
2182EAPI Ethumb_Client_Async *
2183ethumb_client_thumb_async_get(Ethumb_Client *client,
2184 Ethumb_Client_Async_Done_Cb done,
2185 Ethumb_Client_Async_Error_Cb error,
2186 const void *data)
2187{
2188 Ethumb_Client_Async *async;
2189
2190 EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
2191
2192 async = malloc(sizeof (Ethumb_Client_Async));
2193 if (!async)
2194 {
2195 error(client, (void *)data);
2196 return NULL;
2197 }
2198
2199 EINA_REFCOUNT_REF(client);
2200 async->client = client;
2201 async->dup = ethumb_dup(client->ethumb);
2202 async->done = done;
2203 async->error = error;
2204 async->data = data;
2205 async->exists = NULL;
2206 async->id = -1;
2207
2208 idle_tasks[0] = eina_list_append(idle_tasks[0], async);
2209
2210 if (!idler[0])
2211 idler[0] = ecore_idler_add(_ethumb_client_thumb_exists_idler, NULL);
2212
2213 return async;
2214}
2215
2216EAPI void
2217ethumb_client_thumb_async_cancel(Ethumb_Client *client, Ethumb_Client_Async *request)
2218{
2219 const char *path;
2220
2221 EINA_SAFETY_ON_NULL_RETURN(client);
2222 EINA_SAFETY_ON_NULL_RETURN(request);
2223
2224 ethumb_file_get(request->dup, &path, NULL);
2225
2226 if (request->exists)
2227 {
2228 ethumb_client_thumb_exists_cancel(request->exists);
2229 request->exists = NULL;
2230
2231 pending = eina_list_remove(pending, request);
2232 }
2233 else if (request->id != -1)
2234 {
2235 Ethumb *tmp = request->client->ethumb;
2236 request->client->ethumb = request->dup;
2237
2238 ethumb_client_generate_cancel(request->client, request->id, NULL, NULL, NULL);
2239
2240 request->client->ethumb = tmp;
2241
2242 pending = eina_list_remove(pending, request);
2243 }
2244 else
2245 {
2246 idle_tasks[0] = eina_list_remove(idle_tasks[0], request);
2247 idle_tasks[1] = eina_list_remove(idle_tasks[1], request);
2248 }
2249
2250 _ethumb_client_async_free(request);
2251}
diff --git a/src/lib/ethumb/ethumb.c b/src/lib/ethumb/ethumb.c
new file mode 100644
index 0000000000..65d3b97c84
--- /dev/null
+++ b/src/lib/ethumb/ethumb.c
@@ -0,0 +1,1863 @@
1/**
2 * @file
3 *
4 * Copyright (C) 2009 by ProFUSION embedded systems
5 *
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.
10 *
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.
15 *
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/>.
19 *
20 * @author Rafael Antognolli <antognolli@profusion.mobi>
21 */
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#ifdef STDC_HEADERS
27# include <stdlib.h>
28# include <stddef.h>
29#else
30# ifdef HAVE_STDLIB_H
31# include <stdlib.h>
32# endif
33#endif
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <limits.h>
38#include <string.h>
39#include <unistd.h>
40#include <errno.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <dirent.h>
44#include <dlfcn.h>
45#include <ctype.h>
46
47#ifdef HAVE_XATTR
48# include <sys/xattr.h>
49#endif
50
51#ifndef PATH_MAX
52# define PATH_MAX 4096
53#endif
54
55#ifdef HAVE_LIBEXIF
56 #include <libexif/exif-data.h>
57#endif
58
59#ifdef HAVE_EVIL
60# include <Evil.h>
61#endif
62
63#include <Eina.h>
64#include <eina_safety_checks.h>
65#include <Evas.h>
66#include <Ecore.h>
67#include <Ecore_Evas.h>
68#include <Ecore_File.h>
69#include <Edje.h>
70
71#include "Ethumb.h"
72#include "ethumb_private.h"
73#include "Ethumb_Plugin.h"
74#include "md5.h"
75
76static Ethumb_Version _version = { VMAJ, VMIN, VMIC, VREV };
77EAPI Ethumb_Version *ethumb_version = &_version;
78
79static int _log_dom = -1;
80#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
81#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
82#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
83#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
84
85static int initcount = 0;
86static const char *_home_thumb_dir = NULL;
87static const char *_thumb_category_normal = NULL;
88static const char *_thumb_category_large = NULL;
89
90static const int THUMB_SIZE_NORMAL = 128;
91static const int THUMB_SIZE_LARGE = 256;
92
93static Eina_Hash *_plugins_ext = NULL;
94static Eina_Array *_plugins = NULL;
95static Eina_Prefix *_pfx = NULL;
96
97static Eina_Bool
98_ethumb_plugin_list_cb(Eina_Module *m, void *data EINA_UNUSED)
99{
100 const char *file;
101 const char **ext;
102 Ethumb_Plugin *plugin;
103 Ethumb_Plugin *(*plugin_get)(void);
104
105 file = eina_module_file_get(m);
106 if (!eina_module_load(m))
107 {
108 ERR("could not load module \"%s\": %s",
109 file, eina_error_msg_get(eina_error_get()));
110 return EINA_FALSE;
111 }
112
113 plugin_get = eina_module_symbol_get(m, "ethumb_plugin_get");
114 if (!plugin_get)
115 {
116 ERR("could not find ethumb_plugin_get() in module \"%s\": %s",
117 file, eina_error_msg_get(eina_error_get()));
118 eina_module_unload(m);
119 return EINA_FALSE;
120 }
121
122 plugin = plugin_get();
123 if (!plugin)
124 {
125 ERR("plugin \"%s\" failed to init.", file);
126 eina_module_unload(m);
127 return EINA_FALSE;
128 }
129
130 DBG("loaded plugin \"%s\" (%p) with extensions:", file, plugin);
131 for (ext = plugin->extensions; *ext; ext++)
132 {
133 DBG(" extension \"%s\"", *ext);
134 eina_hash_add(_plugins_ext, *ext, plugin);
135 }
136
137 return EINA_TRUE;
138}
139
140static void
141_ethumb_plugins_load(void)
142{
143 char buf[PATH_MAX];
144
145 _plugins_ext = eina_hash_string_small_new(NULL);
146 EINA_SAFETY_ON_NULL_RETURN(_plugins_ext);
147
148 snprintf(buf, sizeof(buf), "%s/ethumb/modules", eina_prefix_lib_get(_pfx));
149 _plugins = eina_module_list_get(_plugins, buf, 1,
150 &_ethumb_plugin_list_cb, NULL);
151}
152
153static void
154_ethumb_plugins_unload(void)
155{
156 eina_hash_free(_plugins_ext);
157 _plugins_ext = NULL;
158 eina_module_list_unload(_plugins);
159 eina_module_list_free(_plugins);
160 eina_array_free(_plugins);
161 _plugins = NULL;
162}
163
164EAPI int
165ethumb_init(void)
166{
167 const char *home;
168 char buf[PATH_MAX];
169
170 if (initcount)
171 return ++initcount;
172
173 if (!eina_init())
174 {
175 fprintf(stderr, "ERROR: Could not initialize eina.\n");
176 return 0;
177 }
178 _log_dom = eina_log_domain_register("ethumb", EINA_COLOR_GREEN);
179 if (_log_dom < 0)
180 {
181 EINA_LOG_ERR("Could not register log domain: ethumb");
182 goto error_log;
183 }
184
185 _pfx = eina_prefix_new(NULL, ethumb_init,
186 "ETHUMB", "ethumb", "checkme",
187 PACKAGE_BIN_DIR, PACKAGE_LIB_DIR,
188 PACKAGE_DATA_DIR, PACKAGE_DATA_DIR);
189 if (!_pfx)
190 {
191 ERR("Could not get ethumb installation prefix.");
192 goto error_pfx;
193 }
194
195 evas_init();
196 ecore_init();
197 ecore_evas_init();
198 edje_init();
199
200 home = getenv("HOME");
201 snprintf(buf, sizeof(buf), "%s/.thumbnails", home);
202
203 _home_thumb_dir = eina_stringshare_add(buf);
204 _thumb_category_normal = eina_stringshare_add("normal");
205 _thumb_category_large = eina_stringshare_add("large");
206
207 _ethumb_plugins_load();
208 return ++initcount;
209
210 error_pfx:
211 eina_log_domain_unregister(_log_dom);
212 _log_dom = -1;
213
214 error_log:
215 eina_shutdown();
216 return 0;
217}
218
219EAPI int
220ethumb_shutdown(void)
221{
222 if (initcount <= 0)
223 {
224 EINA_LOG_ERR("Init count not greater than 0 in shutdown.");
225 return 0;
226 }
227 initcount--;
228 if (initcount == 0)
229 {
230 _ethumb_plugins_unload();
231 eina_stringshare_del(_home_thumb_dir);
232 eina_stringshare_del(_thumb_category_normal);
233 eina_stringshare_del(_thumb_category_large);
234 evas_shutdown();
235 ecore_shutdown();
236 ecore_evas_shutdown();
237 edje_shutdown();
238 eina_prefix_free(_pfx);
239 _pfx = NULL;
240 eina_log_domain_unregister(_log_dom);
241 _log_dom = -1;
242 eina_shutdown();
243 }
244
245 return initcount;
246}
247
248EAPI Ethumb *
249ethumb_new(void)
250{
251 Ethumb *ethumb;
252 Ecore_Evas *ee, *sub_ee;
253 Evas *e, *sub_e;
254 Evas_Object *o, *img;
255
256 ethumb = calloc(1, sizeof(Ethumb));
257 EINA_SAFETY_ON_NULL_RETURN_VAL(ethumb, NULL);
258
259 /* IF CHANGED, UPDATE DOCS in (Ethumb.c, Ethumb_Client.c, python...)!!! */
260 ethumb->tw = THUMB_SIZE_NORMAL;
261 ethumb->th = THUMB_SIZE_NORMAL;
262 ethumb->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
263 ethumb->crop_x = 0.5;
264 ethumb->crop_y = 0.5;
265 ethumb->quality = 80;
266 ethumb->compress = 9;
267 ethumb->video.start = 0.1;
268 ethumb->video.time = 3;
269 ethumb->video.interval = 0.05;
270 ethumb->video.ntimes = 3;
271 ethumb->video.fps = 10;
272
273 ee = ecore_evas_buffer_new(1, 1);
274 e = ecore_evas_get(ee);
275 if (!e)
276 {
277 ERR("could not create ecore evas buffer");
278 free(ethumb);
279 return NULL;
280 }
281
282 evas_image_cache_set(e, 0);
283 evas_font_cache_set(e, 0);
284
285 o = ecore_evas_object_image_new(ee);
286 if (!o)
287 {
288 ERR("could not create sub ecore evas buffer");
289 ecore_evas_free(ee);
290 free(ethumb);
291 return NULL;
292 }
293
294 sub_ee = ecore_evas_object_ecore_evas_get(o);
295 sub_e = ecore_evas_object_evas_get(o);
296 ecore_evas_alpha_set(sub_ee, EINA_TRUE);
297
298 evas_image_cache_set(sub_e, 0);
299 evas_font_cache_set(sub_e, 0);
300
301 img = evas_object_image_add(sub_e);
302 if (!img)
303 {
304 ERR("could not create source objects.");
305 ecore_evas_free(ee);
306 free(ethumb);
307 return NULL;
308 }
309
310 ethumb->ee = ee;
311 ethumb->e = e;
312 ethumb->sub_ee = sub_ee;
313 ethumb->sub_e = sub_e;
314 ethumb->o = o;
315 ethumb->img = img;
316
317 DBG("ethumb=%p", ethumb);
318
319 return ethumb;
320}
321
322static void
323_ethumb_frame_free(Ethumb_Frame *frame)
324{
325 Evas_Object *o;
326
327 if (!frame)
328 return;
329
330 if (frame->swallow && frame->edje)
331 {
332 o = edje_object_part_swallow_get(frame->edje, frame->swallow);
333 if (o)
334 edje_object_part_unswallow(frame->edje, o);
335 }
336 eina_stringshare_del(frame->file);
337 eina_stringshare_del(frame->group);
338 eina_stringshare_del(frame->swallow);
339
340 if (frame->edje)
341 evas_object_del(frame->edje);
342
343 free(frame);
344}
345
346EAPI void
347ethumb_free(Ethumb *ethumb)
348{
349 EINA_SAFETY_ON_NULL_RETURN(ethumb);
350
351 DBG("ethumb=%p", ethumb);
352
353 if (ethumb->frame)
354 _ethumb_frame_free(ethumb->frame);
355 ethumb_file_free(ethumb);
356 evas_object_del(ethumb->o);
357 ecore_evas_free(ethumb->ee);
358 eina_stringshare_del(ethumb->thumb_dir);
359 eina_stringshare_del(ethumb->category);
360 if (ethumb->finished_idler)
361 ecore_idler_del(ethumb->finished_idler);
362 free(ethumb);
363}
364
365EAPI void
366ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s)
367{
368 EINA_SAFETY_ON_NULL_RETURN(e);
369 EINA_SAFETY_ON_FALSE_RETURN(s == ETHUMB_THUMB_NORMAL ||
370 s == ETHUMB_THUMB_LARGE);
371 DBG("ethumb=%p, size=%d", e, s);
372
373 if (s == ETHUMB_THUMB_NORMAL)
374 {
375 e->tw = THUMB_SIZE_NORMAL;
376 e->th = THUMB_SIZE_NORMAL;
377 }
378 else
379 {
380 e->tw = THUMB_SIZE_LARGE;
381 e->th = THUMB_SIZE_LARGE;
382 }
383
384 e->format = ETHUMB_THUMB_FDO;
385 e->aspect = ETHUMB_THUMB_KEEP_ASPECT;
386 e->orientation = ETHUMB_THUMB_ORIENT_ORIGINAL;
387 _ethumb_frame_free(e->frame);
388 e->frame = NULL;
389 eina_stringshare_del(e->thumb_dir);
390 eina_stringshare_del(e->category);
391 e->thumb_dir = NULL;
392 e->category = NULL;
393}
394
395EAPI void
396ethumb_thumb_size_set(Ethumb *e, int tw, int th)
397{
398 EINA_SAFETY_ON_NULL_RETURN(e);
399 EINA_SAFETY_ON_FALSE_RETURN(tw > 0);
400 EINA_SAFETY_ON_FALSE_RETURN(th > 0);
401
402 DBG("ethumb=%p, w=%d, h=%d", e, tw, th);
403 e->tw = tw;
404 e->th = th;
405}
406
407EAPI void
408ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th)
409{
410 EINA_SAFETY_ON_NULL_RETURN(e);
411
412 if (tw) *tw = e->tw;
413 if (th) *th = e->th;
414}
415
416EAPI void
417ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f)
418{
419 EINA_SAFETY_ON_NULL_RETURN(e);
420 EINA_SAFETY_ON_FALSE_RETURN(f == ETHUMB_THUMB_FDO ||
421 f == ETHUMB_THUMB_JPEG ||
422 f == ETHUMB_THUMB_EET);
423
424 DBG("ethumb=%p, format=%d", e, f);
425 e->format = f;
426}
427
428EAPI Ethumb_Thumb_Format
429ethumb_thumb_format_get(const Ethumb *e)
430{
431 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
432 return e->format;
433}
434
435EAPI void
436ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a)
437{
438 EINA_SAFETY_ON_NULL_RETURN(e);
439 EINA_SAFETY_ON_FALSE_RETURN(a == ETHUMB_THUMB_KEEP_ASPECT ||
440 a == ETHUMB_THUMB_IGNORE_ASPECT ||
441 a == ETHUMB_THUMB_CROP);
442
443 DBG("ethumb=%p, aspect=%d", e, a);
444 e->aspect = a;
445}
446
447EAPI Ethumb_Thumb_Aspect
448ethumb_thumb_aspect_get(const Ethumb *e)
449{
450 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
451 return e->aspect;
452}
453
454EAPI void
455ethumb_thumb_orientation_set(Ethumb *e, Ethumb_Thumb_Orientation o)
456{
457 EINA_SAFETY_ON_NULL_RETURN(e);
458 EINA_SAFETY_ON_FALSE_RETURN(o == ETHUMB_THUMB_ORIENT_NONE ||
459 o == ETHUMB_THUMB_ROTATE_90_CW ||
460 o == ETHUMB_THUMB_ROTATE_180 ||
461 o == ETHUMB_THUMB_ROTATE_90_CCW ||
462 o == ETHUMB_THUMB_FLIP_HORIZONTAL ||
463 o == ETHUMB_THUMB_FLIP_VERTICAL ||
464 o == ETHUMB_THUMB_FLIP_TRANSPOSE ||
465 o == ETHUMB_THUMB_FLIP_TRANSVERSE ||
466 o == ETHUMB_THUMB_ORIENT_ORIGINAL);
467
468 DBG("ethumb=%p, orientation=%d", e, o);
469 e->orientation = o;
470}
471
472EAPI Ethumb_Thumb_Orientation
473ethumb_thumb_orientation_get(const Ethumb *e)
474{
475 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
476 return e->orientation;
477}
478
479EAPI void
480ethumb_thumb_crop_align_set(Ethumb *e, float x, float y)
481{
482 EINA_SAFETY_ON_NULL_RETURN(e);
483
484 DBG("ethumb=%p, x=%f, y=%f", e, x, y);
485 e->crop_x = x;
486 e->crop_y = y;
487}
488
489EAPI void
490ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y)
491{
492 EINA_SAFETY_ON_NULL_RETURN(e);
493
494 if (x) *x = e->crop_x;
495 if (y) *y = e->crop_y;
496}
497
498EAPI void
499ethumb_thumb_quality_set(Ethumb *e, int quality)
500{
501 EINA_SAFETY_ON_NULL_RETURN(e);
502
503 DBG("ethumb=%p, quality=%d", e, quality);
504 e->quality = quality;
505}
506
507EAPI int
508ethumb_thumb_quality_get(const Ethumb *e)
509{
510 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
511 return e->quality;
512}
513
514EAPI void
515ethumb_thumb_compress_set(Ethumb *e, int compress)
516{
517 EINA_SAFETY_ON_NULL_RETURN(e);
518
519 DBG("ethumb=%p, compress=%d", e, compress);
520 e->compress = compress;
521}
522
523EAPI int
524ethumb_thumb_compress_get(const Ethumb *e)
525{
526 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
527 return e->compress;
528}
529
530EAPI Eina_Bool
531ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow)
532{
533 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
534
535 Ethumb_Frame *frame;
536 frame = e->frame;
537
538 DBG("ethumb=%p, theme_file=%s, group=%s, swallow=%s",
539 e, theme_file ? theme_file : "", group ? group : "",
540 swallow ? swallow : "");
541
542 if (frame)
543 {
544 edje_object_part_unswallow(frame->edje, e->img);
545 if (!theme_file)
546 _ethumb_frame_free(frame);
547 }
548
549 if (!theme_file)
550 {
551 e->frame = NULL;
552 return EINA_FALSE;
553 }
554
555 if (!frame)
556 {
557 frame = calloc(1, sizeof(Ethumb_Frame));
558 if (!frame)
559 {
560 ERR("could not allocate Ethumb_Frame structure.");
561 return EINA_FALSE;
562 }
563
564 frame->edje = edje_object_add(e->sub_e);
565 if (!frame->edje)
566 {
567 ERR("could not create edje frame object.");
568 _ethumb_frame_free(frame);
569 e->frame = NULL;
570 return EINA_FALSE;
571 }
572 }
573
574 if (!edje_object_file_set(frame->edje, theme_file, group))
575 {
576 ERR("could not load frame theme.");
577 _ethumb_frame_free(frame);
578 e->frame = NULL;
579 return EINA_FALSE;
580 }
581
582 edje_object_part_swallow(frame->edje, swallow, e->img);
583 if (!edje_object_part_swallow_get(frame->edje, swallow))
584 {
585 ERR("could not swallow image to edje frame.");
586 _ethumb_frame_free(frame);
587 e->frame = NULL;
588 return EINA_FALSE;
589 }
590
591 eina_stringshare_replace(&frame->file, theme_file);
592 eina_stringshare_replace(&frame->group, group);
593 eina_stringshare_replace(&frame->swallow, swallow);
594
595 e->frame = frame;
596
597 return EINA_TRUE;
598}
599
600EAPI void
601ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow)
602{
603 EINA_SAFETY_ON_NULL_RETURN(e);
604
605 if (e->frame)
606 {
607 if (theme_file) *theme_file = e->frame->file;
608 if (group) *group = e->frame->group;
609 if (swallow) *swallow = e->frame->swallow;
610 }
611 else
612 {
613 if (theme_file) *theme_file = NULL;
614 if (group) *group = NULL;
615 if (swallow) *swallow = NULL;
616 }
617}
618
619static const char *
620_ethumb_build_absolute_path(const char *path, char buf[PATH_MAX])
621{
622 char *p;
623 int len;
624
625 if (!path)
626 return NULL;
627
628 p = buf;
629
630 if (path[0] == '/')
631 strcpy(p, path);
632 else if (path[0] == '~')
633 {
634 const char *home = getenv("HOME");
635 if (!home)
636 return NULL;
637 strcpy(p, home);
638 len = strlen(p);
639 p += len;
640 p[0] = '/';
641 p++;
642 strcpy(p, path + 2);
643 }
644 else
645 {
646 if (!getcwd(p, PATH_MAX))
647 return NULL;
648 len = strlen(p);
649 p += len;
650 p[0] = '/';
651 p++;
652 strcpy(p, path);
653 }
654
655 return buf;
656}
657
658EAPI void
659ethumb_thumb_dir_path_set(Ethumb *e, const char *path)
660{
661 char buf[PATH_MAX];
662 EINA_SAFETY_ON_NULL_RETURN(e);
663
664 DBG("ethumb=%p, path=%s", e, path ? path : "");
665 path = _ethumb_build_absolute_path(path, buf);
666 eina_stringshare_replace(&e->thumb_dir, path);
667}
668
669EAPI const char *
670ethumb_thumb_dir_path_get(const Ethumb *e)
671{
672 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
673
674 return e->thumb_dir;
675}
676
677EAPI void
678ethumb_thumb_category_set(Ethumb *e, const char *category)
679{
680 EINA_SAFETY_ON_NULL_RETURN(e);
681
682 DBG("ethumb=%p, category=%s", e, category ? category : "");
683 eina_stringshare_replace(&e->category, category);
684}
685
686EAPI const char *
687ethumb_thumb_category_get(const Ethumb *e)
688{
689 EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
690
691 return e->category;
692}
693
694EAPI void
695ethumb_video_start_set(Ethumb *e, float start)
696{
697 EINA_SAFETY_ON_NULL_RETURN(e);
698 EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);
699 EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);
700
701 DBG("ethumb=%p, video_start=%f", e, start);
702 e->video.start = start;
703}
704
705EAPI float
706ethumb_video_start_get(const Ethumb *e)
707{
708 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
709
710 return e->video.start;
711}
712
713EAPI void
714ethumb_video_time_set(Ethumb *e, float t)
715{
716 EINA_SAFETY_ON_NULL_RETURN(e);
717
718 DBG("ethumb=%p, video_start=%f", e, t);
719 e->video.time = t;
720}
721
722EAPI float
723ethumb_video_time_get(const Ethumb *e)
724{
725 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
726
727 return e->video.time;
728}
729
730EAPI void
731ethumb_video_interval_set(Ethumb *e, float interval)
732{
733 EINA_SAFETY_ON_NULL_RETURN(e);
734
735 DBG("ethumb=%p, video_interval=%f", e, interval);
736 e->video.interval = interval;
737}
738
739EAPI float
740ethumb_video_interval_get(const Ethumb *e)
741{
742 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
743
744 return e->video.interval;
745}
746
747EAPI void
748ethumb_video_ntimes_set(Ethumb *e, unsigned int ntimes)
749{
750 EINA_SAFETY_ON_NULL_RETURN(e);
751 EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);
752
753 DBG("ethumb=%p, video_ntimes=%d", e, ntimes);
754 e->video.ntimes = ntimes;
755}
756
757EAPI unsigned int
758ethumb_video_ntimes_get(const Ethumb *e)
759{
760 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
761
762 return e->video.ntimes;
763}
764
765EAPI void
766ethumb_video_fps_set(Ethumb *e, unsigned int fps)
767{
768 EINA_SAFETY_ON_NULL_RETURN(e);
769 EINA_SAFETY_ON_FALSE_RETURN(fps > 0);
770
771 DBG("ethumb=%p, video_fps=%d", e, fps);
772 e->video.fps = fps;
773}
774
775EAPI unsigned int
776ethumb_video_fps_get(const Ethumb *e)
777{
778 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
779
780 return e->video.fps;
781}
782
783EAPI void
784ethumb_document_page_set(Ethumb *e, unsigned int page)
785{
786 EINA_SAFETY_ON_NULL_RETURN(e);
787
788 DBG("ethumb=%p, document_page=%d", e, page);
789 e->document.page = page;
790}
791
792EAPI unsigned int
793ethumb_document_page_get(const Ethumb *e)
794{
795 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
796
797 return e->document.page;
798}
799
800EAPI Eina_Bool
801ethumb_file_set(Ethumb *e, const char *path, const char *key)
802{
803 char buf[PATH_MAX];
804 EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
805
806 eina_stringshare_replace(&e->thumb_path, NULL);
807 eina_stringshare_replace(&e->thumb_key, NULL);
808
809 DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
810 if (path && access(path, R_OK))
811 {
812 ERR("couldn't access file \"%s\"", path);
813 return EINA_FALSE;
814 }
815
816 path = _ethumb_build_absolute_path(path, buf);
817 eina_stringshare_replace(&e->src_hash, NULL);
818 eina_stringshare_replace(&e->src_path, path);
819 eina_stringshare_replace(&e->src_key, key);
820
821 return EINA_TRUE;
822}
823
824EAPI void
825ethumb_file_get(const Ethumb *e, const char **path, const char **key)
826{
827 EINA_SAFETY_ON_NULL_RETURN(e);
828
829 if (path) *path = e->src_path;
830 if (key) *key = e->src_key;
831}
832
833static const char ACCEPTABLE_URI_CHARS[96] = {
834 /* ! " # $ % & ' ( ) * + , - . / */
835 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
836 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
837 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
838 /* @ A B C D E F G H I J K L M N O */
839 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
840 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
841 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
842 /* ` a b c d e f g h i j k l m n o */
843 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
844 /* p q r s t u v w x y z { | } ~ DEL */
845 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
846};
847
848static const char *
849_ethumb_generate_hash(const char *file)
850{
851 int n;
852 MD5_CTX ctx;
853 char md5out[(2 * MD5_HASHBYTES) + 1];
854 unsigned char hash[MD5_HASHBYTES];
855 static const char hex[] = "0123456789abcdef";
856
857 char *uri;
858 char *t;
859 const unsigned char *c;
860
861#ifdef HAVE_XATTR
862 ssize_t length;
863
864 length = getxattr(file, "user.e.md5", NULL, 0);
865
866 if (length > 0)
867 {
868 char *tmp;
869
870 tmp = alloca(length);
871 length = getxattr(file, "user.e.md5", tmp, length);
872
873 /* check if we have at least something that look like a md5 hash */
874 if (length > 0 && (length == MD5_HASHBYTES * 2 + 1))
875 {
876 tmp[length] = '\0';
877 return eina_stringshare_add(tmp);
878 }
879 }
880#endif
881
882#define _check_uri_char(c) \
883 ((c) >= 32 && (c) < 128 && (ACCEPTABLE_URI_CHARS[(c) - 32] & 0x08))
884
885 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
886
887 uri = alloca(3 * strlen(file) + 9);
888 memcpy(uri, "file://", sizeof("file://") - 1);
889 t = uri + sizeof("file://") - 1;
890
891 for (c = (const unsigned char *)file; *c != '\0'; c++)
892 {
893 if (!_check_uri_char(*c))
894 {
895 *t++ = '%';
896 *t++ = hex[*c >> 4];
897 *t++ = hex[*c & 15];
898 }
899 else
900 *t++ = *c;
901 }
902 *t = '\0';
903
904#undef _check_uri_char
905
906 MD5Init (&ctx);
907 MD5Update (&ctx, (unsigned char const*)uri, (unsigned)strlen (uri));
908 MD5Final (hash, &ctx);
909
910 for (n = 0; n < MD5_HASHBYTES; n++)
911 {
912 md5out[2 * n] = hex[hash[n] >> 4];
913 md5out[2 * n + 1] = hex[hash[n] & 0x0f];
914 }
915 md5out[2 * n] = '\0';
916
917#ifdef HAVE_XATTR
918 setxattr(file, "user.e.md5", md5out, 2 * n + 1, 0);
919#endif
920
921 DBG("md5=%s, file=%s", md5out, file);
922 return eina_stringshare_add(md5out);
923}
924
925static int
926_ethumb_file_check_fdo(Ethumb *e)
927{
928 if (!((e->tw == THUMB_SIZE_NORMAL && e->th == THUMB_SIZE_NORMAL) ||
929 (e->tw == THUMB_SIZE_LARGE && e->th == THUMB_SIZE_LARGE)))
930 return 0;
931
932 if (e->format != ETHUMB_THUMB_FDO)
933 return 0;
934
935 if (e->aspect != ETHUMB_THUMB_KEEP_ASPECT)
936 return 0;
937
938 if (e->frame)
939 return 0;
940
941 return 1;
942}
943
944static const char *
945_ethumb_file_generate_custom_category(Ethumb *e)
946{
947 char buf[PATH_MAX];
948 const char *aspect, *format;
949 const char *frame;
950
951 if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
952 aspect = "keep_aspect";
953 else if (e->aspect == ETHUMB_THUMB_IGNORE_ASPECT)
954 aspect = "ignore_aspect";
955 else
956 aspect = "crop";
957
958 if (e->format == ETHUMB_THUMB_FDO)
959 format = "png";
960 else if (e->format == ETHUMB_THUMB_JPEG)
961 format = "jpg";
962 else
963 format = "eet";
964
965 if (e->frame)
966 frame = "-framed";
967 else
968 frame = "";
969
970 snprintf(buf, sizeof(buf), "%dx%d-%s%s-%s",
971 e->tw, e->th, aspect, frame, format);
972
973 return eina_stringshare_add(buf);
974}
975
976static void
977_ethumb_file_generate_path(Ethumb *e)
978{
979 char buf[PATH_MAX];
980 const char *thumb_dir, *category;
981 const char *ext;
982 int fdo_format;
983
984 fdo_format = _ethumb_file_check_fdo(e);
985
986 if (e->thumb_dir)
987 thumb_dir = eina_stringshare_ref(e->thumb_dir);
988 else
989 thumb_dir = eina_stringshare_ref(_home_thumb_dir);
990
991 if (e->category)
992 category = eina_stringshare_ref(e->category);
993 else if (!fdo_format)
994 category = _ethumb_file_generate_custom_category(e);
995 else
996 {
997 if (e->tw == THUMB_SIZE_NORMAL)
998 category = eina_stringshare_ref(_thumb_category_normal);