Commit 72afe3d4 for libheif

commit 72afe3d4c9f91a2102e5c6cb59812bc35205fba9
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sat Apr 4 16:05:27 2026 +0200

    unci: map uncC index to component id (wip)

diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index cddb2681..a6dcbb91 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -204,6 +204,7 @@ static Error validate_component_indices(const std::vector<uint32_t>& indices,
 Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(const unci_properties& properties,
                                                                              uint32_t width,
                                                                              uint32_t height,
+                                                                             std::vector<uint32_t>& uncC_index_to_comp_ids,
                                                                              const heif_security_limits* limits)
 {
   auto cmpd = properties.cmpd;
@@ -252,6 +253,7 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con
       }

       cmpd_index_to_comp_ids[component.component_index].push_back(*result);
+      uncC_index_to_comp_ids.push_back(*result);
     }
     else {
       Result<uint32_t> result = img->add_component(width,
@@ -265,6 +267,7 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con
       }

       cmpd_index_to_comp_ids[component.component_index].push_back(*result);
+      uncC_index_to_comp_ids.push_back(*result);
     }
   }

@@ -371,15 +374,16 @@ Error UncompressedImageCodec::decode_uncompressed_image_tile(const HeifContext*
   // Remember which components reference which cmpd indices.
   // There can be several component ids referencing the same cmpd index.
   std::vector<std::vector<uint32_t>> cmpd_index_to_comp_ids;
+  std::vector<uint32_t> uncC_index_to_comp_ids;

-  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(properties, tile_width, tile_height, context->get_security_limits());
+  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(properties, tile_width, tile_height, uncC_index_to_comp_ids, context->get_security_limits());
   if (!createImgResult) {
     return createImgResult.error();
   }

   img = *createImgResult;

-  auto decoderResult = unc_decoder_factory::get_unc_decoder(ispe->get_width(), ispe->get_height(), cmpd, uncC);
+  auto decoderResult = unc_decoder_factory::get_unc_decoder(ispe->get_width(), ispe->get_height(), cmpd, uncC, uncC_index_to_comp_ids);
   if (!decoderResult) {
     return decoderResult.error();
   }
diff --git a/libheif/codecs/uncompressed/unc_codec.h b/libheif/codecs/uncompressed/unc_codec.h
index 28ca6c60..9fea542b 100644
--- a/libheif/codecs/uncompressed/unc_codec.h
+++ b/libheif/codecs/uncompressed/unc_codec.h
@@ -86,6 +86,7 @@ public:
   static Result<std::shared_ptr<HeifPixelImage>> create_image(const unci_properties& properties,
                                                               uint32_t width,
                                                               uint32_t height,
+                                                              std::vector<uint32_t>& uncC_index_to_comp_ids,
                                                               const heif_security_limits* limits);

   static Error check_header_validity(std::optional<const std::shared_ptr<const Box_ispe>>,
diff --git a/libheif/codecs/uncompressed/unc_decoder.cc b/libheif/codecs/uncompressed/unc_decoder.cc
index 1d15eaa9..41f66668 100644
--- a/libheif/codecs/uncompressed/unc_decoder.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -43,11 +43,13 @@

 unc_decoder::unc_decoder(uint32_t width, uint32_t height,
                          const std::shared_ptr<const Box_cmpd>& cmpd,
-                         const std::shared_ptr<const Box_uncC>& uncC)
+                         const std::shared_ptr<const Box_uncC>& uncC,
+                         const std::vector<uint32_t>& uncC_index_to_comp_ids)
   : m_width(width),
     m_height(height),
     m_cmpd(cmpd),
-    m_uncC(uncC)
+    m_uncC(uncC),
+    m_uncC_index_to_comp_ids(uncC_index_to_comp_ids)
 {
   m_tile_height = m_height / m_uncC->get_number_of_tile_rows();
   m_tile_width = m_width / m_uncC->get_number_of_tile_columns();
@@ -410,7 +412,9 @@ Error check_hard_limits(const std::shared_ptr<const Box_uncC>& uncC)
 Result<std::unique_ptr<unc_decoder> > unc_decoder_factory::get_unc_decoder(
   uint32_t width, uint32_t height,
   const std::shared_ptr<const Box_cmpd>& cmpd,
-  const std::shared_ptr<const Box_uncC>& uncC)
+  const std::shared_ptr<const Box_uncC>& uncC,
+  const std::vector<uint32_t>& uncC_index_to_comp_ids
+)
 {
   static unc_decoder_factory_component_interleave dec_component;
   static unc_decoder_factory_bytealign_component_interleave dec_bytealign_component;
@@ -426,7 +430,7 @@ Result<std::unique_ptr<unc_decoder> > unc_decoder_factory::get_unc_decoder(

   for (const unc_decoder_factory* dec : decoders) {
     if (dec->can_decode(uncC)) {
-      return {dec->create(width, height, cmpd, uncC)};
+      return {dec->create(width, height, cmpd, uncC, uncC_index_to_comp_ids)};
     }
   }

@@ -456,7 +460,9 @@ Result<std::shared_ptr<HeifPixelImage> > unc_decoder::decode_full_image(
     return {global_limit_error};
   }

-  Result<std::shared_ptr<HeifPixelImage> > createImgResult = UncompressedImageCodec::create_image(properties, width, height, limits);
+  std::vector<uint32_t> uncC_index_to_comp_ids;
+
+  Result<std::shared_ptr<HeifPixelImage> > createImgResult = UncompressedImageCodec::create_image(properties, width, height, uncC_index_to_comp_ids, limits);
   if (!createImgResult) {
     return createImgResult.error();
   }
@@ -464,7 +470,7 @@ Result<std::shared_ptr<HeifPixelImage> > unc_decoder::decode_full_image(
   auto img = *createImgResult;


-  auto decoderResult = unc_decoder_factory::get_unc_decoder(width, height, cmpd, uncC);
+  auto decoderResult = unc_decoder_factory::get_unc_decoder(width, height, cmpd, uncC, uncC_index_to_comp_ids);
   if (!decoderResult) {
     return decoderResult.error();
   }
diff --git a/libheif/codecs/uncompressed/unc_decoder.h b/libheif/codecs/uncompressed/unc_decoder.h
index 3106c6ba..75d19efe 100644
--- a/libheif/codecs/uncompressed/unc_decoder.h
+++ b/libheif/codecs/uncompressed/unc_decoder.h
@@ -62,7 +62,8 @@ public:
 protected:
   unc_decoder(uint32_t width, uint32_t height,
               const std::shared_ptr<const Box_cmpd>& cmpd,
-              const std::shared_ptr<const Box_uncC>& uncC);
+              const std::shared_ptr<const Box_uncC>& uncC,
+              const std::vector<uint32_t>& uncC_index_to_comp_ids);

   virtual std::vector<uint64_t> get_tile_data_sizes() const = 0;

@@ -80,6 +81,7 @@ protected:
   const uint32_t m_height;
   const std::shared_ptr<const Box_cmpd> m_cmpd;
   const std::shared_ptr<const Box_uncC> m_uncC;
+  const std::vector<uint32_t> m_uncC_index_to_comp_ids;
   uint32_t m_tile_height;
   uint32_t m_tile_width;
 };
@@ -93,7 +95,8 @@ public:
   static Result<std::unique_ptr<unc_decoder>> get_unc_decoder(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC);
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids);

 protected:
   static bool check_common_requirements(const std::shared_ptr<const Box_uncC>& uncC);
@@ -105,7 +108,8 @@ protected:
   virtual std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const = 0;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const = 0;
 };

 #endif
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
index 625df8fd..8cf2525d 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.cc
@@ -33,8 +33,9 @@
 unc_decoder_block_component_interleave::unc_decoder_block_component_interleave(
     uint32_t width, uint32_t height,
     std::shared_ptr<const Box_cmpd> cmpd,
-    std::shared_ptr<const Box_uncC> uncC)
-    : unc_decoder(width, height, cmpd, uncC)
+    std::shared_ptr<const Box_uncC> uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids)
+    : unc_decoder(width, height, cmpd, uncC, uncC_index_to_comp_ids)
 {
 }

