Commit d9ff25fb for libheif

commit d9ff25fb34bfbcf5ed32a9c8117809a0f07c22a2
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Tue May 26 16:50:59 2026 +0200

    only reject decoding images with errors (e.g., do not reject file completely when 'rref' check fails) (#1823)

diff --git a/libheif/api/libheif/heif_context.cc b/libheif/api/libheif/heif_context.cc
index 04cb516f..b25ab494 100644
--- a/libheif/api/libheif/heif_context.cc
+++ b/libheif/api/libheif/heif_context.cc
@@ -166,8 +166,7 @@ heif_error heif_context_get_primary_image_handle(heif_context* ctx, heif_image_h
     return err.error_struct(ctx->context.get());
   }

-  if (auto errImage = std::dynamic_pointer_cast<ImageItem_Error>(primary_image)) {
-    Error error = errImage->get_item_error();
+  if (Error error = primary_image->get_item_error()) {
     return error.error_struct(ctx->context.get());
   }

@@ -189,17 +188,16 @@ heif_error heif_context_get_image_handle(heif_context* ctx,

   auto image = ctx->context->get_image(id, true);

-  if (auto errImage = std::dynamic_pointer_cast<ImageItem_Error>(image)) {
-    Error error = errImage->get_item_error();
-    return error.error_struct(ctx->context.get());
-  }
-
   if (!image) {
     *imgHdl = nullptr;

     return {heif_error_Usage_error, heif_suberror_Nonexisting_item_referenced, ""};
   }

+  if (Error error = image->get_item_error()) {
+    return error.error_struct(ctx->context.get());
+  }
+
   *imgHdl = new heif_image_handle();
   (*imgHdl)->image = std::move(image);
   (*imgHdl)->context = ctx->context;
diff --git a/libheif/context.cc b/libheif/context.cc
index 037f84b6..8cd066cb 100644
--- a/libheif/context.cc
+++ b/libheif/context.cc
@@ -679,12 +679,15 @@ Error HeifContext::interpret_heif_file_images()
     }


-    // --- Are there any `rref` reference types that we do not process
+    // --- Are there any `rref` reference types that we do not process.
+    // This only makes the affected item undecodable; other items in the file
+    // can still be decoded, so we do not abort the whole load.

     auto rrefBox = m_heif_file->get_property_for_item<Box_rref>(pair.first);
     if (rrefBox) {
       if (Error err = rrefBox->reference_types_supported_error()) {
-        return err;
+        image->set_item_error(err);
+        continue;
       }
     }

diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index e9cdb585..083b9dff 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -881,6 +881,10 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_image(const heif_decod
                  "'iref' has cyclic references"};
   }

+  if (m_item_error) {
+    return m_item_error;
+  }
+
   std::lock_guard<std::mutex> lock(m_decode_mutex);

   // --- check whether image size (according to 'ispe') exceeds maximum
diff --git a/libheif/image-items/image_item.h b/libheif/image-items/image_item.h
index 4d8ff51e..550088b8 100644
--- a/libheif/image-items/image_item.h
+++ b/libheif/image-items/image_item.h
@@ -76,7 +76,12 @@ public:

   bool is_property_essential(const std::shared_ptr<Box>& property) const;

-  virtual Error get_item_error() const { return Error::Ok; }
+  virtual Error get_item_error() const { return m_item_error; }
+
+  // Mark this item as undecodable. The file still loads and other items remain
+  // usable, but decoding this item (or listing it as a non-error image) will
+  // surface this error.
+  void set_item_error(const Error& err) { m_item_error = err; }

   virtual heif_compression_format get_compression_format() const { return heif_compression_undefined; }

@@ -446,6 +451,8 @@ private:
   HeifContext* m_heif_context;
   std::vector<std::shared_ptr<Box>> m_properties;

+  Error m_item_error;  // if set, this item cannot be decoded (e.g. unsupported required reference types)
+
   heif_item_id m_id = 0;
   uint32_t m_width = 0, m_height = 0;  // after all transformations have been applied
   bool m_is_primary = false;