Evas heif loader: correctly manage stride and alpha

This commit is contained in:
Vincent Torri 2023-05-04 12:34:39 +02:00
parent 201a32279f
commit 30a2cd1ec1
1 changed files with 67 additions and 84 deletions

View File

@ -13,6 +13,7 @@ struct _Evas_Loader_Internal
Eina_File *f; Eina_File *f;
Evas_Image_Load_Opts *opts; Evas_Image_Load_Opts *opts;
struct heif_context* ctx; struct heif_context* ctx;
struct heif_image_handle *handle;
}; };
static int _evas_loader_heif_log_dom = -1; static int _evas_loader_heif_log_dom = -1;
@ -28,11 +29,11 @@ static Eina_Module *_evas_loader_heif_mod = NULL;
} \ } \
} }
#define SYM(x) \ #define SYM(x) \
if (!(x ## _f = eina_module_symbol_get(_evas_loader_heif_mod, #x))) { \ if (!(x ## _f = eina_module_symbol_get(_evas_loader_heif_mod, #x))) { \
ERR("Cannot find symbol '%s' in '%s'", \ ERR("Cannot find symbol '%s' in '%s'", \
#x, eina_module_file_get(_evas_loader_heif_mod)); \ #x, eina_module_file_get(_evas_loader_heif_mod)); \
goto error; \ goto error; \
} }
// heif_check_filetype // heif_check_filetype
@ -108,10 +109,10 @@ static heif_image_handle_release_t heif_image_handle_release_f = NULL;
#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__) #define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__)
static Eina_Bool static Eina_Bool
evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED, evas_image_load_file_head_heif_init(Evas_Loader_Internal *loader,
Emile_Image_Property *prop, Emile_Image_Property *prop,
void *map, size_t length, void *map, size_t length,
int *error) int *error)
{ {
struct heif_context *ctx; struct heif_context *ctx;
struct heif_image_handle *handle; struct heif_image_handle *handle;
@ -125,7 +126,7 @@ evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED
/* heif file must have a 12 bytes long header */ /* heif file must have a 12 bytes long header */
if ((length < 12) || if ((length < 12) ||
(heif_check_filetype_f(map, length) == heif_filetype_no)) (heif_check_filetype_f(map, length) != heif_filetype_yes_supported))
{ {
INF("HEIF header invalid"); INF("HEIF header invalid");
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
@ -145,7 +146,8 @@ evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED
{ {
INF("%s", err.message); INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto free_ctx; heif_context_free_f(ctx);
return ret;
} }
err = heif_context_get_primary_image_handle_f(ctx, &handle); err = heif_context_get_primary_image_handle_f(ctx, &handle);
@ -153,7 +155,8 @@ evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED
{ {
INF("%s", err.message); INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
goto free_ctx; heif_context_free_f(ctx);
return ret;
} }
prop->w = heif_image_handle_get_width_f(handle); prop->w = heif_image_handle_get_width_f(handle);
@ -168,22 +171,37 @@ evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader EINA_UNUSED
*error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
else else
*error= EVAS_LOAD_ERROR_GENERIC; *error= EVAS_LOAD_ERROR_GENERIC;
goto release_handle; heif_image_handle_release_f(handle);
heif_context_free_f(ctx);
return ret;
} }
prop->alpha = !!heif_image_handle_has_alpha_channel_f(handle); prop->alpha = !!heif_image_handle_has_alpha_channel_f(handle);
loader->ctx = ctx;
loader->handle = handle;
*error = EVAS_LOAD_ERROR_NONE; *error = EVAS_LOAD_ERROR_NONE;
ret = EINA_TRUE; ret = EINA_TRUE;
release_handle:
heif_image_handle_release_f(handle);
free_ctx:
heif_context_free_f(ctx);
return ret; return ret;
} }
static Eina_Bool
evas_image_load_file_head_heif_internal(Evas_Loader_Internal *loader,
Emile_Image_Property *prop,
void *map, size_t length,
int *error)
{
if (!evas_image_load_file_head_heif_init(loader, prop, map, length, error))
return EINA_FALSE;
heif_image_handle_release_f(loader->handle);
heif_context_free_f(loader->ctx);
return EINA_TRUE;
}
static Eina_Bool static Eina_Bool
evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader, evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
Emile_Image_Property *prop, Emile_Image_Property *prop,
@ -191,13 +209,11 @@ evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
void *map, size_t length, void *map, size_t length,
int *error) int *error)
{ {
struct heif_context *ctx;
struct heif_image_handle *handle;
struct heif_image *img; struct heif_image *img;
struct heif_error err; struct heif_error err;
const unsigned char *data; const unsigned char *data;
unsigned char *dd; unsigned char *dd;
unsigned char *ds; unsigned char *plane;
int stride; int stride;
unsigned int x; unsigned int x;
unsigned int y; unsigned int y;
@ -205,41 +221,10 @@ evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
ret = EINA_FALSE; ret = EINA_FALSE;
ctx = loader->ctx; if (!evas_image_load_file_head_heif_init(loader, prop, map, length, error))
if (!ctx) return ret;
{
ctx = heif_context_alloc_f();
if (!ctx)
{
INF("cannot allocate heif_context");
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
return ret;
}
err = heif_context_read_from_memory_without_copy_f(ctx, err = heif_decode_image_f(loader->handle, &img, heif_colorspace_RGB,
map, length, NULL);
if (err.code != heif_error_Ok)
{
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
heif_context_free_f(ctx);
return ret;
}
err = heif_context_get_primary_image_handle_f(ctx, &handle);
if (err.code != heif_error_Ok)
{
INF("%s", err.message);
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
heif_image_handle_release_f(handle);
heif_context_free_f(ctx);
return ret;
}
loader->ctx = ctx;
}
err = heif_decode_image_f(handle, &img, heif_colorspace_RGB,
prop->alpha ? heif_chroma_interleaved_RGBA prop->alpha ? heif_chroma_interleaved_RGBA
: heif_chroma_interleaved_RGB, : heif_chroma_interleaved_RGB,
NULL); NULL);
@ -253,37 +238,37 @@ evas_image_load_file_data_heif_internal(Evas_Loader_Internal *loader,
data = heif_image_get_plane_readonly_f(img, heif_channel_interleaved, &stride); data = heif_image_get_plane_readonly_f(img, heif_channel_interleaved, &stride);
dd = (unsigned char *)pixels; dd = (unsigned char *)pixels;
ds = (unsigned char *)data; plane = (unsigned char *)data;
if (!prop->alpha) if (!prop->alpha)
{ {
for (y = 0; y < prop->h; y++) for (y = 0; y < prop->h; y++, plane += stride)
{ {
for (x = 0; x < prop->w; x++) int from = 0;
{ for (x = 0; x < prop->w; x++, from += 3)
dd[3] = 0xff; {
dd[0] = ds[2]; dd[0] = *(plane + from + 2);
dd[1] = ds[1]; dd[1] = *(plane + from + 1);
dd[2] = ds[0]; dd[2] = *(plane + from + 0);
ds+=3; dd[3] = 0xff;
dd+=4; dd += 4;
} }
} }
} }
else else
{ {
for (y = 0; y < prop->h; y++) for (y = 0; y < prop->h; y++, plane += stride)
{ {
for (x = 0; x < prop->w; x++) int from = 0;
{ for (x = 0; x < prop->w; x++, from += 4)
dd[0] = ds[2]; {
dd[1] = ds[1]; dd[0] = *(plane + from + 2);
dd[2] = ds[0]; dd[1] = *(plane + from + 1);
dd[3] = ds[3]; dd[2] = *(plane + from + 0);
ds+=4; dd[3] = *(plane + from + 3);
dd+=4; dd += 4;
} }
} }
} }
ret = EINA_TRUE; ret = EINA_TRUE;
@ -323,10 +308,8 @@ evas_image_load_file_close_heif(void *loader_data)
Evas_Loader_Internal *loader; Evas_Loader_Internal *loader;
loader = loader_data; loader = loader_data;
/* if (loader->handle)
* in case _head() fails (because the file is not an heif one), heif_image_handle_release_f(loader->handle);
* loader is not filled and loader->ctx is NULL
*/
if (loader->ctx) if (loader->ctx)
heif_context_free_f(loader->ctx); heif_context_free_f(loader->ctx);
free(loader_data); free(loader_data);