From eb60fefc3b7e9b5367bca9d3b5e5d4e50f5b72a7 Mon Sep 17 00:00:00 2001 From: Carlo Abelli Date: Sun, 15 Mar 2020 12:51:46 -0400 Subject: Add HEIF support Support the HEIF format using libheif. --- .builds/archlinux.yml | 1 + .builds/debian.yml | 1 + .builds/fedora.yml | 5 ++- .builds/freebsd.yml | 1 + .builds/ubuntu.yml | 1 + AUTHORS | 1 + meson.build | 1 + meson_options.txt | 8 ++++ src/backend_libheif.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 5 +++ 10 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 src/backend_libheif.c diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index 4038414..4ba7b83 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml @@ -7,6 +7,7 @@ packages: - glu - icu - libglvnd + - libheif - libjpeg-turbo - libnsgif - libpng diff --git a/.builds/debian.yml b/.builds/debian.yml index 08bc065..b86a6ab 100644 --- a/.builds/debian.yml +++ b/.builds/debian.yml @@ -6,6 +6,7 @@ packages: - libegl1-mesa-dev - libfreeimage-dev - libglu-dev + - libheif-dev - libicu-dev - libpango1.0-dev - libpng-dev diff --git a/.builds/fedora.yml b/.builds/fedora.yml index 7e275ed..b4ea167 100644 --- a/.builds/fedora.yml +++ b/.builds/fedora.yml @@ -22,10 +22,11 @@ packages: sources: - https://git.sr.ht/~exec64/imv tasks: + # libheif ins't packaged by fedora # libnsgif isn't packaged by fedora - gcc: | - CC=gcc meson imv build_gcc -D auto_features=enabled -D libnsgif=disabled + CC=gcc meson imv build_gcc -D auto_features=enabled -D libheif=disabled -D libnsgif=disabled CC=gcc ninja -C build_gcc test - clang: | - CC=clang meson imv build_clang -D auto_features=enabled -D libnsgif=disabled + CC=clang meson imv build_clang -D auto_features=enabled -D libheif=disabled -D libnsgif=disabled CC=clang ninja -C build_clang test diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 97193d7..ddabea2 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -5,6 +5,7 @@ packages: - devel/pkgconf - graphics/freeimage - graphics/libGLU + - graphics/libheif - graphics/libjpeg-turbo - graphics/libnsgif - graphics/librsvg2 diff --git a/.builds/ubuntu.yml b/.builds/ubuntu.yml index cc35286..3070596 100644 --- a/.builds/ubuntu.yml +++ b/.builds/ubuntu.yml @@ -6,6 +6,7 @@ packages: - libegl1-mesa-dev - libfreeimage-dev - libglu-dev + - libheif-dev - libicu-dev - libpango1.0-dev - libpng-dev diff --git a/AUTHORS b/AUTHORS index 385dba0..571ed3d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,6 +2,7 @@ Author and maintainer of imv: * Harry Jeffery People who have contributed to imv: + * Carlo Abelli * Guillaume Brogi * Dmitrij D. Czarkoff * Jose Diez diff --git a/meson.build b/meson.build index f7c1263..648b7d1 100644 --- a/meson.build +++ b/meson.build @@ -107,6 +107,7 @@ foreach backend : [ ['libjpeg', 'dependency', 'libturbojpeg', []], ['librsvg', 'dependency', 'librsvg-2.0', '>= 2.44'], ['libnsgif', 'dependency', 'libnsgif', []], + ['libheif', 'dependency', 'libheif', []], ] _backend_name = backend[0] _dep_type = backend[1] diff --git a/meson_options.txt b/meson_options.txt index 18159dc..f7ecd79 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -57,3 +57,11 @@ option('libnsgif', type : 'feature', description : 'provides: animated gif' ) + +# libheif http://www.libheif.org +# depends: none +# license: LGPL +option('libheif', + type : 'feature', + description : 'provides: heif' +) diff --git a/src/backend_libheif.c b/src/backend_libheif.c new file mode 100644 index 0000000..8264e87 --- /dev/null +++ b/src/backend_libheif.c @@ -0,0 +1,119 @@ +#include +#include +#include + +#include "backend.h" +#include "bitmap.h" +#include "image.h" +#include "source_private.h" + +struct private { + struct heif_image *img; +}; + +static void free_private(void *raw_private) +{ + if (!raw_private) { + return; + } + struct private *private = raw_private; + heif_image_release(private->img); + free(private); +} + +static void load_image(void *raw_private, struct imv_image **image, int *frametime) +{ + *image = NULL; + *frametime = 0; + + struct private *private = raw_private; + + int stride; + const uint8_t *data = heif_image_get_plane_readonly(private->img, heif_channel_interleaved, &stride); + + int width = heif_image_get_width(private->img, heif_channel_interleaved); + int height = heif_image_get_height(private->img, heif_channel_interleaved); + unsigned char *bitmap = malloc(width * height * 4); + memcpy(bitmap, data, width * height * 4); + + struct imv_bitmap *bmp = malloc(sizeof *bmp); + bmp->width = width, + bmp->height = height, + bmp->format = IMV_ABGR; + bmp->data = bitmap; + *image = imv_image_create_from_bitmap(bmp); +} + +static const struct imv_source_vtable vtable = { + .load_first_frame = load_image, + .free = free_private, +}; + +struct heif_error get_primary_image(struct heif_context *ctx, struct heif_image **img) +{ + struct heif_image_handle *handle; + struct heif_error err = heif_context_get_primary_image_handle(ctx, &handle); + if (err.code != heif_error_Ok) { + return err; + } + + err = heif_decode_image(handle, img, heif_colorspace_RGB, heif_chroma_interleaved_RGBA, NULL); + heif_image_handle_release(handle); + return err; +} + +static enum backend_result open_path(const char *path, struct imv_source **src) +{ + struct heif_context *ctx = heif_context_alloc(); + struct heif_error err = heif_context_read_from_file(ctx, path, NULL); // TODO: error + if (err.code != heif_error_Ok) { + heif_context_free(ctx); + if (err.code == heif_error_Input_does_not_exist) { + return BACKEND_BAD_PATH; + } + return BACKEND_UNSUPPORTED; + } + + struct heif_image *img; + err = get_primary_image(ctx, &img); + heif_context_free(ctx); + if (err.code != heif_error_Ok) { + return BACKEND_UNSUPPORTED; + } + + struct private *private = malloc(sizeof *private); + private->img = img; + *src = imv_source_create(&vtable, private); + return BACKEND_SUCCESS; +} + +static enum backend_result open_memory(void *data, size_t len, struct imv_source **src) +{ + struct heif_context *ctx = heif_context_alloc(); + struct heif_error err = heif_context_read_from_memory_without_copy(ctx, data, len, NULL); + if (err.code != heif_error_Ok) { + heif_context_free(ctx); + return BACKEND_UNSUPPORTED; + } + + struct heif_image *img; + err = get_primary_image(ctx, &img); + heif_context_free(ctx); + if (err.code != heif_error_Ok) { + return BACKEND_UNSUPPORTED; + } + + struct private *private = malloc(sizeof *private); + private->img = img; + *src = imv_source_create(&vtable, private); + return BACKEND_SUCCESS; +} + +const struct imv_backend imv_backend_libheif = { + .name = "libheif", + .description = "ISO/IEC 23008-12:2017 HEIF file format decoder and encoder.", + .website = "http://www.libheif.org", + .license = "GNU Lesser General Public License", + .open_path = &open_path, + .open_memory = &open_memory, +}; diff --git a/src/main.c b/src/main.c index cb0db83..1e11f07 100644 --- a/src/main.c +++ b/src/main.c @@ -8,6 +8,7 @@ extern const struct imv_backend imv_backend_librsvg; extern const struct imv_backend imv_backend_libtiff; extern const struct imv_backend imv_backend_libjpeg; extern const struct imv_backend imv_backend_libnsgif; +extern const struct imv_backend imv_backend_libheif; int main(int argc, char **argv) { @@ -41,6 +42,10 @@ int main(int argc, char **argv) imv_install_backend(imv, &imv_backend_freeimage); #endif +#ifdef IMV_BACKEND_LIBHEIF + imv_install_backend(imv, &imv_backend_libheif); +#endif + if (!imv_load_config(imv)) { imv_free(imv); return 1; -- cgit v1.2.3