@@ -96,6 +97,10 @@ Error unc_decoder_block_component_interleave::decode_tile(const std::vector<uint
       comp[i].shift = 0;
     }

+    comp[i].dst_plane = img->get_component(m_uncC_index_to_comp_ids[i], &comp[i].dst_plane_stride);
+    comp[i].use = true;
+
+#if 0
     heif_channel channel;
     comp[i].use = map_uncompressed_component_to_channel(m_cmpd, c, &channel);
     if (comp[i].use) {
@@ -105,6 +110,7 @@ Error unc_decoder_block_component_interleave::decode_tile(const std::vector<uint
       comp[i].dst_plane = nullptr;
       comp[i].dst_plane_stride = 0;
     }
+#endif
   }

   const uint8_t* src = tile_data.data();
@@ -222,7 +228,8 @@ bool unc_decoder_factory_block_component_interleave::can_decode(const std::share
 std::unique_ptr<unc_decoder> unc_decoder_factory_block_component_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_block_component_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_block_component_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
index 597f1d74..a040413d 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_block_component_interleave.h
@@ -31,7 +31,8 @@ class unc_decoder_block_component_interleave : public unc_decoder
 public:
   unc_decoder_block_component_interleave(uint32_t width, uint32_t height,
                                           std::shared_ptr<const Box_cmpd> cmpd,
-                                          std::shared_ptr<const Box_uncC> uncC);
+                                          std::shared_ptr<const Box_uncC> uncC,
+                                          const std::vector<uint32_t>& uncC_index_to_comp_ids);

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -49,7 +50,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_BLOCK_COMPONENT_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
index 848b6186..9e75f6f1 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.cc
@@ -33,8 +33,9 @@
 unc_decoder_block_pixel_interleave::unc_decoder_block_pixel_interleave(
     uint32_t width, uint32_t height,
     std::shared_ptr<const Box_cmpd> cmpd,
-    std::shared_ptr<const Box_uncC> uncC)
-    : unc_decoder(width, height, cmpd, uncC)
+    std::shared_ptr<const Box_uncC> uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids)
+    : unc_decoder(width, height, cmpd, uncC, uncC_index_to_comp_ids)
 {
 }

