Commit 0d974ae0 for libheif

commit 0d974ae0896b0057ec895aa544a1ab7bb02d9f81
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri Feb 27 12:56:38 2026 +0100

    unci: adapt public API to handle non-contiguous component indices

diff --git a/libheif/api/libheif/heif_experimental.cc b/libheif/api/libheif/heif_experimental.cc
index e9183451..9fedd7bc 100644
--- a/libheif/api/libheif/heif_experimental.cc
+++ b/libheif/api/libheif/heif_experimental.cc
@@ -340,65 +340,36 @@ void heif_pyramid_layer_info_release(heif_pyramid_layer_info* infos)
 }


-heif_error heif_image_add_channel(heif_image* image,
-                                  heif_channel channel,
-                                  int width, int height,
-                                  heif_channel_datatype datatype, int bit_depth)
-{
-  if (auto err = image->image->add_channel(channel, width, height, datatype, bit_depth, nullptr)) {
-    return err.error_struct(image->image.get());
-  }
-  else {
-    return heif_error_success;
-  }
-}
-
+// --- index-based component access

-heif_channel_datatype heif_image_get_datatype(const heif_image* image, heif_channel channel)
+uint32_t heif_image_get_number_of_used_components(const heif_image* image)
 {
-  if (image == nullptr) {
-    return heif_channel_datatype_undefined;
+  if (!image || !image->image) {
+    return 0;
   }
-
-  return image->image->get_datatype(channel);
+  return image->image->get_number_of_used_components();
 }


-int heif_image_list_channels(heif_image* image,
-                             heif_channel** out_channels)
+uint32_t heif_image_get_total_number_of_cmpd_components(const heif_image* image)
 {
-  if (!image || !out_channels) {
+  if (!image || !image->image) {
     return 0;
   }
-
-  auto channels = image->image->get_channel_set();
-
-  *out_channels = new heif_channel[channels.size()];
-  heif_channel* p = *out_channels;
-  for (heif_channel c : channels) {
-    *p++ = c;
-  }
-
-  assert(channels.size() < static_cast<size_t>(std::numeric_limits<int>::max()));
-
-  return static_cast<int>(channels.size());
+  return image->image->get_total_number_of_cmpd_components();
 }


-void heif_channel_release_list(heif_channel** channels)
+void heif_image_get_used_component_indices(const heif_image* image, uint32_t* out_component_indices)
 {
-  delete[] channels;
-}
-
-
-// --- index-based component access
+  if (!image || !image->image || !out_component_indices) {
+    return;
+  }

-uint32_t heif_image_get_number_of_components(const heif_image* image)
-{
-  if (!image || !image->image) {
-    return 0;
+  auto indices = image->image->get_used_component_indices();
+  for (size_t i = 0; i < indices.size(); i++) {
+    out_component_indices[i] = indices[i];
   }
-  return image->image->get_number_of_components();
 }


diff --git a/libheif/api/libheif/heif_experimental.h b/libheif/api/libheif/heif_experimental.h
index 1b8e3bde..d2d7a546 100644
--- a/libheif/api/libheif/heif_experimental.h
+++ b/libheif/api/libheif/heif_experimental.h
@@ -188,23 +188,6 @@ typedef enum heif_channel_datatype
   heif_channel_datatype_complex_number = 4
 } heif_channel_datatype;

-#if HEIF_ENABLE_EXPERIMENTAL_FEATURES
-LIBHEIF_API
-heif_error heif_image_add_channel(heif_image* image,
-                                  enum heif_channel channel,
-                                  int width, int height,
-                                  enum heif_channel_datatype datatype,
-                                  int bit_depth);
-
-
-LIBHEIF_API
-int heif_image_list_channels(heif_image*,
-                             enum heif_channel** out_channels);
-
-LIBHEIF_API
-void heif_channel_release_list(enum heif_channel** channels);
-#endif
-
 typedef struct heif_complex32
 {
   float real, imaginary;
@@ -216,15 +199,21 @@ typedef struct heif_complex64
 } heif_complex64;

 #if HEIF_ENABLE_EXPERIMENTAL_FEATURES
-LIBHEIF_API
-enum heif_channel_datatype heif_image_get_datatype(const heif_image* img,
-                                                   enum heif_channel channel);
-

 // --- index-based component access (for ISO 23001-17 multi-component images)

+// Returns the number of components that have pixel data (planes) in this image.
+LIBHEIF_API
+uint32_t heif_image_get_number_of_used_components(const heif_image*);
+
+// Returns the total number of components declared in the cmpd box.
+LIBHEIF_API
+uint32_t heif_image_get_total_number_of_cmpd_components(const heif_image*);
+
+// Fills `out_component_indices` with the valid component indices.
+// The caller must allocate an array of at least heif_image_get_number_of_used_components() elements.
 LIBHEIF_API
-uint32_t heif_image_get_number_of_components(const heif_image*);
+void heif_image_get_used_component_indices(const heif_image*, uint32_t* out_component_indices);

 LIBHEIF_API
 enum heif_channel heif_image_get_component_channel(const heif_image*, uint32_t component_idx);
diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
index a24bc808..0fac9295 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
@@ -50,7 +50,7 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
                                                                    const heif_encoding_options& options)
 {
   bool is_nonvisual = (image->get_colorspace() == heif_colorspace_nonvisual);
-  uint32_t num_components = image->get_number_of_components();
+  uint32_t num_components = image->get_number_of_used_components();

   for (uint32_t idx = 0; idx < num_components; idx++) {
     heif_uncompressed_component_type comp_type;
diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index e76fc271..0ff24ef8 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -2232,7 +2232,7 @@ Result<uint32_t> HeifPixelImage::add_component_for_index(uint32_t component_inde
 }


-std::vector<uint32_t> HeifPixelImage::get_component_indices() const
+std::vector<uint32_t> HeifPixelImage::get_used_component_indices() const
 {
   std::vector<uint32_t> indices;
   indices.reserve(m_planes.size());
diff --git a/libheif/pixelimage.h b/libheif/pixelimage.h
index f79e4bf0..5e53888d 100644
--- a/libheif/pixelimage.h
+++ b/libheif/pixelimage.h
@@ -416,7 +416,9 @@ public:

   // --- index-based component access (for ISO 23001-17 multi-component images)

-  uint32_t get_number_of_components() const { return static_cast<uint32_t>(m_planes.size()); }
+  uint32_t get_number_of_used_components() const { return static_cast<uint32_t>(m_planes.size()); }
+
+  uint32_t get_total_number_of_cmpd_components() const { return static_cast<uint32_t>(m_cmpd_component_types.size()); }

   heif_channel get_component_channel(uint32_t component_idx) const;

@@ -445,8 +447,8 @@ public:
   // Populate the cmpd component types table (decoder path).
   void set_cmpd_component_types(std::vector<uint16_t> types) { m_cmpd_component_types = std::move(types); }

-  // Returns the sorted list of component_indices of all planes.
-  std::vector<uint32_t> get_component_indices() const;
+  // Returns the sorted list of component_indices of all planes that have pixel data.
+  std::vector<uint32_t> get_used_component_indices() const;

   uint8_t* get_component(uint32_t component_idx, size_t* out_stride);
   const uint8_t* get_component(uint32_t component_idx, size_t* out_stride) const;
diff --git a/tests/uncompressed_encode_multicomponent.cc b/tests/uncompressed_encode_multicomponent.cc
index 96bb8105..b531a9d8 100644
--- a/tests/uncompressed_encode_multicomponent.cc
+++ b/tests/uncompressed_encode_multicomponent.cc
@@ -308,7 +308,7 @@ bool values_equal<heif_complex64>(heif_complex64 a, heif_complex64 b)
 template <typename T>
 static void verify_image_data(const heif_image* image)
 {
-  uint32_t num_components = heif_image_get_number_of_components(image);
+  uint32_t num_components = heif_image_get_number_of_used_components(image);
   REQUIRE(num_components == kNumComponents);

   for (uint32_t c = 0; c < kNumComponents; c++) {