Update HEIC/HEIF decoding
authorColin Clark <cclark@carbon>
Wed, 6 Nov 2019 11:44:00 +0000 (11:44 +0000)
committerColin Clark <cclark@carbon>
Wed, 6 Nov 2019 11:44:00 +0000 (11:44 +0000)
Include filetype .heif
Inlude brands ftypmif1, ftypmsf1 (image only - libheif does not support
animations)
Display multiple images in a single file

src/filefilter.c
src/image-load.c
src/image_load_heif.c
src/layout.c

index f80d4a9..adb5316 100644 (file)
@@ -295,7 +295,7 @@ void filter_add_defaults(void)
        filter_add_if_missing("pdf", "Portable Document Format", ".pdf", FORMAT_CLASS_DOCUMENT, FALSE, FALSE, TRUE);
 #endif
 #ifdef HAVE_HEIF
-       filter_add_if_missing("HEIF", "HEIF Format", ".heic", FORMAT_CLASS_IMAGE, FALSE, FALSE, TRUE);
+       filter_add_if_missing("HEIF", "HEIF Format", ".heic;.heif", FORMAT_CLASS_IMAGE, FALSE, FALSE, TRUE);
 #endif
 #ifdef HAVE_WEBP
        filter_add_if_missing("webp", "WebP Format", ".webp", FORMAT_CLASS_IMAGE, FALSE, FALSE, TRUE);
index 6c9a305..136e8d4 100644 (file)
@@ -637,8 +637,10 @@ static void image_loader_setup_loader(ImageLoader *il)
        else
 #endif
 #ifdef HAVE_HEIF
-       if (il->bytes_total >= 10 &&
-           (memcmp(il->mapped_file + 4, "ftypheic", 8) == 0))
+       if (il->bytes_total >= 12 &&
+               ((memcmp(il->mapped_file + 4, "ftypheic", 8) == 0) ||
+               (memcmp(il->mapped_file + 4, "ftypmsf1", 8) == 0) ||
+               (memcmp(il->mapped_file + 4, "ftypmif1", 8) == 0)))
                {
                DEBUG_1("Using custom heif loader");
                image_loader_backend_set_heif(&il->backend);
@@ -741,6 +743,15 @@ static void image_loader_setup_loader(ImageLoader *il)
        g_free(format);
 #endif
 
+#ifdef HAVE_HEIF
+       format = il->backend.get_format_name(il->loader);
+       if (g_strcmp0(format, "heif") == 0)
+               {
+               il->backend.set_page_num(il->loader, il->fd->page_num);
+               }
+       g_free(format);
+#endif
+
 #ifdef HAVE_DJVU
        format = il->backend.get_format_name(il->loader);
        if (g_strcmp0(format, "djvu") == 0)
@@ -843,6 +854,15 @@ static gboolean image_loader_begin(ImageLoader *il)
                }
        g_free(format);
 #endif
+#ifdef HAVE_HEIF
+       format = il->backend.get_format_name(il->loader);
+       if (g_strcmp0(format, "heif") == 0)
+               {
+               gint i = il->backend.get_page_total(il->loader);
+               file_data_set_page_total(il->fd, i);
+               }
+       g_free(format);
+#endif
 #ifdef HAVE_DJVU
        format = il->backend.get_format_name(il->loader);
        if (g_strcmp0(format, "djvu") == 0)
index ae14406..5791a57 100644 (file)
@@ -36,6 +36,8 @@ struct _ImageLoaderHEIF {
        guint requested_width;
        guint requested_height;
        gboolean abort;
+       gint page_num;
+       gint page_total;
 };
 
 static void free_buffer(guchar *pixels, gpointer data)