@@ -88,7 +89,7 @@ Error unc_decoder_block_pixel_interleave::decode_tile(const std::vector<uint8_t>
     const auto& c = components[i];
     comp[i].bytes_per_sample = (c.component_bit_depth + 7) / 8;
     comp[i].mask = (uint64_t{1} << c.component_bit_depth) - 1;
-
+#if 0
     heif_channel channel;
     comp[i].use = map_uncompressed_component_to_channel(m_cmpd, c, &channel);
     if (comp[i].use) {
@@ -98,6 +99,9 @@ Error unc_decoder_block_pixel_interleave::decode_tile(const std::vector<uint8_t>
       comp[i].dst_plane = nullptr;
       comp[i].dst_plane_stride = 0;
     }
+#endif
+    comp[i].use = true;
+    comp[i].dst_plane = img->get_component(m_uncC_index_to_comp_ids[i], &comp[i].dst_plane_stride);
   }

   // Compute bit shifts within the block.
@@ -228,7 +232,8 @@ bool unc_decoder_factory_block_pixel_interleave::can_decode(const std::shared_pt
 std::unique_ptr<unc_decoder> unc_decoder_factory_block_pixel_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_block_pixel_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_block_pixel_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
index a9dfe6b9..122160db 100644
--- a/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_block_pixel_interleave.h
@@ -31,7 +31,8 @@ class unc_decoder_block_pixel_interleave : public unc_decoder
 public:
   unc_decoder_block_pixel_interleave(uint32_t width, uint32_t height,
                                      std::shared_ptr<const Box_cmpd> cmpd,
-                                     std::shared_ptr<const Box_uncC> uncC);
+                                     std::shared_ptr<const Box_uncC> uncC,
+                                     const std::vector<uint32_t>& uncC_index_to_comp_ids);

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -49,7 +50,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_BLOCK_PIXEL_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
index 77f67ba2..098142fb 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
@@ -33,8 +33,9 @@
 unc_decoder_bytealign_component_interleave::unc_decoder_bytealign_component_interleave(
     uint32_t width, uint32_t height,
     std::shared_ptr<const Box_cmpd> cmpd,
-    std::shared_ptr<const Box_uncC> uncC)
-    : unc_decoder(width, height, cmpd, uncC)
+    std::shared_ptr<const Box_uncC> uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids)
+    : unc_decoder(width, height, cmpd, uncC, uncC_index_to_comp_ids)
 {
 }

@@ -85,6 +86,7 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
     comp[i].bytes_per_sample = (c.component_bit_depth + 7) / 8;

     comp[i].use = true; // map_uncompressed_component_to_channel(m_cmpd, c, &channel);
+#if 0
     if (comp[i].use) {
       comp[i].dst_plane = img->get_component(c.component_index, &comp[i].dst_plane_stride);
       assert(comp[i].dst_plane != nullptr);
@@ -93,6 +95,9 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
       comp[i].dst_plane = nullptr;
       comp[i].dst_plane_stride = 0;
     }
