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. --- src/backend_libheif.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 5 +++ 2 files changed, 124 insertions(+) create mode 100644 src/backend_libheif.c (limited to 'src') 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