@@ -54,6 +56,7 @@ static gboolean image_loader_heif_load(gpointer loader, const guchar *buf, gsize
        gint width, height;
        gint stride;
        gboolean alpha;
+       gint page_total;
 
        ctx = heif_context_alloc();
 
@@ -64,34 +67,43 @@ static gboolean image_loader_heif_load(gpointer loader, const guchar *buf, gsize
                heif_context_free(ctx);
                return FALSE;
                }
-
-       // get a handle to the primary image
-       error_code = heif_context_get_primary_image_handle(ctx, &handle);
-       if (error_code.code)
+       else
                {
-               log_printf("warning: heif reader error: %s\n", error_code.message);
-               heif_context_free(ctx);
-               return FALSE;
-               }
+               page_total = heif_context_get_number_of_top_level_images(ctx);
+               ld->page_total = page_total;
 
-       // decode the image and convert colorspace to RGB, saved as 24bit interleaved
-       error_code = heif_decode_image(handle, &img, heif_colorspace_RGB, heif_chroma_interleaved_24bit, NULL);
-       if (error_code.code)
-               {
-               log_printf("warning: heif reader error: %s\n", error_code.message);
-               heif_context_free(ctx);
-               return FALSE;
-               }
+               guint32 IDs[page_total * sizeof(guint32)];
+
+               /* get list of all (top level) image IDs */
+               heif_context_get_list_of_top_level_image_IDs(ctx, IDs, page_total);
 
-       data = heif_image_get_plane(img, heif_channel_interleaved, &stride);
+               error_code = heif_context_get_image_handle(ctx, IDs[ld->page_num], &handle);
+               if (error_code.code)
+                       {
+                       log_printf("warning:  heif reader error: %s\n", error_code.message);
+                       heif_context_free(ctx);
+                       return FALSE;
+                       }
 
-       height = heif_image_get_height(img,heif_channel_interleaved);
-       width = heif_image_get_width(img,heif_channel_interleaved);
-       alpha = heif_image_handle_has_alpha_channel(handle);
+               // decode the image and convert colorspace to RGB, saved as 24bit interleaved
+               error_code = heif_decode_image(handle, &img, heif_colorspace_RGB, heif_chroma_interleaved_24bit, NULL);
+               if (error_code.code)
+                       {
+                       log_printf("warning: heif reader error: %s\n", error_code.message);
+                       heif_context_free(ctx);
+                       return FALSE;
+                       }
 
-       ld->pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, alpha, 8, width, height, stride, free_buffer, NULL);
+               data = heif_image_get_plane(img, heif_channel_interleaved, &stride);
 
-       ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
+               height = heif_image_get_height(img,heif_channel_interleaved);
+               width = heif_image_get_width(img,heif_channel_interleaved);
+               alpha = heif_image_handle_has_alpha_channel(handle);
+
+               ld->pixbuf = gdk_pixbuf_new_from_data(data, GDK_COLORSPACE_RGB, alpha, 8, width, height, stride, free_buffer, NULL);
+
+               ld->area_updated_cb(loader, 0, 0, width, height, ld->data);
+               }
 
        heif_context_free(ctx);
 
@@ -105,6 +117,7 @@ static gpointer image_loader_heif_new(ImageLoaderBackendCbAreaUpdated area_updat
        loader->size_cb = size_cb;
        loader->area_prepared_cb = area_prepared_cb;
        loader->data = data;
+       loader->page_num = 0;
        return (gpointer) loader;
 }
 
@@ -132,6 +145,21 @@ static gchar** image_loader_heif_get_format_mime_types(gpointer loader)
        return g_strdupv(mime);
 }
 
+static void image_loader_heif_set_page_num(gpointer loader, gint page_num)
+{
+       ImageLoader *il = (ImageLoader *) loader;
+       ImageLoaderHEIF *ld = (ImageLoaderHEIF *) loader;
+
+       ld->page_num = page_num;
+}
+
+static gint image_loader_heif_get_page_total(gpointer loader)
+{
+       ImageLoaderHEIF *ld = (ImageLoaderHEIF *) loader;
+
+       return ld->page_total;
+}
+
 static gboolean image_loader_heif_close(gpointer loader, GError **error)
 {
        return TRUE;
@@ -162,6 +190,8 @@ void image_loader_backend_set_heif(ImageLoaderBackend *funcs)
        funcs->free = image_loader_heif_free;
        funcs->get_format_name = image_loader_heif_get_format_name;
        funcs->get_format_mime_types = image_loader_heif_get_format_mime_types;
+       funcs->set_page_num = image_loader_heif_set_page_num;
+       funcs->get_page_total = image_loader_heif_get_page_total;
 }
 
 #endif
index d7edb2d..b844689 100644 (file)
@@ -724,7 +724,7 @@ void layout_status_update_image(LayoutWindow *lw)
                        page_num = fd->page_num + 1;
                        image_get_image_size(lw->image, &width, &height);
 
-                       if (page_total > 0)
+                       if (page_total > 1)
                                {
                                text = g_strdup_printf(_("( %d x %d ) %s bytes %s%d%s%d%s"), width, height, b, "[", page_num, "/", page_total, "]");
                                }