+#endif
+
+    comp[i].dst_plane = img->get_component(m_uncC_index_to_comp_ids[i], &comp[i].dst_plane_stride);
   }

   const uint8_t* src = tile_data.data();
@@ -273,7 +278,8 @@ bool unc_decoder_factory_bytealign_component_interleave::can_decode(const std::s
 std::unique_ptr<unc_decoder> unc_decoder_factory_bytealign_component_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_bytealign_component_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_bytealign_component_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
index 4a2326ab..c52b9f2b 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.h
@@ -31,7 +31,8 @@ class unc_decoder_bytealign_component_interleave : public unc_decoder
 public:
   unc_decoder_bytealign_component_interleave(uint32_t width, uint32_t height,
                                               std::shared_ptr<const Box_cmpd> cmpd,
-                                              std::shared_ptr<const Box_uncC> uncC);
+                                              std::shared_ptr<const Box_uncC> uncC,
+                                              const std::vector<uint32_t>& uncC_index_to_comp_ids);

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -49,7 +50,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_BYTEALIGN_COMPONENT_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
index e57c0714..d94f6bdb 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.cc
@@ -168,7 +168,8 @@ bool unc_decoder_factory_component_interleave::can_decode(const std::shared_ptr<
 std::unique_ptr<unc_decoder> unc_decoder_factory_component_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_component_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_component_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
index c32ab6ea..731e261c 100644
--- a/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_component_interleave.h
@@ -32,8 +32,9 @@ class unc_decoder_component_interleave : public unc_decoder_legacybase
 public:
   unc_decoder_component_interleave(uint32_t width, uint32_t height,
                                     std::shared_ptr<const Box_cmpd> cmpd,
-                                    std::shared_ptr<const Box_uncC> uncC) :
-      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
+                                    std::shared_ptr<const Box_uncC> uncC,
+                                    const std::vector<uint32_t>& uncC_index_to_comp_ids) :
+      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -51,7 +52,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_COMPONENT_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_legacybase.cc b/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
index af706ae5..99920685 100644
--- a/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_legacybase.cc
@@ -44,8 +44,9 @@

 unc_decoder_legacybase::unc_decoder_legacybase(uint32_t width, uint32_t height,
                                                const std::shared_ptr<const Box_cmpd>& cmpd,
-                                               const std::shared_ptr<const Box_uncC>& uncC)
-    : unc_decoder(width, height, cmpd, uncC)
+                                               const std::shared_ptr<const Box_uncC>& uncC,
+                                               const std::vector<uint32_t>& uncC_index_to_comp_ids)
+    : unc_decoder(width, height, cmpd, uncC, uncC_index_to_comp_ids)
 {
 }

