diff --git a/src/lib/evas/canvas/efl_canvas_image.c b/src/lib/evas/canvas/efl_canvas_image.c index 9d4c6c4594..9b19be0775 100644 --- a/src/lib/evas/canvas/efl_canvas_image.c +++ b/src/lib/evas/canvas/efl_canvas_image.c @@ -722,7 +722,8 @@ _efl_canvas_image_efl_gfx_buffer_buffer_managed_get(Eo *eo_obj, void *_pd EINA_U if (!o->buffer_data_set || !o->engine_data || !ENFN->image_data_direct_get) return slice; - ENFN->image_data_direct_get(ENC, o->engine_data, plane, &slice, &cspace, EINA_FALSE); + ENFN->image_data_direct_get(ENC, o->engine_data, plane, &slice, &cspace, EINA_FALSE, NULL); + return slice; } diff --git a/src/lib/evas/canvas/evas_object_image.c b/src/lib/evas/canvas/evas_object_image.c index 1d9ede0de7..289ffaaa3d 100644 --- a/src/lib/evas/canvas/evas_object_image.c +++ b/src/lib/evas/canvas/evas_object_image.c @@ -880,6 +880,7 @@ _efl_canvas_image_internal_efl_file_save_save(const Eo *eo_obj, Evas_Image_Data Evas_Colorspace want_cspace = EVAS_COLORSPACE_ARGB8888; Evas_Object_Protected_Data *obj; Eina_Bool unmap_it = EINA_FALSE; + Eina_Bool tofree = EINA_FALSE; int imagew, imageh, uvw, uvh; Eina_Rw_Slice slice = {}; DATA32 *data = NULL; @@ -932,7 +933,7 @@ _efl_canvas_image_internal_efl_file_save_save(const Eo *eo_obj, Evas_Image_Data Evas_Colorspace cs; Eina_Slice sl; - ok = ENFN->image_data_direct_get(ENC, pixels, 0, &sl, &cs, EINA_TRUE); + ok = ENFN->image_data_direct_get(ENC, pixels, 0, &sl, &cs, EINA_TRUE, &tofree); if (ok && (cs == want_cspace)) data = (DATA32 *)sl.mem; } @@ -966,6 +967,8 @@ _efl_canvas_image_internal_efl_file_save_save(const Eo *eo_obj, Evas_Image_Data if (unmap_it) ENFN->image_data_unmap(ENC, pixels, &slice); + if (tofree) free(data); + if (!ok) ERR("Image save failed."); return ok; diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 5a4bd9cc5e..7d6d1c452f 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -1336,7 +1336,7 @@ struct _Evas_Func void *(*image_dirty_region) (void *engine, void *image, int x, int y, int w, int h); void *(*image_data_get) (void *engine, void *image, int to_write, DATA32 **image_data, int *err, Eina_Bool *tofree); void *(*image_data_put) (void *engine, void *image, DATA32 *image_data); - Eina_Bool (*image_data_direct_get) (void *engine, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace, Eina_Bool load); + Eina_Bool (*image_data_direct_get) (void *engine, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace, Eina_Bool load, Eina_Bool *tofree); void (*image_data_preload_request) (void *engine, void *image, const Eo *target); void (*image_data_preload_cancel) (void *engine, void *image, const Eo *target, Eina_Bool force); void *(*image_alpha_set) (void *engine, void *image, int has_alpha); diff --git a/src/modules/evas/engines/gl_generic/evas_engine.c b/src/modules/evas/engines/gl_generic/evas_engine.c index 60301d4283..00989e8e17 100644 --- a/src/modules/evas/engines/gl_generic/evas_engine.c +++ b/src/modules/evas/engines/gl_generic/evas_engine.c @@ -301,20 +301,86 @@ eng_image_file_colorspace_get(void *engine EINA_UNUSED, void *image) static Eina_Bool eng_image_data_direct_get(void *engine EINA_UNUSED, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace, - Eina_Bool load) + Eina_Bool load, Eina_Bool *tofree) { + Eina_Bool ret = EINA_FALSE; Evas_GL_Image *im = image; + int bpp = 0; - if (!slice || !im || !im->im) - return EINA_FALSE; + if (!slice || !im) return ret; + + /* If content hint is DYNAMIC, the im->im could be NULL. If the im->im does + not exist, eng_image_data_direct_get needs to return copied dyn.data to + make functions including efl_file_save work. */ + if ((im->content_hint == EVAS_IMAGE_CONTENT_HINT_DYNAMIC) && + tofree && + (im->tex_only) && (!im->im) && + (im->tex) && (im->tex->pt) && (im->tex->pt->dyn.data)) + { + *tofree = EINA_FALSE; + switch ( im->cs.space) + { + case EFL_GFX_COLORSPACE_ARGB8888: + bpp = 4; + EINA_FALLTHROUGH; + // falltrhough is intended + case EFL_GFX_COLORSPACE_AGRY88: + if (!bpp) bpp = 2; + EINA_FALLTHROUGH; + // falltrhough is intended + case EFL_GFX_COLORSPACE_GRY8: + if (!bpp) bpp = 1; + *tofree = EINA_TRUE; + im->im = (RGBA_Image *)evas_cache_image_empty(evas_common_image_cache_get()); + im->im->cache_entry.flags.alpha = im->alpha; + im->im->cache_entry.space = im->cs.space; + evas_cache_image_colorspace(&im->im->cache_entry, im->cs.space); + im->im = (RGBA_Image *)evas_cache_image_size_set(&im->im->cache_entry, im->w, im->h); + + DATA8 *pixels = (DATA8 *)im->tex->pt->dyn.data; + for (int i = 0; i < im->tex->pt->dyn.h; i++) + { + memcpy(im->im->image.data + (im->w * i), + pixels + (im->tex->pt->dyn.stride * i), + im->w * bpp); + } + break; + default: break; + } + } + + if (!im->im) return ret; if (cspace) *cspace = im->im->cache_entry.space; if (load) { if (evas_cache_image_load_data(&im->im->cache_entry) != 0) - return EINA_FALSE; + { + /* Only valid when content hint is DYNAMIC */ + if (tofree && *tofree) + { + evas_cache_image_drop(&im->im->cache_entry); + im->im = NULL; + } + + return ret; + } } - return _evas_common_rgba_image_plane_get(im->im, plane, slice); + + ret = _evas_common_rgba_image_plane_get(im->im, plane, slice); + + /* The im->im is not necessary, because it is created temporal purpose to + get the slice used by out side of this function. */ + if (tofree && *tofree) + { + if (ret) + *slice = eina_rw_slice_slice_get(eina_slice_dup(*slice)); + + evas_cache_image_drop(&im->im->cache_entry); + im->im = NULL; + } + + return ret; } static void diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 1b9aeed1c3..79f9a7b95b 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -1049,9 +1049,10 @@ eng_image_file_colorspace_get(void *data EINA_UNUSED, void *image) static Eina_Bool eng_image_data_direct_get(void *data EINA_UNUSED, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace, - Eina_Bool load) + Eina_Bool load, Eina_Bool *tofree) { RGBA_Image *im = image; + if (tofree) *tofree = EINA_FALSE; if (!slice || !im) return EINA_FALSE;