Commit 748656fb for libheif

commit 748656fb74e3ed60e2a1a429574af9b2cb15e63c
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Thu Aug 27 02:53:12 2026 +0200

    make Result<T> and Error operator bool explicit

    An implicit operator bool() lets `id = result;` and `return err;` from an
    int-returning function compile silently and yield 0/1. This is the root cause of
    the bug fixed piecemeal in #1885 (and twice before): three item writers stored
    the boolean value of a Result<heif_item_id> instead of the ID.

    With 'explicit', only contextual conversions (if/!/&&/assert) compile. Rebuilding
    all targets flagged the remaining copies of the bug, fixed here:

    - heif_context_add_pyramid_entity_group stored `*out_group_id = result;` and
      always reported group ID 1.
    - ImageItem::get_luma_bits_per_pixel / get_chroma_bits_per_pixel returned
      `decoderResult.error()`, i.e. 1 instead of the documented -1.

diff --git a/libheif/api/libheif/heif_experimental.cc b/libheif/api/libheif/heif_experimental.cc
index e83a0301..0dc96df2 100644
--- a/libheif/api/libheif/heif_experimental.cc
+++ b/libheif/api/libheif/heif_experimental.cc
@@ -286,7 +286,7 @@ heif_error heif_context_add_pyramid_entity_group(struct heif_context* ctx,

   if (result) {
     if (out_group_id) {
-      *out_group_id = result;
+      *out_group_id = *result;
     }
     return heif_error_success;
   }
diff --git a/libheif/error.h b/libheif/error.h
index 607605e0..2ea36f4d 100644
--- a/libheif/error.h
+++ b/libheif/error.h
@@ -111,7 +111,10 @@ public:
     }
   }

-  operator bool() const { return error_code != heif_error_Ok; }
+  // 'explicit' so that an Error can only be tested in a boolean context (if/!/&&/...).
+  // Without it, `int x = err;` or `return err;` from an int function silently compile
+  // and yield 0/1 instead of the intended value.
+  explicit operator bool() const { return error_code != heif_error_Ok; }

   static const char* get_error_string(heif_error_code err);

@@ -137,7 +140,11 @@ public:

   Result(const Error& e) : m_data(e) {}

-  operator bool() const { return std::holds_alternative<T>(m_data); }
+  // True if the Result holds a value, false if it holds an error.
+  // 'explicit' so that the value can only be extracted with operator*: `id = result;` must
+  // not compile, because it would store the boolean (this bug shipped several times, see
+  // https://github.com/strukturag/libheif/pull/1885).
+  explicit operator bool() const { return std::holds_alternative<T>(m_data); }

   //void set(const T& v) { m_data = v; }

diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index d5624bab..98f76f61 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -523,7 +523,7 @@ int ImageItem::get_luma_bits_per_pixel() const
 {
   auto decoderResult = get_decoder();
   if (!decoderResult) {
-    return decoderResult.error();
+    return -1;
   }

   auto decoder = *decoderResult;
@@ -536,7 +536,7 @@ int ImageItem::get_chroma_bits_per_pixel() const
 {
   auto decoderResult = get_decoder();
   if (!decoderResult) {
-    return decoderResult.error();
+    return -1;
   }

   auto decoder = *decoderResult;