GraphicsMagick: ReadHEIFImage(): Pass decode options to heif_dec...

GraphicsMagick Commits <[email protected]>
Newsgroups gmane.comp.video.graphicsmagick.cvs
Message-ID <mailman.33263.1645922381.1623.graphicsmagick-commit@lists.sourceforge.net>
changeset 1428b30e12b0 in /hg/GraphicsMagick
details: http://hg.GraphicsMagick.org/hg/GraphicsMagick?cmd=changeset;node=1428b30e12b0
summary: ReadHEIFImage(): Pass decode options to heif_decode_image().

diffstat:

 ChangeLog          |    5 ++
 coders/heif.c      |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 www/Changelog.html |    4 +
 3 files changed, 118 insertions(+), 3 deletions(-)

diffs (181 lines):

diff -r 90e1c92a709c -r 1428b30e12b0 ChangeLog
--- a/ChangeLog	Sat Feb 26 09:36:35 2022 -0600
+++ b/ChangeLog	Sat Feb 26 18:39:29 2022 -0600
@@ -1,5 +1,10 @@
 2022-02-26  Bob Friesenhahn  <[email protected]>
 
+        * coders/heif.c (ReadHEIFImage): Pass decode options to
+        heif_decode_image().  Include rough implementation of progress
+        monitor support but leave it disabled since libheif does not
+        currently invoke the callbacks.
+
         * coders/jpeg.c (ReadJPEGImage): Store embedded profiles in image,
         even if in 'ping' mode.  This addresses a problem discovered when
         interfacing with minimagick (Debian bug #1006374 "graphicsmagick
diff -r 90e1c92a709c -r 1428b30e12b0 coders/heif.c
--- a/coders/heif.c	Sat Feb 26 09:36:35 2022 -0600
+++ b/coders/heif.c	Sat Feb 26 18:39:29 2022 -0600
@@ -32,6 +32,9 @@
 #include "magick/utility.h"
 #include "magick/resource.h"
 
+/* Set to 1 to enable the currently non-functional progress monitor callbacks */
+#define HEIF_ENABLE_PROGRESS_MONITOR 0
+
 #if defined(HasHEIF)
 #include <libheif/heif.h>
 
@@ -116,7 +119,6 @@
     ThrowReaderException(code_,reason_,image_)         \
   }
 
-
 static Image *ReadMetadata(struct heif_image_handle *heif_image_handle,
                            Image *image, ExceptionInfo *exception)
 {
@@ -194,6 +196,74 @@
   return image;
 }
 
