Edje: Directly embed TGV files inside EDJ when possible

This checks that the ETC format is the same, and then proceeds
to simply stuff in the TGV file inside the EDJ as an "edje/image/n"

This will save a huge amount of time since now you just need
to encode an image once to TGV (ETC1 or ETC2) and you can reuse it
directly without re-encoding.

To use this, convert images with ecore_evas_convert and then
add them to EDC with the ".tgv" extension and the proper LOSSY format.
The quality argument will then be ignored.

@feature
This commit is contained in:
Jean-Philippe Andre 2015-10-30 16:41:03 +09:00
parent 64de2f6ce5
commit a5d0284820
1 changed files with 194 additions and 60 deletions

View File

@ -151,6 +151,9 @@ struct _Image_Write
Eet_File *ef;
Edje_Image_Directory_Entry *img;
Evas_Object *im;
Emile_Image_Property prop;
Eina_File *f;
Emile_Image *emi;
int w, h;
int alpha;
unsigned int *data;
@ -1061,7 +1064,7 @@ data_thread_image_end(void *data, Ecore_Thread *thread EINA_UNUSED)
error_and_abort(iw->ef, iw->errstr);
free(iw->errstr);
}
if (iw->path) free(iw->path);
free(iw->path);
evas_object_del(iw->im);
free(iw);
}
@ -1083,6 +1086,127 @@ data_image_preload_done(void *data, Evas *e EINA_UNUSED, Evas_Object *o, void *e
}
}
static void
tgv_file_thread(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Image_Write *iw = data;
char buf[256];
size_t len;
snprintf(buf, sizeof(buf), "edje/images/%i", iw->img->id);
len = eina_file_size_get(iw->f);
eet_write_cipher(iw->ef, buf, iw->data, len, EINA_FALSE /*!no_comp*/, NULL);
}
static void
tgv_file_thread_end(void *data, Ecore_Thread *thread EINA_UNUSED)
{
Image_Write *iw = data;
pending_threads--;
if (pending_threads <= 0) ecore_main_loop_quit();
if (iw->errstr)
{
error_and_abort(iw->ef, iw->errstr);
free(iw->errstr);
}
free(iw->path);
emile_image_close(iw->emi);
eina_file_map_free(iw->f, iw->data);
eina_file_close(iw->f);
free(iw);
}
static Eina_Bool
tgv_file_check_and_add(Eet_File *ef, Edje_Image_Directory_Entry *img, int *image_num)
{
Emile_Image_Load_Error err;
Emile_Image *emi = NULL;
Image_Write *iw = NULL;
Eina_List *li;
const char *s;
Eina_File *f;
void *data;
EINA_LIST_FOREACH(img_dirs, li, s)
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
f = eina_file_open(buf, EINA_FALSE);
if (f) break;
}
if (!f) return EINA_FALSE;
data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
if (!data) goto on_error;
using_file(img->entry, 'I');
emi = emile_image_tgv_file_open(f, NULL, NULL, &err);
if (!emi || (err != EMILE_IMAGE_LOAD_ERROR_NONE)) goto on_error;
iw = calloc(1, sizeof(*iw));
if (!emile_image_head(emi, &iw->prop, sizeof(iw->prop), &err) ||
(err != EMILE_IMAGE_LOAD_ERROR_NONE))
goto on_error;
if (!iw->prop.cspaces || !iw->prop.w || !iw->prop.h)
goto on_error;
iw->f = f;
iw->ef = ef;
iw->img = img;
iw->emi = emi;
iw->data = (unsigned int *) data;
iw->w = iw->prop.w;
iw->h = iw->prop.h;
iw->prop.cspace = iw->prop.cspaces[0];
if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1)
{
if (no_etc1) goto on_error;
if (iw->prop.cspace == EMILE_COLORSPACE_ETC1)
iw->alpha = 0;
else if (iw->prop.cspace == EMILE_COLORSPACE_ETC1_ALPHA)
iw->alpha = 1;
else
goto on_error;
}
else if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
{
if (no_etc2) goto on_error;
if (iw->prop.cspace == EMILE_COLORSPACE_RGB8_ETC2)
iw->alpha = 0;
else if (iw->prop.cspace == EMILE_COLORSPACE_RGBA8_ETC2_EAC)
iw->alpha = 1;
else
goto on_error;
}
*image_num += 1;
iw->path = strdup(img->entry);
pending_threads++;
if (threads)
ecore_thread_run(tgv_file_thread, tgv_file_thread_end, NULL, iw);
else
{
tgv_file_thread(iw, NULL);
tgv_file_thread_end(iw, NULL);
}
return EINA_TRUE;
on_error:
free(iw);
emile_image_close(emi);
if (data) eina_file_map_free(f, data);
eina_file_close(f);
return EINA_FALSE;
}
static void
data_write_images(Eet_File *ef, int *image_num)
{
@ -1101,73 +1225,83 @@ data_write_images(Eet_File *ef, int *image_num)
for (i = 0; i < (int)edje_file->image_dir->entries_count; i++)
{
Edje_Image_Directory_Entry *img;
Evas_Object *im;
Eina_List *ll;
char *s;
int load_err = EVAS_LOAD_ERROR_NONE;
Image_Write *iw;
img = &edje_file->image_dir->entries[i];
if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) ||
(img->entry == NULL))
{
}
else
{
Evas_Object *im;
Eina_List *ll;
char *s;
int load_err = EVAS_LOAD_ERROR_NONE;
Image_Write *iw;
if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) || !img->entry)
continue;
iw = calloc(1, sizeof(Image_Write));
iw->ef = ef;
iw->img = img;
iw->im = im = evas_object_image_add(evas);
if (threads)
evas_object_event_callback_add(im,
EVAS_CALLBACK_IMAGE_PRELOADED,
data_image_preload_done,
iw);
EINA_LIST_FOREACH(img_dirs, ll, s)
if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC1 ||
img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY_ETC2)
{
const char *ext = strrchr(img->entry, '.');
if (ext && !strcasecmp(ext, ".tgv"))
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
evas_object_image_file_set(im, buf, NULL);
load_err = evas_object_image_load_error_get(im);
if (load_err == EVAS_LOAD_ERROR_NONE)
if (tgv_file_check_and_add(ef, img, image_num))
{
*image_num += 1;
iw->path = strdup(buf);
pending_threads++;
if (threads)
evas_object_image_preload(im, 0);
using_file(buf, 'I');
if (!threads)
data_image_preload_done(iw, evas, im, NULL);
break;
}
}
if (load_err != EVAS_LOAD_ERROR_NONE)
{
evas_object_image_file_set(im, img->entry, NULL);
load_err = evas_object_image_load_error_get(im);
if (load_err == EVAS_LOAD_ERROR_NONE)
{
*image_num += 1;
iw->path = strdup(img->entry);
pending_threads++;
if (threads)
evas_object_image_preload(im, 0);
using_file(img->entry, 'I');
if (!threads)
data_image_preload_done(iw, evas, im, NULL);
DBG("Directly copying data from TGV file into EDJ");
continue;
}
else
{
free(iw);
error_and_abort_image_load_error
(ef, img->entry, load_err);
exit(1); // ensure static analysis tools know we exit
}
ERR("Source '%s' has incompatible ETC format.", img->entry);
}
}
}
iw = calloc(1, sizeof(Image_Write));
iw->ef = ef;
iw->img = img;
iw->im = im = evas_object_image_add(evas);
if (threads)
evas_object_event_callback_add(im,
EVAS_CALLBACK_IMAGE_PRELOADED,
data_image_preload_done,
iw);
EINA_LIST_FOREACH(img_dirs, ll, s)
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s", s, img->entry);
evas_object_image_file_set(im, buf, NULL);
load_err = evas_object_image_load_error_get(im);
if (load_err == EVAS_LOAD_ERROR_NONE)
{
*image_num += 1;
iw->path = strdup(buf);
pending_threads++;
if (threads)
evas_object_image_preload(im, 0);
using_file(buf, 'I');
if (!threads)
data_image_preload_done(iw, evas, im, NULL);
break;
}
}
if (load_err != EVAS_LOAD_ERROR_NONE)
{
evas_object_image_file_set(im, img->entry, NULL);
load_err = evas_object_image_load_error_get(im);
if (load_err == EVAS_LOAD_ERROR_NONE)
{
*image_num += 1;
iw->path = strdup(img->entry);
pending_threads++;
if (threads)
evas_object_image_preload(im, 0);
using_file(img->entry, 'I');
if (!threads)
data_image_preload_done(iw, evas, im, NULL);
}
else
{
free(iw);
error_and_abort_image_load_error(ef, img->entry, load_err);
exit(1); // ensure static analysis tools know we exit
}
}
}
}