@@ -58,9 +59,11 @@ void unc_decoder_legacybase::ensureChannelList(std::shared_ptr<HeifPixelImage>&

 void unc_decoder_legacybase::buildChannelList(std::shared_ptr<HeifPixelImage>& img)
 {
+  uint32_t uncC_index = 0;
   for (Box_uncC::Component component : m_uncC->get_components()) {
-    ChannelListEntry entry = buildChannelListEntry(component.component_index, component, img);
+    ChannelListEntry entry = buildChannelListEntry(uncC_index, component, img);
     channelList.push_back(entry);
+    uncC_index++;
   }
 }

@@ -134,13 +137,13 @@ void unc_decoder_legacybase::processComponentTileRow(ChannelListEntry& entry, Un
 }


-unc_decoder_legacybase::ChannelListEntry unc_decoder_legacybase::buildChannelListEntry(uint32_t component_idx,
+unc_decoder_legacybase::ChannelListEntry unc_decoder_legacybase::buildChannelListEntry(uint32_t component_id,
                                                                                         Box_uncC::Component component,
                                                                                         std::shared_ptr<HeifPixelImage>& img)
 {
   ChannelListEntry entry;
   entry.use_channel = map_uncompressed_component_to_channel(m_cmpd, component, &(entry.channel));
-  entry.dst_plane = img->get_component(component_idx, &(entry.dst_plane_stride));
+  entry.dst_plane = img->get_component(m_uncC_index_to_comp_ids[component_id], &(entry.dst_plane_stride));
   entry.tile_width = m_tile_width;
   entry.tile_height = m_tile_height;
   entry.other_chroma_dst_plane_stride = 0; // will be overwritten below if used
diff --git a/libheif/codecs/uncompressed/unc_decoder_legacybase.h b/libheif/codecs/uncompressed/unc_decoder_legacybase.h
index 79b93fcc..a6ffd9ea 100644
--- a/libheif/codecs/uncompressed/unc_decoder_legacybase.h
+++ b/libheif/codecs/uncompressed/unc_decoder_legacybase.h
@@ -142,7 +142,8 @@ public:
 protected:
   unc_decoder_legacybase(uint32_t width, uint32_t height,
                          const std::shared_ptr<const Box_cmpd>& cmpd,
-                         const std::shared_ptr<const Box_uncC>& uncC);
+                         const std::shared_ptr<const Box_uncC>& uncC,
+                         const std::vector<uint32_t>& uncC_index_to_comp_ids);

   class ChannelListEntry
   {
diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
index bcb67501..f21199fe 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.cc
@@ -154,7 +154,8 @@ bool unc_decoder_factory_mixed_interleave::can_decode(const std::shared_ptr<cons
 std::unique_ptr<unc_decoder> unc_decoder_factory_mixed_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_mixed_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_mixed_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
index 2f37c859..4e441401 100644
--- a/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_mixed_interleave.h
@@ -30,8 +30,8 @@
 class unc_decoder_mixed_interleave : public unc_decoder_legacybase
 {
 public:
-  unc_decoder_mixed_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_mixed_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC, const std::vector<uint32_t>& uncC_index_to_comp_ids) :
+      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -51,7 +51,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_MIXED_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
index 79886e7c..de7169d6 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.cc
@@ -133,7 +133,8 @@ bool unc_decoder_factory_pixel_interleave::can_decode(const std::shared_ptr<cons
 std::unique_ptr<unc_decoder> unc_decoder_factory_pixel_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_pixel_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_pixel_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
index bee123fa..45aa55ae 100644
--- a/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_pixel_interleave.h
@@ -30,8 +30,8 @@
 class unc_decoder_pixel_interleave : public unc_decoder_legacybase
 {
 public:
-  unc_decoder_pixel_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
+  unc_decoder_pixel_interleave(uint32_t width, uint32_t height, std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC, const std::vector<uint32_t>& uncC_index_to_comp_ids) :
+      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}

   std::vector<uint64_t> get_tile_data_sizes() const override;

@@ -51,7 +51,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_PIXEL_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
index f90603c9..e8dc47c9 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.cc
@@ -124,7 +124,8 @@ bool unc_decoder_factory_row_interleave::can_decode(const std::shared_ptr<const
 std::unique_ptr<unc_decoder> unc_decoder_factory_row_interleave::create(
     uint32_t width, uint32_t height,
     const std::shared_ptr<const Box_cmpd>& cmpd,
-    const std::shared_ptr<const Box_uncC>& uncC) const
+    const std::shared_ptr<const Box_uncC>& uncC,
+    const std::vector<uint32_t>& uncC_index_to_comp_ids) const
 {
-  return std::make_unique<unc_decoder_row_interleave>(width, height, cmpd, uncC);
+  return std::make_unique<unc_decoder_row_interleave>(width, height, cmpd, uncC, uncC_index_to_comp_ids);
 }
diff --git a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
index 90d111b6..6c028e83 100644
--- a/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
+++ b/libheif/codecs/uncompressed/unc_decoder_row_interleave.h
@@ -31,8 +31,8 @@ class unc_decoder_row_interleave : public unc_decoder_legacybase
 {
 public:
   unc_decoder_row_interleave(uint32_t width, uint32_t height,
-                              std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC) :
-      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC)) {}
+                              std::shared_ptr<const Box_cmpd> cmpd, std::shared_ptr<const Box_uncC> uncC, const std::vector<uint32_t>& uncC_index_to_comp_ids) :
+      unc_decoder_legacybase(width, height, std::move(cmpd), std::move(uncC), uncC_index_to_comp_ids) {}


   std::vector<uint64_t> get_tile_data_sizes() const override;
@@ -54,7 +54,8 @@ private:
   std::unique_ptr<unc_decoder> create(
       uint32_t width, uint32_t height,
       const std::shared_ptr<const Box_cmpd>& cmpd,
-      const std::shared_ptr<const Box_uncC>& uncC) const override;
+      const std::shared_ptr<const Box_uncC>& uncC,
+      const std::vector<uint32_t>& uncC_index_to_comp_ids) const override;
 };

 #endif // LIBHEIF_UNC_DECODER_ROW_INTERLEAVE_H
diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
index a161492b..f8027f5a 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
@@ -37,17 +37,17 @@ bool unc_encoder_factory_component_interleave::can_encode(const std::shared_ptr<
   // If any component is not byte-aligned, we use the bit-packing path which
   // reads samples as uint32_t, limiting all components to 32 bpp.
   bool any_non_aligned = false;
-  uint32_t num_components = image->get_number_of_used_components();
-  for (uint32_t idx = 0; idx < num_components; idx++) {
-    uint16_t bpp = image->get_component_bits_per_pixel(idx);
+  auto component_ids = image->get_used_component_ids();
+  for (uint32_t id : component_ids) {
+    uint16_t bpp = image->get_component_bits_per_pixel(id);
     if (bpp % 8 != 0) {
       any_non_aligned = true;
     }
   }

   if (any_non_aligned) {
-    for (uint32_t idx = 0; idx < num_components; idx++) {
-      if (image->get_component_bits_per_pixel(idx) > 32) {
+    for (uint32_t id : component_ids) {
+      if (image->get_component_bits_per_pixel(id) > 32) {
         return false;
       }
     }
@@ -55,8 +55,8 @@ bool unc_encoder_factory_component_interleave::can_encode(const std::shared_ptr<

   if (!any_non_aligned) {
     // All components are byte-aligned. Only accept typical integer widths.
-    for (uint32_t idx = 0; idx < num_components; idx++) {
-      uint16_t bpp = image->get_component_bits_per_pixel(idx);
+    for (uint32_t id : component_ids) {
+      uint16_t bpp = image->get_component_bits_per_pixel(id);
       switch (bpp) {
         case 8:
         case 16:
@@ -87,17 +87,19 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
     : unc_encoder(image)
 {
   bool is_nonvisual = (image->get_colorspace() == heif_colorspace_nonvisual);
-  uint32_t num_components = image->get_number_of_used_components();
+  //uint32_t num_components = image->get_number_of_used_components();

-  for (uint32_t idx = 0; idx < num_components; idx++) {
+  auto componentIds = image->get_used_planar_component_ids();
+
+  for (uint32_t id : componentIds) {
     heif_unci_component_type comp_type;
     heif_channel ch = heif_channel_Y; // default for nonvisual

     if (is_nonvisual) {
-      comp_type = static_cast<heif_unci_component_type>(image->get_component_type(idx));
+      comp_type = static_cast<heif_unci_component_type>(image->get_component_type(id));
     }
     else {
-      ch = image->get_component_channel(idx);
+      ch = image->get_component_channel(id);
       if (ch == heif_channel_Y && !image->has_channel(heif_channel_Cb)) {
         comp_type = heif_unci_component_type_monochrome;
       }
@@ -106,11 +108,11 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
       }
     }

-    uint16_t bpp = image->get_component_bits_per_pixel(idx);
-    auto comp_format = to_unc_component_format(image->get_component_datatype(idx));
+    uint16_t bpp = image->get_component_bits_per_pixel(id);
+    auto comp_format = to_unc_component_format(image->get_component_datatype(id));
     bool aligned = (bpp % 8 == 0);

-    m_components.push_back({idx, ch, comp_type, comp_format, bpp, aligned});
+    m_components.push_back({id, ch, comp_type, comp_format, bpp, aligned});
   }

   // Build cmpd/uncC boxes
diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index 55c5e4f5..485780fc 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -2383,6 +2383,20 @@ std::vector<uint32_t> HeifPixelImage::get_used_component_ids() const
 }


+std::vector<uint32_t> HeifPixelImage::get_used_planar_component_ids() const
+{
+  std::vector<uint32_t> indices;
+
+  for (const auto& plane : m_planes) {
+    if (plane.m_component_ids.size() == 1) {
+      indices.push_back(plane.m_component_ids[0]);
+    }
+  }
+
+  return indices;
+}
+
+
 uint8_t* HeifPixelImage::get_component(uint32_t component_idx, size_t* out_stride)
 {
   return get_component_data<uint8_t>(component_idx, out_stride);
diff --git a/libheif/pixelimage.h b/libheif/pixelimage.h
index c19dd8af..75e2df95 100644
--- a/libheif/pixelimage.h
+++ b/libheif/pixelimage.h
@@ -501,6 +501,8 @@ public:
   // Returns the sorted list of component_indices of all planes that have pixel data.
   std::vector<uint32_t> get_used_component_ids() const;

+  std::vector<uint32_t> get_used_planar_component_ids() 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;