summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthierry1970 <thierry@ordissimo.com>2021-02-06 15:45:42 +0000
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2021-02-06 18:58:04 +0000
commit97f95e736269fcdf5511077135ede9b37dd06854 (patch)
tree9f8f74e8bb9b6cd2341210ea5becd9c141a3c520
parentec4ef6911591b0ce47616438dfd34626d9302537 (diff)
downloadefl-97f95e736269fcdf5511077135ede9b37dd06854.tar.gz
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
-rw-r--r--README9
-rw-r--r--data/evas/evas.xml13
-rw-r--r--data/evas/meson.build4
-rw-r--r--data/meson.build3
-rw-r--r--meson_options.txt4
-rw-r--r--src/lib/evas/common/evas_image_load.c7
-rw-r--r--src/lib/evas/file/evas_module.c4
-rw-r--r--src/lib/evas/meson.build2
-rw-r--r--src/modules/evas/image_loaders/heif/evas_image_load_heif.c300
-rw-r--r--src/tests/evas/evas_test_image.c5
10 files changed, 347 insertions, 4 deletions
diff --git a/README b/README
index ec3b27a737..03085056d3 100644
--- a/README
+++ b/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
diff --git a/data/evas/evas.xml b/data/evas/evas.xml
new file mode 100644
index 0000000000..7764c0c05e
--- /dev/null
+++ b/data/evas/evas.xml
@@ -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>
+
diff --git a/data/evas/meson.build b/data/evas/meson.build
new file mode 100644
index 0000000000..ddcc57dcad
--- /dev/null
+++ b/data/evas/meson.build
@@ -0,0 +1,4 @@
+install_data(files('evas.xml'),
+ install_dir : join_paths(dir_data, 'mime', 'packages')
+)
+
diff --git a/data/meson.build b/data/meson.build
index 4e1f68d406..5944dad07c 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -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')
diff --git a/meson_options.txt b/meson_options.txt
index f5ffb0e134..b224179366 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -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',
diff --git a/src/lib/evas/common/evas_image_load.c b/src/lib/evas/common/evas_image_load.c
index 8ed04dda2e..797fae37ea 100644
--- a/src/lib/evas/common/evas_image_load.c
+++ b/src/lib/evas/common/evas_image_load.c
@@ -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
diff --git a/src/lib/evas/file/evas_module.c b/src/lib/evas/file/evas_module.c
index 6292c1bb42..1362a004d8 100644
--- a/src/lib/evas/file/evas_module.c
+++ b/src/lib/evas/file/evas_module.c
@@ -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
diff --git a/src/lib/evas/meson.build b/src/lib/evas/meson.build
index 8dcfd98713..1bf5fa0801 100644
--- a/src/lib/evas/meson.build
+++ b/src/lib/evas/meson.build
@@ -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]],
diff --git a/src/modules/evas/image_loaders/heif/evas_image_load_heif.c b/src/modules/evas/image_loaders/heif/evas_image_load_heif.c
new file mode 100644
index 0000000000..bc9f2a1e06
--- /dev/null
+++ b/src/modules/evas/image_loaders/heif/evas_image_load_heif.c
@@ -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
diff --git a/src/tests/evas/evas_test_image.c b/src/tests/evas/evas_test_image.c
index c2530632a3..5753651f30 100644
--- a/src/tests/evas/evas_test_image.c
+++ b/src/tests/evas/evas_test_image.c
@@ -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)