forked from enlightenment/efl
Added the heif loader
Summary: that supports images : *.heif, *hiec and *.avif I have disabled *.avif images, there is already a loader. Reviewers: stefan_schmidt, raster Subscribers: raster, vtorri, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12135
This commit is contained in:
parent
ec4ef69115
commit
97f95e7362
9
README
9
README
|
@ -404,6 +404,15 @@ This library acts as a porting library for Windows to provide missing
|
|||
libc calls not in Mingw32 that EFL needs.
|
||||
|
||||
|
||||
**Heif:**
|
||||
|
||||
//LGPL v3 license//
|
||||
|
||||
The license doesnt affect efl or apps using efl, but gpl3 or lgpl3
|
||||
affects the entire os requiring any gpl/lgpl3 component be
|
||||
user-replacable.
|
||||
The end user must be able to modify the libheif code and still be
|
||||
able to use the efl.
|
||||
|
||||
|
||||
COMPILING AND INSTALLING
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
>------<mime-type type="image/heif">
|
||||
>------>-------<comment>HEIF image file</comment>
|
||||
>------>-------<glob pattern="*.heif"/>
|
||||
>------>-------<glob pattern="*.heic"/>
|
||||
>------</mime-type>
|
||||
>------<mime-type type="image/avif">
|
||||
>------>-------<comment>AVIF image file</comment>
|
||||
>------>--------<glob pattern="*.avif"/>
|
||||
>------</mime-type>
|
||||
</mime-info>
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
install_data(files('evas.xml'),
|
||||
install_dir : join_paths(dir_data, 'mime', 'packages')
|
||||
)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
checkme_files = ['ecore', 'ecore_imf', 'ecore_x', 'eeze', 'efreet', 'elua', 'emotion', 'ethumb', 'ethumb_client', 'evas']
|
||||
checkme_files = ['ecore', 'ecore_imf', 'ecore_x', 'eeze', 'efreet', 'elua', 'emotion', 'ethumb', 'ethumb_client']
|
||||
foreach checkme : checkme_files
|
||||
install_data(join_paths(checkme, 'checkme'),
|
||||
install_dir : join_paths(dir_data, checkme)
|
||||
|
@ -10,3 +10,4 @@ subdir('edje')
|
|||
subdir('embryo')
|
||||
subdir(join_paths('ethumb', 'frames'))
|
||||
subdir('elementary')
|
||||
subdir('evas')
|
||||
|
|
|
@ -189,8 +189,8 @@ option('unmount-path',
|
|||
option('evas-loaders-disabler',
|
||||
type : 'array',
|
||||
description : 'List of modular image/vector loaders to disable in efl',
|
||||
choices : ['', 'gst', 'pdf', 'ps', 'raw', 'svg', 'rsvg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm', 'json', 'avif'],
|
||||
value : ['json', 'avif']
|
||||
choices : ['', 'gst', 'pdf', 'ps', 'raw', 'svg', 'rsvg', 'xcf', 'bmp', 'dds', 'eet', 'generic', 'gif', 'ico', 'jp2k', 'jpeg', 'pmaps', 'png', 'psd', 'tga', 'tgv', 'tiff', 'wbmp', 'webp', 'xpm', 'json', 'avif', 'heif'],
|
||||
value : ['json', 'avif', 'heif']
|
||||
)
|
||||
|
||||
option('ecore-imf-loaders-disabler',
|
||||
|
|
|
@ -69,6 +69,10 @@ static const struct ext_loader_s loaders[] =
|
|||
MATCHING(".avif", "avif"),
|
||||
MATCHING(".avifs", "avif"),
|
||||
|
||||
MATCHING(".heif", "heif"),
|
||||
MATCHING(".heic", "heif"),
|
||||
// MATCHING(".avif", "heif"),
|
||||
|
||||
/* xcf - gefenric */
|
||||
MATCHING(".xcf", "generic"),
|
||||
MATCHING(".xcf.gz", "generic"),
|
||||
|
@ -167,7 +171,8 @@ static const struct ext_loader_s loaders[] =
|
|||
static const char *loaders_name[] =
|
||||
{ /* in order of most likely needed */
|
||||
"png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "webp", "pmaps",
|
||||
"bmp", "tga", "wbmp", "ico", "psd", "jp2k", "dds", "avif", "generic"
|
||||
"bmp", "tga", "wbmp", "ico", "psd", "jp2k", "dds", "avif", "heif",
|
||||
"generic"
|
||||
};
|
||||
|
||||
struct evas_image_foreach_loader_data
|
||||
|
|
|
@ -202,6 +202,7 @@ EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, dds);
|
|||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, eet);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, generic);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, gif);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, heif);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, ico);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jpeg);
|
||||
EVAS_EINA_STATIC_MODULE_DEFINE(image_loader, jp2k);
|
||||
|
@ -307,6 +308,9 @@ static const struct {
|
|||
#ifdef EVAS_STATIC_BUILD_GIF
|
||||
EVAS_EINA_STATIC_MODULE_USE(image_loader, gif),
|
||||
#endif
|
||||
#ifdef EVAS_STATIC_BUILD_HEIF
|
||||
EVAS_EINA_STATIC_MODULE_USE(image_loader, heif),
|
||||
#endif
|
||||
#ifdef EVAS_STATIC_BUILD_ICO
|
||||
EVAS_EINA_STATIC_MODULE_USE(image_loader, ico),
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@ webp = dependency('libwebp', version: ['>=0.5.0'], required: get_option('evas-lo
|
|||
webpdemux = dependency('libwebpdemux', version: ['>=0.5.0'], required: get_option('evas-loaders-disabler').contains('webp') == false)
|
||||
libopenjp2 = dependency('libopenjp2', required: get_option('evas-loaders-disabler').contains('jp2k') == false)
|
||||
libavif = dependency('libavif', required: get_option('evas-loaders-disabler').contains('avif') == false, version: '>= 0.8.2')
|
||||
heif= dependency('libheif', required: get_option('evas-loaders-disabler').contains('heif') == false)
|
||||
|
||||
evas_image_loaders_file = [
|
||||
['avif', 'shared', [libavif]],
|
||||
|
@ -18,6 +19,7 @@ evas_image_loaders_file = [
|
|||
['eet', 'static', [eet]],
|
||||
['generic', 'shared', [rt]],
|
||||
['gif', 'shared', [giflib]],
|
||||
['heif', 'shared', [heif]],
|
||||
['ico', 'shared', []],
|
||||
['jpeg', 'static', [jpeg]],
|
||||
['jp2k', 'shared', [libopenjp2]],
|
||||
|
|
|
@ -0,0 +1,300 @@
|
|||
#define _XOPEN_SOURCE 600
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <math.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <libheif/heif.h>
|
||||
|
||||
#include "evas_common_private.h"
|
||||
#include "evas_private.h"
|
||||
|
||||
static int _evas_loader_heif_log_dom = -1;
|
||||
|
||||
#ifdef ERR
|
||||
# undef ERR
|
||||
#endif
|
||||
#define ERR(...) EINA_LOG_DOM_ERR(_evas_loader_heif_log_dom, __VA_ARGS__)
|
||||
|
||||
#ifdef INF
|
||||
# undef INF
|
||||
#endif
|
||||
#define INF(...) EINA_LOG_DOM_INFO(_evas_loader_heif_log_dom, __VA_ARGS__)
|
||||
|
||||
|
||||
static void *
|
||||
evas_image_load_file_open_heif(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
|
||||
Evas_Image_Load_Opts *opts EINA_UNUSED,
|
||||
Evas_Image_Animated *animated EINA_UNUSED,
|
||||
int *error EINA_UNUSED)
|
||||
{
|
||||
return f;
|
||||
}
|
||||
|
||||
static void
|
||||
evas_image_load_file_close_heif(void *loader_data EINA_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
evas_image_load_file_head_heif(void *loader_data,
|
||||
Emile_Image_Property *prop,
|
||||
int *error)
|
||||
{
|
||||
Eina_File *f = loader_data;
|
||||
void *map;
|
||||
size_t length;
|
||||
struct heif_error err;
|
||||
struct heif_context* hc = NULL;
|
||||
struct heif_image_handle* hdl = NULL;
|
||||
struct heif_image* img = NULL;
|
||||
Eina_Bool r = EINA_FALSE;
|
||||
|
||||
*error = EVAS_LOAD_ERROR_NONE;
|
||||
|
||||
map = eina_file_map_all(f, EINA_FILE_RANDOM);
|
||||
length = eina_file_size_get(f);
|
||||
|
||||
// init prop struct with some default null values
|
||||
prop->w = 0;
|
||||
prop->h = 0;
|
||||
|
||||
if (!map || length < 1)
|
||||
{
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
hc = heif_context_alloc();
|
||||
if (!hc) {
|
||||
INF("cannot allocate heif_context");
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = heif_context_read_from_memory_without_copy(hc, map, length, NULL);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = heif_context_get_primary_image_handle(hc, &hdl);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
int has_alpha = heif_image_handle_has_alpha_channel(hdl);
|
||||
|
||||
err = heif_decode_image(hdl, &img, heif_colorspace_RGB,
|
||||
has_alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB,
|
||||
NULL);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
prop->w = heif_image_get_width(img, heif_channel_interleaved);
|
||||
prop->h = heif_image_get_height(img, heif_channel_interleaved);
|
||||
if (has_alpha != 3)
|
||||
prop->alpha = 1;
|
||||
|
||||
r = EINA_TRUE;
|
||||
|
||||
on_error:
|
||||
if (img) {
|
||||
heif_image_release(img);
|
||||
}
|
||||
|
||||
if (hdl) {
|
||||
heif_image_handle_release(hdl);
|
||||
}
|
||||
|
||||
if (hc) {
|
||||
heif_context_free(hc);
|
||||
}
|
||||
eina_file_map_free(f, map);
|
||||
return r;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
evas_image_load_file_data_heif(void *loader_data,
|
||||
Emile_Image_Property *prop,
|
||||
void *pixels,
|
||||
int *error)
|
||||
{
|
||||
Eina_File *f = loader_data;
|
||||
|
||||
void *map;
|
||||
size_t length;
|
||||
struct heif_error err;
|
||||
struct heif_context* hc = NULL;
|
||||
struct heif_image_handle* hdl = NULL;
|
||||
struct heif_image* img = NULL;
|
||||
unsigned int x, y;
|
||||
int stride, bps = 3;
|
||||
const uint8_t* data;
|
||||
uint8_t* dd = (uint8_t*)pixels, *ds = NULL;
|
||||
Eina_Bool result = EINA_FALSE;
|
||||
|
||||
map = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
|
||||
length = eina_file_size_get(f);
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
if (!map || length < 1)
|
||||
goto on_error;
|
||||
|
||||
*error = EVAS_LOAD_ERROR_GENERIC;
|
||||
result = EINA_FALSE;
|
||||
|
||||
hc = heif_context_alloc();
|
||||
if (!hc) {
|
||||
INF("cannot allocate heif_context");
|
||||
*error = EVAS_LOAD_ERROR_CORRUPT_FILE;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = heif_context_read_from_memory_without_copy(hc, map, length, NULL);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = heif_context_get_primary_image_handle(hc, &hdl);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
|
||||
err = heif_decode_image(hdl, &img, heif_colorspace_RGB,
|
||||
prop->alpha ? heif_chroma_interleaved_RGBA : heif_chroma_interleaved_RGB,
|
||||
NULL);
|
||||
if (err.code != heif_error_Ok) {
|
||||
INF("%s", err.message);
|
||||
*error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
|
||||
goto on_error;
|
||||
}
|
||||
if (prop->alpha) bps = 4;
|
||||
data = heif_image_get_plane_readonly(img, heif_channel_interleaved, &stride);
|
||||
ds = (uint8_t*)data;
|
||||
for (y = 0; y < prop->h; y++)
|
||||
for (x = 0; x < prop->w; x++)
|
||||
{
|
||||
if (bps == 3)
|
||||
{
|
||||
dd[3] = 0xff;
|
||||
dd[0] = ds[2];
|
||||
dd[1] = ds[1];
|
||||
dd[2] = ds[0];
|
||||
ds+=3;
|
||||
dd+=4;
|
||||
}
|
||||
else
|
||||
{
|
||||
dd[0] = ds[2];
|
||||
dd[1] = ds[1];
|
||||
dd[2] = ds[0];
|
||||
dd[3] = ds[3];
|
||||
ds+=4;
|
||||
dd+=4;
|
||||
}
|
||||
}
|
||||
result = EINA_TRUE;
|
||||
|
||||
*error = EVAS_LOAD_ERROR_NONE;
|
||||
prop->premul = EINA_TRUE;
|
||||
|
||||
on_error:
|
||||
|
||||
if (map) eina_file_map_free(f, map);
|
||||
|
||||
if (img) {
|
||||
// Do not free the image here when we pass it to gdk-pixbuf, as its memory will still be used by gdk-pixbuf.
|
||||
heif_image_release(img);
|
||||
}
|
||||
|
||||
if (hdl) {
|
||||
heif_image_handle_release(hdl);
|
||||
}
|
||||
|
||||
if (hc) {
|
||||
heif_context_free(hc);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static const Evas_Image_Load_Func evas_image_load_heif_func = {
|
||||
EVAS_IMAGE_LOAD_VERSION,
|
||||
evas_image_load_file_open_heif,
|
||||
evas_image_load_file_close_heif,
|
||||
(void*) evas_image_load_file_head_heif,
|
||||
NULL,
|
||||
(void*) evas_image_load_file_data_heif,
|
||||
NULL,
|
||||
EINA_TRUE,
|
||||
EINA_FALSE
|
||||
};
|
||||
|
||||
static int
|
||||
module_open(Evas_Module *em)
|
||||
{
|
||||
if (!em) return 0;
|
||||
_evas_loader_heif_log_dom = eina_log_domain_register
|
||||
("evas-heif", EVAS_DEFAULT_LOG_COLOR);
|
||||
if (_evas_loader_heif_log_dom < 0)
|
||||
{
|
||||
EINA_LOG_ERR("Can not create a module log domain.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
em->functions = (void *)(&evas_image_load_heif_func);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
module_close(Evas_Module *em EINA_UNUSED)
|
||||
{
|
||||
if (_evas_loader_heif_log_dom >= 0)
|
||||
{
|
||||
eina_log_domain_unregister(_evas_loader_heif_log_dom);
|
||||
_evas_loader_heif_log_dom = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static Evas_Module_Api evas_modapi =
|
||||
{
|
||||
EVAS_MODULE_API_VERSION,
|
||||
"heif",
|
||||
"none",
|
||||
{
|
||||
module_open,
|
||||
module_close
|
||||
}
|
||||
};
|
||||
|
||||
EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, heif);
|
||||
|
||||
|
||||
#ifndef EVAS_STATIC_BUILD_HEIF
|
||||
EVAS_EINA_MODULE_DEFINE(image_loader, heif);
|
||||
#endif
|
|
@ -53,6 +53,11 @@ static const char *exts[] = {
|
|||
,"jpeg"
|
||||
,"jpg"
|
||||
#endif
|
||||
#ifdef BUILD_LOADER_HEIF
|
||||
,"heif"
|
||||
,"heic"
|
||||
// ,"avif"
|
||||
#endif
|
||||
};
|
||||
|
||||
EFL_START_TEST(evas_object_image_loader)
|
||||
|
|
Loading…
Reference in New Issue