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:
thierry1970 2021-02-06 15:45:42 +00:00 committed by Carsten Haitzler (Rasterman)
parent ec4ef69115
commit 97f95e7362
10 changed files with 347 additions and 4 deletions

9
README
View File

@ -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

13
data/evas/evas.xml Normal file
View File

@ -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>

4
data/evas/meson.build Normal file
View File

@ -0,0 +1,4 @@
install_data(files('evas.xml'),
install_dir : join_paths(dir_data, 'mime', 'packages')
)

View File

@ -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')

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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]],

View File

@ -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

View File

@ -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)