From 7974f674aa9ba18588576a373e1ec0c524bbde9f Mon Sep 17 00:00:00 2001 From: Jean-Philippe Andre Date: Fri, 30 Oct 2015 16:41:32 +0900 Subject: [PATCH] Evas: Allow edje_decc to work with ETC images This reuses the internal function data_get, data_put, image_save respecting the border information and adding support for ETC formats. @fix --- src/bin/edje/edje_decc.c | 2 +- src/lib/evas/canvas/evas_object_image.c | 101 ++++++++++++++++++--- src/lib/evas/common/evas_image_data.c | 100 ++++++++++++-------- src/lib/evas/common/evas_image_main.c | 30 +++--- .../evas/engines/software_generic/evas_engine.c | 16 ++++ .../evas/image_savers/tgv/evas_image_save_tgv.c | 14 ++- 6 files changed, 186 insertions(+), 77 deletions(-) diff --git a/src/bin/edje/edje_decc.c b/src/bin/edje/edje_decc.c index 8c0dd3c..5eeb7ef 100644 --- a/src/bin/edje/edje_decc.c +++ b/src/bin/edje/edje_decc.c @@ -336,7 +336,7 @@ output(void) } ecore_file_mkpath(pp); free(pp); - if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9")) + if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9 encoding=auto")) { ERR("Cannot write file %s. Perhaps missing JPEG or PNG saver modules for Evas.", out); exit(-1); diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index e174353..b4a8f19 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -1648,7 +1648,9 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file int quality = 80, compress = 9, ok = 0; char *encoding = NULL; Image_Entry *ie; - Eina_Bool putback = EINA_FALSE, tofree = EINA_FALSE; + Eina_Bool putback = EINA_FALSE, tofree = EINA_FALSE, no_convert = EINA_FALSE; + Evas_Colorspace cspace = EVAS_COLORSPACE_ARGB8888; + int want_cspace = EVAS_COLORSPACE_ARGB8888; int imagew, imageh; void *pixels; @@ -1698,16 +1700,9 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file o->proxyrendering = EINA_FALSE; } - pixels = ENFN->image_data_get(ENDT, pixels, 0, &data, &o->load_error, &tofree); - - if (!pixels) - { - WRN("Could not get image pixels."); - return EINA_FALSE; - } - if (flags) { + const char *ext = NULL; char *p, *pp; char *tflags; @@ -1724,23 +1719,99 @@ _evas_image_efl_file_save(const Eo *eo_obj, Evas_Image_Data *o, const char *file if (pp) p = pp + 1; else break; } + + if (file) ext = strrchr(file, '.'); + if (encoding && ext && !strcasecmp(ext, ".tgv")) + { + if (!strcmp(encoding, "auto")) + want_cspace = -1; + else if (!strcmp(encoding, "etc1")) + want_cspace = EVAS_COLORSPACE_ETC1; + else if (!strcmp(encoding, "etc2")) + { + if (!ENFN->image_alpha_get(ENDT, pixels)) + want_cspace = EVAS_COLORSPACE_RGB8_ETC2; + else + want_cspace = EVAS_COLORSPACE_RGBA8_ETC2_EAC; + } + else if (!strcmp(encoding, "etc1+alpha")) + want_cspace = EVAS_COLORSPACE_ETC1_ALPHA; + } + else + { + free(encoding); + encoding = NULL; + } + } + + if (!ENFN->image_data_has) + pixels = ENFN->image_data_get(ENDT, pixels, 0, &data, &o->load_error, &tofree); + else + { + if (ENFN->image_data_has(ENDT, pixels, &cspace)) + { + if ((want_cspace != (int) cspace) && (want_cspace != -1)) + cspace = EVAS_COLORSPACE_ARGB8888; + } + else + { + cspace = ENFN->image_file_colorspace_get(ENDT, pixels); + if ((want_cspace != (int) cspace) && (want_cspace != -1)) + cspace = EVAS_COLORSPACE_ARGB8888; + else + { + ENFN->image_colorspace_set(ENDT, pixels, cspace); + no_convert = EINA_TRUE; + } + } + pixels = ENFN->image_data_get(ENDT, pixels, 0, &data, &o->load_error, &tofree); + } + + if (!pixels) + { + WRN("Could not get image pixels."); + return EINA_FALSE; + } + + switch (cspace) + { + case EVAS_COLORSPACE_ARGB8888: + break; + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_ETC1_ALPHA: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + break; + default: + DBG("Need to convert colorspace before saving"); + cspace = EVAS_COLORSPACE_ARGB8888; + break; } + ie = evas_cache_image_data(evas_common_image_cache_get(), - imagew, imageh, data, o->cur->has_alpha, - EVAS_COLORSPACE_ARGB8888); + imagew, imageh, data, o->cur->has_alpha, cspace); if (ie) { RGBA_Image *im = (RGBA_Image *) ie; - if (o->cur->cspace == EVAS_COLORSPACE_ARGB8888) + DATA32 *old_data = NULL; + + // FIXME: Something is fishy here... what about the previous pointer? + if ((o->cur->cspace == cspace) || no_convert) im->image.data = data; else - im->image.data = evas_object_image_data_convert_internal(o, data, EVAS_COLORSPACE_ARGB8888); + { + old_data = im->image.data; + im->image.data = evas_object_image_data_convert_internal(o, data, EVAS_COLORSPACE_ARGB8888); + } if (im->image.data) { ok = evas_common_save_image_to_file(im, file, key, quality, compress, encoding); - if (o->cur->cspace != EVAS_COLORSPACE_ARGB8888) - free(im->image.data); + if (old_data) + { + free(im->image.data); + im->image.data = old_data; + } } evas_cache_image_drop(ie); } diff --git a/src/lib/evas/common/evas_image_data.c b/src/lib/evas/common/evas_image_data.c index b6e2bdc..1269818 100644 --- a/src/lib/evas/common/evas_image_data.c +++ b/src/lib/evas/common/evas_image_data.c @@ -41,6 +41,21 @@ evas_common_rgba_image_from_data(Image_Entry* ie_dst, int w, int h, DATA32 *imag dst->cs.data = image_data; dst->cs.no_free = 1; break; + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_ETC1_ALPHA: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + // FIXME: Borders are just guessed, not passed in (they should be) + dst->cache_entry.w = w; + dst->cache_entry.h = h; + dst->cache_entry.borders.l = 1; + dst->cache_entry.borders.t = 1; + dst->cache_entry.borders.r = ((w + 2 + 3) & ~0x3) - w - 1; + dst->cache_entry.borders.b = ((h + 2 + 3) & ~0x3) - h - 1; + dst->image.data = image_data; + dst->image.no_free = 1; + dst->cache_entry.flags.alpha = alpha ? 1 : 0; + break; default: abort(); break; @@ -119,58 +134,67 @@ evas_common_rgba_image_size_set(Image_Entry *ie_dst, const Image_Entry *ie_im, u } int -evas_common_rgba_image_colorspace_set(Image_Entry* ie_dst, Evas_Colorspace cspace) +evas_common_rgba_image_colorspace_set(Image_Entry* ie, Evas_Colorspace cspace) { - RGBA_Image *dst = (RGBA_Image *) ie_dst; - Eina_Bool change = (dst->cache_entry.space != cspace); + RGBA_Image *im = (RGBA_Image *) ie; + + // FIXME: This function looks extremely dubious now, trying to free the + // data pointer without even knowing how it was allocated (malloc / mmap). + // Also, lacks support for S3TC and exotic formats. + + if (im->cache_entry.space == cspace) + return 1; + + if (ie->references > 1) + WRN("Releasing data of image with >1 refs. Bad things may happen."); + + if (im->cs.data) + { + if (!im->cs.no_free) free(im->cs.data); + im->cs.data = NULL; + } + im->cs.no_free = 0; + if (im->image.data && !im->image.no_free) + { + // FIXME: Call _evas_common_rgba_image_surface_munmap + free(im->image.data); + } + ie->allocated.w = 0; + ie->allocated.h = 0; + ie->flags.preload_done = 0; + ie->flags.loaded = 0; + im->image.data = NULL; + im->image.no_free = 0; switch (cspace) { case EVAS_COLORSPACE_ARGB8888: case EVAS_COLORSPACE_AGRY88: case EVAS_COLORSPACE_GRY8: - if (dst->cs.data) - { - if (!dst->cs.no_free) free(dst->cs.data); - dst->cs.data = NULL; - dst->cs.no_free = 0; - } - if (change && dst->image.data) - { - if (!dst->image.no_free) free(dst->image.data); - dst->image.data = NULL; - dst->image.no_free = 0; - } + // all good + break; + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_ETC1_ALPHA: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGBA8_ETC2_EAC: + // living on the edge (no conversion atm) break; case EVAS_COLORSPACE_YCBCR422P601_PL: case EVAS_COLORSPACE_YCBCR422P709_PL: case EVAS_COLORSPACE_YCBCR422601_PL: case EVAS_COLORSPACE_YCBCR420TM12601_PL: case EVAS_COLORSPACE_YCBCR420NV12601_PL: - if (dst->image.no_free) - { - ie_dst->allocated.w = 0; - ie_dst->allocated.h = 0; - ie_dst->flags.preload_done = 0; - ie_dst->flags.loaded = 0; - dst->image.data = NULL; - dst->image.no_free = 0; - /* FIXME: Must allocate image.data surface cleanly. */ - } - if (dst->cs.data) - { - if (!dst->cs.no_free) free(dst->cs.data); - } - dst->cs.data = calloc(1, dst->cache_entry.h * sizeof(unsigned char *) * 2); - dst->cs.no_free = 0; + // prepare cspace conversion buffer + im->cs.data = calloc(1, im->cache_entry.h * sizeof(unsigned char *) * 2); + im->cs.no_free = 0; break; default: - abort(); - break; + CRI("Can't set colorspace to %u: unsupported", (unsigned) cspace); + abort(); + return 0; } - dst->cache_entry.space = cspace; - evas_common_image_colorspace_dirty(dst); - - _evas_common_rgba_image_post_surface(ie_dst); - return 0; + im->cache_entry.space = cspace; + evas_common_image_colorspace_dirty(im); + _evas_common_rgba_image_post_surface(ie); + return 1; } diff --git a/src/lib/evas/common/evas_image_main.c b/src/lib/evas/common/evas_image_main.c index 5cf5335..b82a851 100644 --- a/src/lib/evas/common/evas_image_main.c +++ b/src/lib/evas/common/evas_image_main.c @@ -213,8 +213,8 @@ _evas_common_rgba_image_surface_mmap(Image_Entry *ie, unsigned int w, unsigned i #endif } -static void -_evas_common_rgba_image_surface_munmap(void *data, unsigned int w, unsigned int h, Evas_Colorspace cspace) +void +evas_common_rgba_image_surface_munmap(void *data, unsigned int w, unsigned int h, Evas_Colorspace cspace) { if (!data) return ; #if defined (HAVE_SYS_MMAN_H) && (!defined (_WIN32)) @@ -379,9 +379,9 @@ evas_common_rgba_image_unload_real(Image_Entry *ie) if (im->image.data && !im->image.no_free) { - _evas_common_rgba_image_surface_munmap(im->image.data, - ie->allocated.w, ie->allocated.h, - ie->space); + evas_common_rgba_image_surface_munmap(im->image.data, + ie->allocated.w, ie->allocated.h, + ie->space); #ifdef SURFDBG surfs = eina_list_remove(surfs, ie); #endif @@ -532,9 +532,9 @@ _evas_common_rgba_image_surface_alloc(Image_Entry *ie, unsigned int w, unsigned if (im->image.data) { - _evas_common_rgba_image_surface_munmap(im->image.data, - ie->allocated.w, ie->allocated.h, - ie->space); + evas_common_rgba_image_surface_munmap(im->image.data, + ie->allocated.w, ie->allocated.h, + ie->space); im->image.data = NULL; #ifdef SURFDBG surfs = eina_list_remove(surfs, ie); @@ -605,9 +605,9 @@ _evas_common_rgba_image_surface_delete(Image_Entry *ie) if (im->image.data && !im->image.no_free) { - _evas_common_rgba_image_surface_munmap(im->image.data, - ie->allocated.w, ie->allocated.h, - ie->space); + evas_common_rgba_image_surface_munmap(im->image.data, + ie->allocated.w, ie->allocated.h, + ie->space); #ifdef SURFDBG surfs = eina_list_remove(surfs, ie); #endif @@ -854,10 +854,10 @@ evas_common_image_colorspace_normalize(RGBA_Image *im) #endif if (!im->image.no_free) { - _evas_common_rgba_image_surface_munmap(im->image.data, - im->cache_entry.allocated.w, - im->cache_entry.allocated.h, - im->cache_entry.space); + evas_common_rgba_image_surface_munmap(im->image.data, + im->cache_entry.allocated.w, + im->cache_entry.allocated.h, + im->cache_entry.space); #ifdef SURFDBG surfs = eina_list_remove(surfs, im); #endif diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index e1f73cb..9570a51 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -1344,6 +1344,18 @@ eng_image_data_get(void *data EINA_UNUSED, void *image, int to_write, DATA32 **i case EVAS_COLORSPACE_YCBCR420TM12601_PL: *image_data = im->cs.data; break; + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGB_S3TC_DXT1: + case EVAS_COLORSPACE_RGBA_S3TC_DXT1: + if (to_write) + { + // abort() ? + error = EVAS_LOAD_ERROR_GENERIC; + return NULL; + } + *image_data = im->image.data; + break; default: abort(); break; @@ -1362,6 +1374,10 @@ eng_image_data_put(void *data, void *image, DATA32 *image_data) switch (im->cache_entry.space) { case EVAS_COLORSPACE_ARGB8888: + case EVAS_COLORSPACE_ETC1: + case EVAS_COLORSPACE_RGB8_ETC2: + case EVAS_COLORSPACE_RGB_S3TC_DXT1: + case EVAS_COLORSPACE_RGBA_S3TC_DXT1: if (image_data != im->image.data) { int w, h; diff --git a/src/modules/evas/image_savers/tgv/evas_image_save_tgv.c b/src/modules/evas/image_savers/tgv/evas_image_save_tgv.c index 2ce6ab0..44b38e0 100644 --- a/src/modules/evas/image_savers/tgv/evas_image_save_tgv.c +++ b/src/modules/evas/image_savers/tgv/evas_image_save_tgv.c @@ -53,12 +53,6 @@ _alpha_to_greyscale_convert(uint32_t *data, int len) static int _save_direct_tgv(RGBA_Image *im, const char *file, int compress) { - // FIXME: Now we have border information, this comment isn't valid anymore: - - // In case we are directly copying ETC1/2 data, we can't properly - // duplicate the 1 pixel borders. So we just assume the image contains - // them already. - // TODO: Add block by block compression. int image_width, image_height, planes = 1; @@ -69,8 +63,12 @@ _save_direct_tgv(RGBA_Image *im, const char *file, int compress) uint8_t *data, *ptr; FILE *f; - image_width = im->cache_entry.w; - image_height = im->cache_entry.h; + if (!im->cache_entry.borders.l || !im->cache_entry.borders.t || + !im->cache_entry.borders.r || !im->cache_entry.borders.b) + WRN("No im->cache_entry.borders on ETC image. Final image may have wrong dimensions."); + + image_width = im->cache_entry.w + im->cache_entry.borders.l + im->cache_entry.borders.r; + image_height = im->cache_entry.h + im->cache_entry.borders.t + im->cache_entry.borders.b; data = im->image.data8; width = htonl(image_width); height = htonl(image_height); -- 2.7.4