+/*
+  This progress monitor implementation is tentative since it is not invoked
+
+  According to libheif issue 161
+  (https://github.com/strukturag/libheif/issues/161) progress monitor
+  does not actually work since the decoders it depends on do not
+  support it.
+
+  Libheif issue 546 (https://github.com/strukturag/libheif/pull/546)
+  suggests changing the return type of on_progress and start_progress
+  to "bool" so that one can implement cancelation support.
+ */
+typedef struct ProgressUserData_
+{
+  ExceptionInfo *exception;
+  Image *image;
+  enum heif_progress_step step;
+  unsigned long int progress;
+  unsigned long int max_progress;
+
+} ProgressUserData;
+
+#if HEIF_ENABLE_PROGRESS_MONITOR
+/* Called when progress monitor starts.  The 'max_progress' parameter indicates the maximum value of progress */
+static void start_progress(enum heif_progress_step step, int max_progress, void* progress_user_data)
+{
+  ProgressUserData *context= (ProgressUserData *) progress_user_data;
+  Image *image=context->image;
+  context->step = step;
+  context->progress = 0;
+  context->max_progress = max_progress;
+  if (context->image->logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "start_progress: step=%d, max_progress=%d",step, max_progress);
+  MagickMonitorFormatted(context->progress,context->max_progress,&image->exception,
+                         "[%s] Loading image: %lux%lu...  ",
+                         image->filename,
+                         image->columns,image->rows);
+}
+
+/* Called for each step of progress.  The 'progress' parameter represents the progress within the span of 'max_progress' */
+static void on_progress(enum heif_progress_step step, int progress, void* progress_user_data)
+{
+  ProgressUserData *context = (ProgressUserData *) progress_user_data;
+  Image *image=context->image;
+  context->step = step;
+  context->progress = progress;
+  if (context->image->logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "on_progress: step=%d, progress=%d",step, progress);
+  MagickMonitorFormatted(context->progress,context->max_progress,&image->exception,
+                         "[%s] Loading image: %lux%lu...  ",
+                         image->filename,
+                         image->columns,image->rows);
+}
+
+/* Called when progress monitor stops */
+static void end_progress(enum heif_progress_step step, void* progress_user_data)
+{
+  ProgressUserData *context = (ProgressUserData *) progress_user_data;
+  context->step = step;
+  if (context->image->logging)
+    (void) LogMagickEvent(CoderEvent,GetMagickModule(),
+                          "end_progress: step=%d",step);
+}
+
+#endif /* if HEIF_ENABLE_PROGRESS_MONITOR */
+
 static Image *ReadHEIFImage(const ImageInfo *image_info,
                             ExceptionInfo *exception)
 {
@@ -212,6 +282,12 @@
   struct heif_image
     *heif_image = NULL;
 
+  struct heif_decoding_options
+    *decode_options;
+
+  ProgressUserData
+    progress_user_data;
+
   size_t
     in_len;
 
@@ -316,11 +392,41 @@
   if (CheckImagePixelLimits(image, exception) != MagickPass)
     ThrowHEIFReaderException(ResourceLimitError,ImagePixelLimitExceeded,image);
 
-  /* FIXME: Add decoding options support such as a progress monitor */
+  /* Add decoding options support */
+  decode_options = heif_decoding_options_alloc();
+  if (decode_options == (struct heif_decoding_options*) NULL)
+    ThrowHEIFReaderException(ResourceLimitError,MemoryAllocationFailed,image);
+
+  progress_user_data.exception = exception;
+  progress_user_data.image = image;
+  progress_user_data.max_progress = 0;
+  progress_user_data.progress = 0;
+
+  /* version 1 options */
+  decode_options->ignore_transformations = 0;
+#if HEIF_ENABLE_PROGRESS_MONITOR
+  decode_options->start_progress = start_progress;
+  decode_options->on_progress = on_progress;
+  decode_options->end_progress = end_progress;
+#endif /* if HEIF_ENABLE_PROGRESS_MONITOR */
+  decode_options->progress_user_data = &progress_user_data;
+
+  /* version 2 options */
+#if LIBHEIF_NUMERIC_VERSION > 0x01070000
+  decode_options->convert_hdr_to_8bit = 1;
+#endif /* if LIBHEIF_NUMERIC_VERSION > 0x01070000 */
+
+  /* version 3 options */
+
+  /* When enabled, an error is returned for invalid input. Otherwise, it will try its best and
+     add decoding warnings to the decoded heif_image. Default is non-strict. */
+  /* uint8_t strict_decoding; */
+
   heif_status=heif_decode_image(heif_image_handle, &heif_image,
                                 heif_colorspace_RGB, image->matte ? heif_chroma_interleaved_RGBA :
                                 heif_chroma_interleaved_RGB,
-                                /* const struct heif_decoding_options* */ NULL );
+                                decode_options);
+  heif_decoding_options_free(decode_options);
   if (heif_status.code == heif_error_Memory_allocation_error)
     ThrowHEIFReaderException(ResourceLimitError,MemoryAllocationFailed,image);
   if (heif_status.code != heif_error_Ok)
diff -r 90e1c92a709c -r 1428b30e12b0 www/Changelog.html
--- a/www/Changelog.html	Sat Feb 26 09:36:35 2022 -0600
+++ b/www/Changelog.html	Sat Feb 26 18:39:29 2022 -0600
@@ -37,6 +37,10 @@
 
 <p>2022-02-26  Bob Friesenhahn  &lt;<a class="reference external" href="mailto:bfriesen&#37;&#52;&#48;simple&#46;dallas&#46;tx&#46;us">bfriesen<span>&#64;</span>simple<span>&#46;</span>dallas<span>&#46;</span>tx<span>&#46;</span>us</a>&gt;</p>
 <blockquote>
+<p>* coders/heif.c (ReadHEIFImage): Pass decode options to
+heif_decode_image().  Include rough implementation of progress
+monitor support but leave it disabled since libheif does not
+currently invoke the callbacks.</p>
 <p>* coders/jpeg.c (ReadJPEGImage): Store embedded profiles in image,
 even if in 'ping' mode.  This addresses a problem discovered when
 interfacing with minimagick (Debian bug #1006374 &quot;graphicsmagick
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.