Commit 0b81eb93 for libheif

commit 0b81eb93c8ce00e4889c74d4d3af9a1de3c58527
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Wed May 13 22:00:15 2026 +0200

    combine two functions into register_plane_descriptions()

diff --git a/libheif/image/pixelimage.cc b/libheif/image/pixelimage.cc
index 333c2952..10e10dfb 100644
--- a/libheif/image/pixelimage.cc
+++ b/libheif/image/pixelimage.cc
@@ -295,23 +295,11 @@ static uint32_t rounded_size(uint32_t s)
   return s;
 }

-HeifPixelImage::ImageComponent HeifPixelImage::new_image_plane_for_channel(heif_channel channel)
+void HeifPixelImage::register_plane_descriptions(ImageComponent& plane,
+                                                 heif_channel channel,
+                                                 const std::vector<uint16_t>& component_types)
 {
-  ImageComponent plane;
-
-  // libheif channel type
-
-  plane.m_channel = channel;
-
-  // ISO 23001-17 component types
-  // For interleaved planes, several component types are added to cmpd.
-  // Each component gets a freshly-minted id and an entry in the inherited
-  // ImageDescription::m_components vector. Datatype / bit_depth / width /
-  // height fields stay at their defaults; they are filled in after alloc()
-  // succeeds, by fill_component_descriptions_after_alloc().
-
-  auto component_types = map_channel_to_component_type(channel, m_chroma);
-  for (auto type : component_types) {
+  for (uint16_t type : component_types) {
     uint32_t id = mint_component_id();
     plane.m_component_ids.push_back(id);

@@ -319,21 +307,19 @@ HeifPixelImage::ImageComponent HeifPixelImage::new_image_plane_for_channel(heif_
     desc.component_id = id;
     desc.channel = channel;
     desc.component_type = type;
+    desc.datatype = plane.m_datatype;
+    desc.bit_depth = plane.m_bit_depth;
+    desc.width = plane.m_width;
+    desc.height = plane.m_height;
     desc.has_data_plane = true;
     add_component_description(std::move(desc));
   }
-
-  return plane;
 }


 Error HeifPixelImage::add_plane(heif_channel channel, uint32_t width, uint32_t height, int bit_depth,
                                 const heif_security_limits* limits)
 {
-  ImageComponent plane = new_image_plane_for_channel(channel);
-
-  int num_interleaved_pixels = num_interleaved_components_per_plane(m_chroma);
-
   // for backwards compatibility, allow for 24/32 bits for RGB/RGBA interleaved chromas

   if (m_chroma == heif_chroma_interleaved_RGB && bit_depth == 24) {
@@ -344,49 +330,34 @@ Error HeifPixelImage::add_plane(heif_channel channel, uint32_t width, uint32_t h
     bit_depth = 8;
   }

+  int num_interleaved_pixels = num_interleaved_components_per_plane(m_chroma);
+
+  ImageComponent plane;
+  plane.m_channel = channel;
+
   if (auto err = plane.alloc(width, height, heif_component_datatype_unsigned_integer, bit_depth, num_interleaved_pixels, limits, m_memory_handle)) {
     return err;
   }
-  else {
-    fill_component_descriptions_after_alloc(plane, width, height);
-    m_planes.push_back(plane);
-    return Error::Ok;
-  }
+
+  register_plane_descriptions(plane, channel, map_channel_to_component_type(channel, m_chroma));
+  m_planes.push_back(std::move(plane));
+  return Error::Ok;
 }


 Error HeifPixelImage::add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_component_datatype datatype, int bit_depth,
                                   const heif_security_limits* limits)
 {
-  ImageComponent plane = new_image_plane_for_channel(channel);
+  ImageComponent plane;
+  plane.m_channel = channel;

   if (Error err = plane.alloc(width, height, datatype, bit_depth, 1, limits, m_memory_handle)) {
     return err;
   }
-  else {
-    fill_component_descriptions_after_alloc(plane, width, height);
-    m_planes.push_back(plane);
-    return Error::Ok;
-  }
-}
-

-// After alloc() has succeeded on `plane`, fill in the per-id fields of the
-// existing ComponentDescription entries (which were pushed at id-mint time
-// in new_image_plane_for_channel or by add_component). id, channel and
-// component_type were already set then; datatype, bit_depth, width and
-// height become known here.
-void HeifPixelImage::fill_component_descriptions_after_alloc(const ImageComponent& plane,
-                                                             uint32_t width, uint32_t height)
-{
-  for (uint32_t cid : plane.m_component_ids) {
-    auto* desc = find_component_description(cid);
-    if (!desc) continue; // shouldn't happen; defensive
-    desc->datatype = plane.m_datatype;
-    desc->bit_depth = plane.m_bit_depth;
-    desc->width = width;
-    desc->height = height;
-  }
+  register_plane_descriptions(plane, channel, map_channel_to_component_type(channel, m_chroma));
+  m_planes.push_back(std::move(plane));
+  return Error::Ok;
 }


@@ -2155,27 +2126,18 @@ Result<uint32_t> HeifPixelImage::add_component(uint32_t width, uint32_t height,
                                                heif_component_datatype datatype, int bit_depth,
                                                const heif_security_limits* limits)
 {
-  // Auto-generate component_id by appending to the description vector.
-  uint32_t component_id = mint_component_id();
-
-  // Push a partial description now (id, channel, type known); the remaining
-  // fields will be filled in by fill_component_descriptions_after_alloc().
-  ComponentDescription desc;
-  desc.component_id = component_id;
-  desc.channel = map_uncompressed_component_to_channel(component_type);
-  desc.component_type = component_type;
-  desc.has_data_plane = true;
-  add_component_description(std::move(desc));
+  heif_channel channel = map_uncompressed_component_to_channel(component_type);

   ImageComponent plane;
-  plane.m_channel = map_uncompressed_component_to_channel(component_type);
-  plane.m_component_ids = std::vector{component_id};
+  plane.m_channel = channel;
+
   if (Error err = plane.alloc(width, height, datatype, bit_depth, 1, limits, m_memory_handle)) {
     return {err};
   }

-  fill_component_descriptions_after_alloc(plane, width, height);
-  m_planes.push_back(plane);
+  register_plane_descriptions(plane, channel, {component_type});
+  uint32_t component_id = plane.m_component_ids.front();
+  m_planes.push_back(std::move(plane));
   return component_id;
 }

diff --git a/libheif/image/pixelimage.h b/libheif/image/pixelimage.h
index 25acaa73..51ebb485 100644
--- a/libheif/image/pixelimage.h
+++ b/libheif/image/pixelimage.h
@@ -369,14 +369,14 @@ private:
   ImageComponent* find_component_by_id(uint32_t component_id);
   const ImageComponent* find_component_by_id(uint32_t component_id) const;

-  ImageComponent new_image_plane_for_channel(heif_channel channel);
-
-  // After alloc() succeeds on `plane`, fills in datatype / component_format
-  // / bit_depth / width / height of the matching ComponentDescription
-  // entries (which were already pushed at id-mint time with id, channel,
-  // and component_type populated).
-  void fill_component_descriptions_after_alloc(const ImageComponent& plane,
-                                                uint32_t width, uint32_t height);
+  // After plane.alloc() has succeeded, mints fresh component ids, appends
+  // them to plane.m_component_ids, and pushes fully-populated
+  // ComponentDescription entries for each component_type. Must only be
+  // called once allocation has succeeded so that no descriptions are
+  // registered for a plane that failed to materialize.
+  void register_plane_descriptions(ImageComponent& plane,
+                                   heif_channel channel,
+                                   const std::vector<uint16_t>& component_types);

   uint32_t m_width = 0;
   uint32_t m_height = 0;