ephoto/src/bin/ephoto_thumbnailer.c

716 lines
22 KiB
C
Raw Normal View History

2016-03-24 10:14:39 -07:00
#include "ephoto.h"
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef _WIN32
# include <winsock2.h>
#endif
2016-03-24 10:14:39 -07:00
#define SHSH(n, v) ((((v) << (n)) & 0xffffffff) | ((v) >> (32 - (n))))
typedef struct _E_Thumb E_Thumb;
struct _E_Thumb
{
int objid;
int w, h;
char *file;
char *key;
};
/* local subsystem functions */
static int _e_ipc_init(void);
static Eina_Bool _e_ipc_cb_server_add(void *data,
int type,
void *event);
static Eina_Bool _e_ipc_cb_server_del(void *data,
int type,
void *event);
static Eina_Bool _e_ipc_cb_server_data(void *data,
int type,
void *event);
static Eina_Bool _e_cb_timer(void *data);
static void _e_thumb_generate(E_Thumb *eth);
static char *_e_thumb_file_id(char *file,
char *key);
/* local subsystem globals */
static Ecore_Ipc_Server *_e_ipc_server = NULL;
static Eina_List *_thumblist = NULL;
static Ecore_Timer *_timer = NULL;
static char _thumbdir[4096] = "";
/* externally accessible functions */
int
main(int argc,
char **argv)
{
int i;
for (i = 1; i < argc; i++)
{
if ((!strcmp(argv[i], "-h")) ||
(!strcmp(argv[i], "-help")) ||
(!strcmp(argv[i], "--help")))
{
printf(
"This is an internal tool for Ephoto.\n"
"do not use it.\n"
);
exit(0);
}
else if (!strncmp(argv[i], "--nice=", 7))
{
#ifdef HAVE_NICE
2016-03-24 10:14:39 -07:00
const char *val;
val = argv[i] + 7;
if (*val)
{
if (nice(atoi(val)) < 0) perror("nice");
}
#endif
2016-03-24 10:14:39 -07:00
}
}
ecore_app_no_system_modules();
ecore_init();
ecore_app_args_set(argc, (const char **)argv);
eet_init();
evas_init();
ecore_evas_init();
edje_init();
ecore_file_init();
ecore_ipc_init();
snprintf(_thumbdir, PATH_MAX, "%s/.thumbnails", getenv("HOME"));
2016-03-24 10:14:39 -07:00
ecore_file_mkpath(_thumbdir);
if (_e_ipc_init()) ecore_main_loop_begin();
if (_e_ipc_server)
{
ecore_ipc_server_del(_e_ipc_server);
_e_ipc_server = NULL;
}
ecore_ipc_shutdown();
ecore_file_shutdown();
ecore_evas_shutdown();
edje_shutdown();
evas_shutdown();
eet_shutdown();
ecore_shutdown();
return 0;
}
/* local subsystem functions */
static int
_e_ipc_init(void)
{
char *sdir;
sdir = getenv("EPHOTO_IPC_SOCKET");
if (!sdir)
{
printf("The EPHOTO_IPC_SOCKET environment variable is not set. This is\n"
"exported by Enlightenment to all processes it launches.\n"
"This environment variable must be set and must point to\n"
"Enlightenment's IPC socket file (minus port number).\n");
return 0;
}
_e_ipc_server = ecore_ipc_server_connect(ECORE_IPC_LOCAL_SYSTEM, sdir, 0, NULL);
if (!_e_ipc_server) return 0;
ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _e_ipc_cb_server_add, NULL);
ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _e_ipc_cb_server_del, NULL);
ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _e_ipc_cb_server_data, NULL);
return 1;
}
static Eina_Bool
_e_ipc_cb_server_add(void *data EINA_UNUSED,
int type EINA_UNUSED,
void *event)
{
Ecore_Ipc_Event_Server_Add *e;
e = event;
ecore_ipc_server_send(e->server,
EPHOTO_IPC_DOMAIN_THUMB,
1 /*hello*/,
0, 0, 0, NULL, 0); /* send hello */
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_ipc_cb_server_del(void *data EINA_UNUSED,
int type EINA_UNUSED,
void *event EINA_UNUSED)
{
/* quit now */
ecore_main_loop_quit();
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_ipc_cb_server_data(void *data EINA_UNUSED,
int type EINA_UNUSED,
void *event)
{
Ecore_Ipc_Event_Server_Data *e;
E_Thumb *eth;
Eina_List *l;
char *file = NULL;
char *key = NULL;
e = event;
if (e->major != EPHOTO_IPC_DOMAIN_THUMB) return ECORE_CALLBACK_PASS_ON;
switch (e->minor)
{
case 1:
if (e->data)
{
/* begin thumb */
/* don't check stuff. since this connects TO E it is connecting */
/* TO a trusted process that WILL send this message properly */
/* formatted. if the thumbnailer dies anyway - it's not a big loss */
/* but it is a sign of a bug in e formatting messages maybe */
file = e->data;
key = file + strlen(file) + 1;
if (!key[0]) key = NULL;
eth = calloc(1, sizeof(E_Thumb));
if (eth)
{
eth->objid = e->ref;
eth->w = e->ref_to;
eth->h = e->response;
eth->file = strdup(file);
if (key) eth->key = strdup(key);
_thumblist = eina_list_append(_thumblist, eth);
if (!_timer) _timer = ecore_timer_add(0.001, _e_cb_timer, NULL);
}
}
break;
case 2:
/* end thumb */
EINA_LIST_FOREACH(_thumblist, l, eth)
{
if (eth->objid == e->ref)
{
_thumblist = eina_list_remove_list(_thumblist, l);
free(eth->file);
free(eth->key);
free(eth);
break;
}
}
break;
case 3:
/* quit now */
ecore_main_loop_quit();
break;
default:
break;
}
return ECORE_CALLBACK_PASS_ON;
}
static Eina_Bool
_e_cb_timer(void *data EINA_UNUSED)
{
E_Thumb *eth;
/*
Eina_List *del_list = NULL, *l;
*/
/* take thumb at head of list */
if (_thumblist)
{
eth = eina_list_data_get(_thumblist);
_thumblist = eina_list_remove_list(_thumblist, _thumblist);
_e_thumb_generate(eth);
free(eth->file);
free(eth->key);
free(eth);
if (_thumblist) _timer = ecore_timer_add(0.01, _e_cb_timer, NULL);
else _timer = NULL;
}
else
_timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
typedef struct _Color Color;
struct _Color
{
Color *closest;
int closest_dist;
int use;
unsigned char r, g, b;
};
static void
_e_thumb_generate(E_Thumb *eth)
{
char buf[4096], dbuf[4096], *id, *td, *ext = NULL;
Evas *evas = NULL, *evas_im = NULL;
Ecore_Evas *ee = NULL, *ee_im = NULL;
Evas_Object *im = NULL, *edje = NULL;
Eet_File *ef = NULL;
int iw, ih, alpha, ww, hh;
const unsigned int *data = NULL;
time_t mtime_orig, mtime_thumb;
id = _e_thumb_file_id(eth->file, eth->key);
if (!id) return;
td = strdup(id);
if (!td)
{
free(id);
return;
}
td[2] = 0;
snprintf(dbuf, sizeof(dbuf), "%s/%s", _thumbdir, td);
snprintf(buf, sizeof(buf), "%s/%s/%s-%ix%i.thm",
_thumbdir, td, id + 2, eth->w, eth->h);
free(id);
free(td);
mtime_orig = ecore_file_mod_time(eth->file);
mtime_thumb = ecore_file_mod_time(buf);
while (mtime_thumb <= mtime_orig)
{
unsigned int *data1;
Eina_Bool sortkey;
Evas_Object *im2, *bg;
im = NULL;
im2 = NULL;
bg = NULL;
ecore_file_mkdir(dbuf);
edje_file_cache_set(0);
edje_collection_cache_set(0);
ee = ecore_evas_buffer_new(1, 1);
evas = ecore_evas_get(ee);
evas_image_cache_set(evas, 0);
evas_font_cache_set(evas, 0);
ww = 0;
hh = 0;
alpha = 1;
ext = strrchr(eth->file, '.');
sortkey = EINA_FALSE;
if ((ext) && (eth->key) &&
((!strcasecmp(ext, ".edj")) ||
(!strcasecmp(ext, ".eap"))))
{
ww = eth->w;
hh = eth->h;
im = ecore_evas_object_image_new(ee);
ee_im = evas_object_data_get(im, "Ecore_Evas");
evas_im = ecore_evas_get(ee_im);
evas_image_cache_set(evas_im, 0);
evas_font_cache_set(evas_im, 0);
evas_object_image_size_set(im, ww * 4, hh * 4);
evas_object_image_fill_set(im, 0, 0, ww, hh);
edje = edje_object_add(evas_im);
if ((eth->key) &&
((!strcmp(eth->key, "e/desktop/background")) ||
(!strcmp(eth->key, "e/init/splash"))))
alpha = 0;
if (edje_object_file_set(edje, eth->file, eth->key))
{
evas_object_move(edje, 0, 0);
evas_object_resize(edje, ww * 4, hh * 4);
evas_object_show(edje);
}
evas_object_move(im, 0, 0);
evas_object_resize(im, ww, hh);
sortkey = EINA_TRUE;
}
else if ((ext) &&
((!strcasecmp(ext, ".ttf")) ||
(!strcasecmp(ext, ".pcf")) ||
(!strcasecmp(ext, ".bdf")) ||
(!strcasecmp(ext, ".ttx")) ||
(!strcasecmp(ext, ".pfa")) ||
(!strcasecmp(ext, ".pfb")) ||
(!strcasecmp(ext, ".afm")) ||
(!strcasecmp(ext, ".sfd")) ||
(!strcasecmp(ext, ".snf")) ||
(!strcasecmp(ext, ".otf")) ||
(!strcasecmp(ext, ".psf")) ||
(!strcasecmp(ext, ".ttc")) ||
(!strcasecmp(ext, ".ttx")) ||
(!strcasecmp(ext, ".gsf")) ||
(!strcasecmp(ext, ".spd"))
))
{
Evas_Coord tx = 0, ty = 0, tw = 0, th = 0;
ww = eth->w;
hh = eth->h;
alpha = 0;
bg = evas_object_rectangle_add(evas);
evas_object_color_set(bg, 96, 96, 96, 255);
evas_object_move(bg, 0, 0);
evas_object_resize(bg, ww, hh);
evas_object_show(bg);
im = evas_object_text_add(evas);
evas_object_text_font_set(im, eth->file, hh / 4);
evas_object_color_set(im, 192, 192, 192, 255);
evas_object_text_ellipsis_set(im, 0.0);
evas_object_text_text_set(im, "ABCabc");
evas_object_geometry_get(im, NULL, NULL, &tw, &th);
if (tw > ww) tw = ww;
tx = 0 + ((ww - tw) / 2);
ty = 0 + (((hh / 2) - th) / 2);
evas_object_move(im, tx, ty);
evas_object_resize(im, tw, th);
evas_object_show(im);
im2 = evas_object_text_add(evas);
evas_object_text_font_set(im2, eth->file, hh / 4);
evas_object_color_set(im2, 255, 255, 255, 255);
evas_object_text_ellipsis_set(im2, 0.0);
evas_object_text_text_set(im2, "123!@?");
evas_object_geometry_get(im2, NULL, NULL, &tw, &th);
if (tw > ww) tw = ww;
tx = 0 + ((ww - tw) / 2);
ty = (hh / 2) + (((hh / 2) - th) / 2);
evas_object_move(im2, tx, ty);
evas_object_resize(im2, tw, th);
evas_object_show(im2);
}
else if (evas_object_image_extension_can_load_get(ext))
{
im = evas_object_image_add(evas);
evas_object_image_load_orientation_set(im, EINA_TRUE);
evas_object_image_load_size_set(im, eth->w, eth->h);
evas_object_image_file_set(im, eth->file, NULL);
iw = 0; ih = 0;
evas_object_image_size_get(im, &iw, &ih);
alpha = evas_object_image_alpha_get(im);
if ((iw > 0) && (ih > 0))
{
ww = eth->w;
hh = (eth->w * ih) / iw;
if (hh > eth->h)
{
hh = eth->h;
ww = (eth->h * iw) / ih;
}
evas_object_image_fill_set(im, 0, 0, ww, hh);
}
evas_object_move(im, 0, 0);
evas_object_resize(im, ww, hh);
sortkey = EINA_TRUE;
}
else
goto end;
ecore_evas_alpha_set(ee, alpha);
ecore_evas_resize(ee, ww, hh);
evas_object_show(im);
if (ww <= 0) goto end;
data = ecore_evas_buffer_pixels_get(ee);
if (!data) goto end;
ef = eet_open(buf, EET_FILE_MODE_WRITE);
if (!ef) goto end;
eet_write(ef, "/thumbnail/orig_file",
eth->file, strlen(eth->file), 1);
if (eth->key)
eet_write(ef, "/thumbnail/orig_key",
eth->key, strlen(eth->key), 1);
eet_data_image_write(ef, "/thumbnail/data",
(void *)data, ww, hh, alpha,
0, 91, 1);
if (sortkey)
{
ww = 4; hh = 4;
evas_object_image_fill_set(im, 0, 0, ww, hh);
evas_object_resize(im, ww, hh);
ecore_evas_resize(ee, ww, hh);
data = ecore_evas_buffer_pixels_get(ee);
if (!data) goto end;
data1 = malloc(ww * hh * sizeof(unsigned int));
memcpy(data1, data, ww * hh * sizeof(unsigned int));
ww = 2; hh = 2;
evas_object_image_fill_set(im, 0, 0, ww, hh);
evas_object_resize(im, ww, hh);
ecore_evas_resize(ee, ww, hh);
data = ecore_evas_buffer_pixels_get(ee);
if (data)
{
unsigned int *data2;
data2 = malloc(ww * hh * sizeof(unsigned int));
memcpy(data2, data, ww * hh * sizeof(unsigned int));
ww = 1; hh = 1;
evas_object_image_fill_set(im, 0, 0, ww, hh);
evas_object_resize(im, ww, hh);
ecore_evas_resize(ee, ww, hh);
data = ecore_evas_buffer_pixels_get(ee);
if (data)
{
unsigned int *data3;
unsigned char id2[(21 * 4) + 1];
int n, i;
int hi, si, vi;
float h, s, v;
const int pat2[4] =
{
0, 3, 1, 2
};
const int pat1[16] =
{
5, 10, 6, 9,
0, 15, 3, 12,
1, 14, 7, 8,
4, 11, 2, 13
};
/* ww = hh = 1 here */
data3 = malloc(sizeof(unsigned int));
memcpy(data3, data, sizeof(unsigned int));
// sort_id
n = 0;
#define A(v) (((v) >> 24) & 0xff)
#define R(v) (((v) >> 16) & 0xff)
#define G(v) (((v) >> 8) & 0xff)
#define B(v) (((v)) & 0xff)
#define HSV(p) \
evas_color_rgb_to_hsv(R(p), G(p), B(p), &h, &s, &v); \
hi = 20 * (h / 360.0); \
si = 20 * s; \
vi = 20 * v; \
if (si < 2) hi = 25;
#define SAVEHSV(h, s, v) \
id2[n++] = 'a' + h; \
id2[n++] = 'a' + v; \
id2[n++] = 'a' + s;
#define SAVEX(x) \
id2[n++] = 'a' + x;
#if 0
HSV(data3[0]);
SAVEHSV(hi, si, vi);
for (i = 0; i < 4; i++)
{
HSV(data2[pat2[i]]);
SAVEHSV(hi, si, vi);
}
for (i = 0; i < 16; i++)
{
HSV(data1[pat1[i]]);
SAVEHSV(hi, si, vi);
}
#else
HSV(data3[0]);
SAVEX(hi);
for (i = 0; i < 4; i++)
{
HSV(data2[pat2[i]]);
SAVEX(hi);
}
for (i = 0; i < 16; i++)
{
HSV(data1[pat1[i]]);
SAVEX(hi);
}
HSV(data3[0]);
SAVEX(vi);
for (i = 0; i < 4; i++)
{
HSV(data2[pat2[i]]);
SAVEX(vi);
}
for (i = 0; i < 16; i++)
{
HSV(data1[pat1[i]]);
SAVEX(vi);
}
HSV(data3[0]);
SAVEX(si);
for (i = 0; i < 4; i++)
{
HSV(data2[pat2[i]]);
SAVEX(si);
}
for (i = 0; i < 16; i++)
{
HSV(data1[pat1[i]]);
SAVEX(si);
}
#endif
id2[n++] = 0;
eet_write(ef, "/thumbnail/sort_id", id2, n, 1);
free(data3);
}
free(data2);
}
free(data1);
}
end:
if (ef) eet_close(ef);
/* will free all */
if (edje) evas_object_del(edje);
if (ee_im) ecore_evas_free(ee_im);
else if (im) evas_object_del(im);
if (im2) evas_object_del(im2);
if (bg) evas_object_del(bg);
ecore_evas_free(ee);
eet_clearcache();
break;
}
/* send back path to thumb */
ecore_ipc_server_send(_e_ipc_server, EPHOTO_IPC_DOMAIN_THUMB, 2, eth->objid, 0, 0, buf, strlen(buf) + 1);
}
static int
e_sha1_sum(unsigned char *data, int size, unsigned char *dst)
{
unsigned int digest[5], word[80], wa, wb, wc, wd, we, t;
unsigned char buf[64], *d;
int idx, left, i;
const unsigned int magic[4] =
{
0x5a827999,
0x6ed9eba1,
0x8f1bbcdc,
0xca62c1d6
};
idx = 0;
digest[0] = 0x67452301;
digest[1] = 0xefcdab89;
digest[2] = 0x98badcfe;
digest[3] = 0x10325476;
digest[4] = 0xc3d2e1f0;
memset(buf, 0, sizeof(buf));
for (left = size, d = data; left > 0; left--, d++)
{
if ((idx == 0) && (left < 64))
{
memset(buf, 0, 60);
buf[60] = (size >> 24) & 0xff;
buf[61] = (size >> 16) & 0xff;
buf[62] = (size >> 8) & 0xff;
buf[63] = (size) & 0xff;
}
buf[idx] = *d;
idx++;;
if ((idx == 64) || (left == 1))
{
if ((left == 1) && (idx < 64)) buf[idx] = 0x80;
for (i = 0; i < 16; i++)
{
word[i] = (unsigned int)buf[(i * 4) ] << 24;
word[i] |= (unsigned int)buf[(i * 4) + 1] << 16;
word[i] |= (unsigned int)buf[(i * 4) + 2] << 8;
word[i] |= (unsigned int)buf[(i * 4) + 3];
}
for (i = 16; i < 80; i++)
word[i] = SHSH(1,
word[i - 3 ] ^ word[i - 8 ] ^
word[i - 14] ^ word[i - 16]);
wa = digest[0];
wb = digest[1];
wc = digest[2];
wd = digest[3];
we = digest[4];
for (i = 0; i < 80; i++)
{
if (i < 20)
t = SHSH(5, wa) + ((wb & wc) | ((~wb) & wd)) +
we + word[i] + magic[0];
else if (i < 40)
t = SHSH(5, wa) + (wb ^ wc ^ wd) +
we + word[i] + magic[1];
else if (i < 60)
t = SHSH(5, wa) + ((wb & wc) | (wb & wd) | (wc & wd)) +
we + word[i] + magic[2];
else if (i < 80)
t = SHSH(5, wa) + (wb ^ wc ^ wd) +
we + word[i] + magic[3];
we = wd;
wd = wc;
wc = SHSH(30, wb);
wb = wa;
wa = t;
}
digest[0] += wa;
digest[1] += wb;
digest[2] += wc;
digest[3] += wd;
digest[4] += we;
idx = 0;
}
}
t = htonl(digest[0]); digest[0] = t;
t = htonl(digest[1]); digest[1] = t;
t = htonl(digest[2]); digest[2] = t;
t = htonl(digest[3]); digest[3] = t;
t = htonl(digest[4]); digest[4] = t;
memcpy(dst, digest, 5 * 4);
return 1;
}
static char *
_e_thumb_file_id(char *file,
char *key)
{
char s[64];
const char *chmap = "0123456789abcdef";
unsigned char *buf, id[20];
int i, len, lenf;
len = 0;
lenf = strlen(file);
len += lenf;
len++;
if (key)
{
key += strlen(key);
len++;
}
buf = alloca(len);
strcpy((char *)buf, file);
if (key) strcpy((char *)(buf + lenf + 1), key);
e_sha1_sum(buf, len, id);
for (i = 0; i < 20; i++)
{
s[(i * 2) + 0] = chmap[(id[i] >> 4) & 0xf];
s[(i * 2) + 1] = chmap[(id[i]) & 0xf];
}
s[(i * 2)] = 0;
return strdup(s);
}