Commit 72672c1c for libheif

commit 72672c1cb3c059158eaa663661a967d52f2a75ee
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Sat Apr 4 03:10:09 2026 +0200

    unci: refactor to opaque component ids (wip)

diff --git a/examples/heif_gen_bayer.cc b/examples/heif_gen_bayer.cc
index c59f1b81..f07265b2 100644
--- a/examples/heif_gen_bayer.cc
+++ b/examples/heif_gen_bayer.cc
@@ -50,7 +50,7 @@ struct PatternDefinition
   std::string name;
   uint16_t width;
   uint16_t height;
-  std::vector<heif_uncompressed_component_type> cpat;
+  std::vector<heif_unci_component_type> cpat;
 };


@@ -61,10 +61,10 @@ static const PatternDefinition patterns[] = {
   {
     "rggb", 2, 2,
     {
-      heif_uncompressed_component_type_red,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_blue,
+      heif_unci_component_type_red,
+      heif_unci_component_type_green,
+      heif_unci_component_type_green,
+      heif_unci_component_type_blue,
     }
   },

@@ -77,25 +77,25 @@ static const PatternDefinition patterns[] = {
   {
     "rgbw", 4, 4,
     {
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_red,
-
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_Y,
-
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_green,
-
-      heif_uncompressed_component_type_red,
-      heif_uncompressed_component_type_Y,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_Y,
+      heif_unci_component_type_Y,
+      heif_unci_component_type_green,
+      heif_unci_component_type_Y,
+      heif_unci_component_type_red,
+
+      heif_unci_component_type_green,
+      heif_unci_component_type_Y,
+      heif_unci_component_type_blue,
+      heif_unci_component_type_Y,
+
+      heif_unci_component_type_Y,
+      heif_unci_component_type_blue,
+      heif_unci_component_type_Y,
+      heif_unci_component_type_green,
+
+      heif_unci_component_type_red,
+      heif_unci_component_type_Y,
+      heif_unci_component_type_green,
+      heif_unci_component_type_Y,
     }
   },

@@ -107,25 +107,25 @@ static const PatternDefinition patterns[] = {
   {
     "qbc", 4, 4,
     {
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_red,
-      heif_uncompressed_component_type_red,
-
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_red,
-      heif_uncompressed_component_type_red,
-
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_green,
-
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_blue,
-      heif_uncompressed_component_type_green,
-      heif_uncompressed_component_type_green,
+      heif_unci_component_type_green,
+      heif_unci_component_type_green,
+      heif_unci_component_type_red,
+      heif_unci_component_type_red,
+
+      heif_unci_component_type_green,
+      heif_unci_component_type_green,
+      heif_unci_component_type_red,
+      heif_unci_component_type_red,
+
+      heif_unci_component_type_blue,
+      heif_unci_component_type_blue,
+      heif_unci_component_type_green,
+      heif_unci_component_type_green,
+
+      heif_unci_component_type_blue,
+      heif_unci_component_type_blue,
+      heif_unci_component_type_green,
+      heif_unci_component_type_green,
     }
   },
 };
@@ -153,14 +153,14 @@ static std::optional<PatternDefinition> parse_pattern_string(const char* str)
   }

   uint16_t dim = (len == 4) ? 2 : 4;
-  std::vector<heif_uncompressed_component_type> cpat;
+  std::vector<heif_unci_component_type> cpat;
   cpat.reserve(len);

   for (char c : s) {
     switch (std::tolower(c)) {
-      case 'r': cpat.push_back(heif_uncompressed_component_type_red); break;
-      case 'g': cpat.push_back(heif_uncompressed_component_type_green); break;
-      case 'b': cpat.push_back(heif_uncompressed_component_type_blue); break;
+      case 'r': cpat.push_back(heif_unci_component_type_red); break;
+      case 'g': cpat.push_back(heif_unci_component_type_green); break;
+      case 'b': cpat.push_back(heif_unci_component_type_blue); break;
       default: return {};
     }
   }
@@ -309,7 +309,9 @@ static heif_image* create_bayer_image_from_png(const char* png_filename,
     return nullptr;
   }

-  err = heif_image_add_plane(bayer_img, heif_channel_filter_array, width, height, output_bit_depth);
+  uint32_t filter_array_component_id;
+
+  err = heif_image_add_component(bayer_img, width, height, heif_unci_component_type_filter_array, heif_component_datatype_unsigned_integer, output_bit_depth, &filter_array_component_id);
   if (err.code != heif_error_Ok) {
     std::cerr << "Cannot add plane: " << err.message << "\n";
     heif_image_release(bayer_img);
@@ -335,10 +337,10 @@ static heif_image* create_bayer_image_from_png(const char* png_filename,
         auto comp_type = pat->cpat[py * pat->width + px];

         switch (comp_type) {
-          case heif_uncompressed_component_type_red:   dst_row[x] = r; break;
-          case heif_uncompressed_component_type_green: dst_row[x] = g; break;
-          case heif_uncompressed_component_type_blue:  dst_row[x] = b; break;
-          case heif_uncompressed_component_type_Y: dst_row[x] = static_cast<uint8_t>((r + g + b) / 3); break;
+          case heif_unci_component_type_red:   dst_row[x] = r; break;
+          case heif_unci_component_type_green: dst_row[x] = g; break;
+          case heif_unci_component_type_blue:  dst_row[x] = b; break;
+          case heif_unci_component_type_Y: dst_row[x] = static_cast<uint8_t>((r + g + b) / 3); break;
           default:
             assert(false);
         }
@@ -366,10 +368,10 @@ static heif_image* create_bayer_image_from_png(const char* png_filename,
         auto comp_type = pat->cpat[py * pat->width + px];

         switch (comp_type) {
-          case heif_uncompressed_component_type_red:   dst_row[x] = r; break;
-          case heif_uncompressed_component_type_green: dst_row[x] = g; break;
-          case heif_uncompressed_component_type_blue:  dst_row[x] = b; break;
-          case heif_uncompressed_component_type_Y: dst_row[x] = static_cast<uint16_t>((r + g + b) / 3); break;
+          case heif_unci_component_type_red:   dst_row[x] = r; break;
+          case heif_unci_component_type_green: dst_row[x] = g; break;
+          case heif_unci_component_type_blue:  dst_row[x] = b; break;
+          case heif_unci_component_type_Y: dst_row[x] = static_cast<uint16_t>((r + g + b) / 3); break;
           default:
             assert(false);
         }
@@ -377,17 +379,30 @@ static heif_image* create_bayer_image_from_png(const char* png_filename,
     }
   }

+  // map component type to component id
+
+  std::map<uint16_t, uint32_t> map_type_to_id;
+  for (const auto& type : pat->cpat) {
+    if (map_type_to_id.find(type) == map_type_to_id.end()) {
+      uint32_t component_id;
+      heif_image_add_bayer_component(bayer_img, type, &component_id);
+
+      map_type_to_id[type] = component_id;
+    }
+  }
+
   // Build heif_bayer_pattern_pixel array from component types.
   // The component_index values here are the component types themselves — the encoder
   // will resolve them to proper cmpd indices when writing the cpat box.
   std::vector<heif_bayer_pattern_pixel> bayer_pixels(pat->cpat.size());
   for (size_t i = 0; i < pat->cpat.size(); i++) {
-    bayer_pixels[i].component_index = static_cast<uint16_t>(pat->cpat[i]);
+    bayer_pixels[i].component_id = map_type_to_id[pat->cpat[i]];
     bayer_pixels[i].component_gain = 1.0f;
   }

   // Set Bayer pattern metadata
   err = heif_image_set_bayer_pattern(bayer_img,
+                                     filter_array_component_id,
                                      pat->width, pat->height,
                                      bayer_pixels.data());
   if (err.code != heif_error_Ok) {
diff --git a/heifio/decoder_raw.cc b/heifio/decoder_raw.cc
index 4ee0cce4..a17ed8e0 100644
--- a/heifio/decoder_raw.cc
+++ b/heifio/decoder_raw.cc
@@ -38,39 +38,39 @@ static struct heif_error heif_error_ok = {heif_error_Ok, heif_suberror_Unspecifi


 bool parse_raw_pixel_type(const std::string& type_string,
-                          heif_channel_datatype* out_datatype,
+                          heif_component_datatype* out_datatype,
                           int* out_bit_depth)
 {
   if (type_string == "uint8") {
-    *out_datatype = heif_channel_datatype_unsigned_integer;
+    *out_datatype = heif_component_datatype_unsigned_integer;
     *out_bit_depth = 8;
   }
   else if (type_string == "sint8") {
-    *out_datatype = heif_channel_datatype_signed_integer;
+    *out_datatype = heif_component_datatype_signed_integer;
     *out_bit_depth = 8;
   }
   else if (type_string == "uint16") {
-    *out_datatype = heif_channel_datatype_unsigned_integer;
+    *out_datatype = heif_component_datatype_unsigned_integer;
     *out_bit_depth = 16;
   }
   else if (type_string == "sint16") {
-    *out_datatype = heif_channel_datatype_signed_integer;
+    *out_datatype = heif_component_datatype_signed_integer;
     *out_bit_depth = 16;
   }
   else if (type_string == "uint32") {
-    *out_datatype = heif_channel_datatype_unsigned_integer;
+    *out_datatype = heif_component_datatype_unsigned_integer;
     *out_bit_depth = 32;
   }
   else if (type_string == "sint32") {
-    *out_datatype = heif_channel_datatype_signed_integer;
+    *out_datatype = heif_component_datatype_signed_integer;
     *out_bit_depth = 32;
   }
   else if (type_string == "float32") {
-    *out_datatype = heif_channel_datatype_floating_point;
+    *out_datatype = heif_component_datatype_floating_point;
     *out_bit_depth = 32;
   }
   else if (type_string == "float64") {
-    *out_datatype = heif_channel_datatype_floating_point;
+    *out_datatype = heif_component_datatype_floating_point;
     *out_bit_depth = 64;
   }
   else {
@@ -103,7 +103,7 @@ heif_error loadRAW(const char* filename, const RawImageParameters& params, Input
             "At least one of --raw-width or --raw-height must be specified"};
   }

-  if (params.datatype == heif_channel_datatype_undefined || params.bit_depth <= 0) {
+  if (params.datatype == heif_component_datatype_undefined || params.bit_depth <= 0) {
     return {heif_error_Invalid_input, heif_suberror_Unspecified,
             "Raw image pixel type must be specified (use --raw-type)"};
   }
@@ -187,7 +187,7 @@ heif_error loadRAW(const char* filename, const RawImageParameters& params, Input

   uint32_t component_idx = 0;
   err = heif_image_add_component(image, width, height,
-                                 heif_uncompressed_component_type_monochrome,
+                                 heif_unci_component_type_monochrome,
                                  params.datatype, params.bit_depth,
                                  &component_idx);
   if (err.code != heif_error_Ok) {
diff --git a/heifio/decoder_raw.h b/heifio/decoder_raw.h
index b272e67d..1f856757 100644
--- a/heifio/decoder_raw.h
+++ b/heifio/decoder_raw.h
@@ -34,7 +34,7 @@
 struct RawImageParameters {
   int width = 0;
   int height = 0;
-  heif_channel_datatype datatype = heif_channel_datatype_undefined;
+  heif_component_datatype datatype = heif_component_datatype_undefined;
   int bit_depth = 0;
   bool big_endian = false;
 };
@@ -42,7 +42,7 @@ struct RawImageParameters {
 // Maps a CLI string like "uint16" or "float32" to datatype + bit_depth.
 // Returns false if the string is not recognized.
 bool parse_raw_pixel_type(const std::string& type_string,
-                          heif_channel_datatype* out_datatype,
+                          heif_component_datatype* out_datatype,
                           int* out_bit_depth);

 LIBHEIF_API
diff --git a/heifio/decoder_tiff.cc b/heifio/decoder_tiff.cc
index baea6103..980371e5 100644
--- a/heifio/decoder_tiff.cc
+++ b/heifio/decoder_tiff.cc
@@ -693,8 +693,8 @@ static heif_error readMonoFloat(TIFF* tif, heif_image** image)

   uint32_t component_idx;
   err = heif_image_add_component(*image, (int)width, (int)height,
-                                 heif_uncompressed_component_type_monochrome,
-                                 heif_channel_datatype_floating_point, 32, &component_idx);
+                                 heif_unci_component_type_monochrome,
+                                 heif_component_datatype_floating_point, 32, &component_idx);
   if (err.code != heif_error_Ok) {
     heif_image_release(*image);
     *image = nullptr;
@@ -740,8 +740,8 @@ static heif_error readMonoSignedInt(TIFF* tif, uint16_t bps, heif_image** image)

   uint32_t component_idx;
   err = heif_image_add_component(*image, (int)width, (int)height,
-                                 heif_uncompressed_component_type_monochrome,
-                                 heif_channel_datatype_signed_integer, bps, &component_idx);
+                                 heif_unci_component_type_monochrome,
+                                 heif_component_datatype_signed_integer, bps, &component_idx);
   if (err.code != heif_error_Ok) {
     heif_image_release(*image);
     *image = nullptr;
@@ -1031,8 +1031,8 @@ static heif_error readTiledContiguous(TIFF* tif, uint32_t width, uint32_t height

     uint32_t component_idx;
     err = heif_image_add_component(*out_image, (int)width, (int)height,
-                                   heif_uncompressed_component_type_monochrome,
-                                   heif_channel_datatype_floating_point, 32, &component_idx);
+                                   heif_unci_component_type_monochrome,
+                                   heif_component_datatype_floating_point, 32, &component_idx);
     if (err.code != heif_error_Ok) {
       heif_image_release(*out_image);
       *out_image = nullptr;
@@ -1091,8 +1091,8 @@ static heif_error readTiledContiguous(TIFF* tif, uint32_t width, uint32_t height

     uint32_t component_idx;
     err = heif_image_add_component(*out_image, (int)width, (int)height,
-                                   heif_uncompressed_component_type_monochrome,
-                                   heif_channel_datatype_signed_integer, bps, &component_idx);
+                                   heif_unci_component_type_monochrome,
+                                   heif_component_datatype_signed_integer, bps, &component_idx);
     if (err.code != heif_error_Ok) {
       heif_image_release(*out_image);
       *out_image = nullptr;
@@ -1637,8 +1637,8 @@ heif_error TiledTiffReader::readTile(uint32_t tx, uint32_t ty, int output_bit_de

     uint32_t component_idx;
     err = heif_image_add_component(*out_image, (int)actual_w, (int)actual_h,
-                                   heif_uncompressed_component_type_monochrome,
-                                   heif_channel_datatype_floating_point, 32, &component_idx);
+                                   heif_unci_component_type_monochrome,
+                                   heif_component_datatype_floating_point, 32, &component_idx);
     if (err.code != heif_error_Ok) {
       heif_image_release(*out_image);
       *out_image = nullptr;
@@ -1684,8 +1684,8 @@ heif_error TiledTiffReader::readTile(uint32_t tx, uint32_t ty, int output_bit_de

     uint32_t component_idx;
     err = heif_image_add_component(*out_image, (int)actual_w, (int)actual_h,
-                                   heif_uncompressed_component_type_monochrome,
-                                   heif_channel_datatype_signed_integer, m_bits_per_sample, &component_idx);
+                                   heif_unci_component_type_monochrome,
+                                   heif_component_datatype_signed_integer, m_bits_per_sample, &component_idx);
     if (err.code != heif_error_Ok) {
       heif_image_release(*out_image);
       *out_image = nullptr;
diff --git a/libheif/api/libheif/heif_uncompressed.cc b/libheif/api/libheif/heif_uncompressed.cc
index 22ea296b..152f5af8 100644
--- a/libheif/api/libheif/heif_uncompressed.cc
+++ b/libheif/api/libheif/heif_uncompressed.cc
@@ -31,6 +31,7 @@


 heif_error heif_image_set_bayer_pattern(heif_image* image,
+                                        uint32_t bayer_component_id,
                                         uint16_t pattern_width,
                                         uint16_t pattern_height,
                                         const struct heif_bayer_pattern_pixel* patternPixels)
@@ -58,11 +59,26 @@ heif_error heif_image_set_bayer_pattern(heif_image* image,
 }


+heif_error heif_image_add_bayer_component(heif_image* image,
+                                          uint16_t component_type,
+                                          uint32_t* out_component_id)
+{
+  if (image == nullptr || out_component_id == nullptr) {
+    return heif_error_null_pointer_argument;
+  }
+
+  *out_component_id = image->image->add_component_without_data(component_type);
+
+  return heif_error_success;
+}
+
+
 int heif_image_has_bayer_pattern(const heif_image* image,
+                                 uint32_t bayer_component_id,
                                  uint16_t* out_pattern_width,
                                  uint16_t* out_pattern_height)
 {
-  if (image == nullptr || !image->image->has_bayer_pattern()) {
+  if (image == nullptr || !image->image->has_bayer_pattern(bayer_component_id)) {
     if (out_pattern_width) {
       *out_pattern_width = 0;
     }
@@ -72,7 +88,7 @@ int heif_image_has_bayer_pattern(const heif_image* image,
     return 0;
   }

-  const BayerPattern& pattern = image->image->get_bayer_pattern();
+  const BayerPattern& pattern = image->image->get_bayer_pattern(bayer_component_id);

   if (out_pattern_width) {
     *out_pattern_width = pattern.pattern_width;
@@ -86,19 +102,20 @@ int heif_image_has_bayer_pattern(const heif_image* image,


 heif_error heif_image_get_bayer_pattern(const heif_image* image,
+                                        uint32_t bayer_component_id,
                                         struct heif_bayer_pattern_pixel* out_patternPixels)
 {
   if (image == nullptr || out_patternPixels == nullptr) {
     return heif_error_null_pointer_argument;
   }

-  if (!image->image->has_bayer_pattern()) {
+  if (!image->image->has_bayer_pattern(bayer_component_id)) {
     return {heif_error_Usage_error,
             heif_suberror_Invalid_parameter_value,
             "Image does not have a Bayer pattern."};
   }

-  const BayerPattern& pattern = image->image->get_bayer_pattern();
+  const BayerPattern& pattern = image->image->get_bayer_pattern(bayer_component_id);
   size_t num_pixels = size_t{pattern.pattern_width} * pattern.pattern_height;
   std::copy(pattern.pixels.begin(), pattern.pixels.begin() + num_pixels, out_patternPixels);

@@ -124,8 +141,8 @@ int heif_polarization_angle_is_no_filter(float angle)


 heif_error heif_image_add_polarization_pattern(heif_image* image,
-                                               uint32_t num_component_indices,
-                                               const uint32_t* component_indices,
+                                               uint32_t num_component_ids,
+                                               const uint32_t* component_ids,
                                                uint16_t pattern_width,
                                                uint16_t pattern_height,
                                                const float* polarization_angles)
@@ -134,7 +151,7 @@ heif_error heif_image_add_polarization_pattern(heif_image* image,
     return heif_error_null_pointer_argument;
   }

-  if (num_component_indices > 0 && component_indices == nullptr) {
+  if (num_component_ids > 0 && component_ids == nullptr) {
     return heif_error_null_pointer_argument;
   }

@@ -145,7 +162,7 @@ heif_error heif_image_add_polarization_pattern(heif_image* image,
   }

   PolarizationPattern pattern;
-  pattern.component_indices.assign(component_indices, component_indices + num_component_indices);
+  pattern.component_ids.assign(component_ids, component_ids + num_component_ids);
   pattern.pattern_width = pattern_width;
   pattern.pattern_height = pattern_height;

@@ -170,7 +187,7 @@ int heif_image_get_number_of_polarization_patterns(const heif_image* image)

 heif_error heif_image_get_polarization_pattern_info(const heif_image* image,
                                                     int pattern_index,
-                                                    uint32_t* out_num_component_indices,
+                                                    uint32_t* out_num_component_ids,
                                                     uint16_t* out_pattern_width,
                                                     uint16_t* out_pattern_height)
 {
@@ -186,8 +203,8 @@ heif_error heif_image_get_polarization_pattern_info(const heif_image* image,
   }

   const auto& p = patterns[pattern_index];
-  if (out_num_component_indices) {
-    *out_num_component_indices = static_cast<uint32_t>(p.component_indices.size());
+  if (out_num_component_ids) {
+    *out_num_component_ids = static_cast<uint32_t>(p.component_ids.size());
   }
   if (out_pattern_width) {
     *out_pattern_width = p.pattern_width;
@@ -202,7 +219,7 @@ heif_error heif_image_get_polarization_pattern_info(const heif_image* image,

 heif_error heif_image_get_polarization_pattern_data(const heif_image* image,
                                                     int pattern_index,
-                                                    uint32_t* out_component_indices,
+                                                    uint32_t* out_component_ids,
                                                     float* out_polarization_angles)
 {
   if (image == nullptr || out_polarization_angles == nullptr) {
@@ -218,8 +235,8 @@ heif_error heif_image_get_polarization_pattern_data(const heif_image* image,

   const auto& p = patterns[pattern_index];

-  if (out_component_indices && !p.component_indices.empty()) {
-    std::copy(p.component_indices.begin(), p.component_indices.end(), out_component_indices);
+  if (out_component_ids && !p.component_ids.empty()) {
+    std::copy(p.component_ids.begin(), p.component_ids.end(), out_component_ids);
   }

   size_t num_pixels = size_t{p.pattern_width} * p.pattern_height;
@@ -230,7 +247,7 @@ heif_error heif_image_get_polarization_pattern_data(const heif_image* image,


 int heif_image_get_polarization_pattern_index_for_component(const heif_image* image,
-                                                            uint32_t component_index)
+                                                            uint32_t component_id)
 {
   if (image == nullptr) {
     return -1;
@@ -239,12 +256,12 @@ int heif_image_get_polarization_pattern_index_for_component(const heif_image* im
   const auto& patterns = image->image->get_polarization_patterns();
   for (size_t i = 0; i < patterns.size(); i++) {
     const auto& p = patterns[i];
-    if (p.component_indices.empty()) {
+    if (p.component_ids.empty()) {
       // Empty component list means pattern applies to all components.
       return static_cast<int>(i);
     }
-    for (uint32_t idx : p.component_indices) {
-      if (idx == component_index) {
+    for (uint32_t idx : p.component_ids) {
+      if (idx == component_id) {
         return static_cast<int>(i);
       }
     }
@@ -255,8 +272,8 @@ int heif_image_get_polarization_pattern_index_for_component(const heif_image* im


 heif_error heif_image_add_sensor_bad_pixels_map(heif_image* image,
-                                                 uint32_t num_component_indices,
-                                                 const uint32_t* component_indices,
+                                                 uint32_t num_component_ids,
+                                                 const uint32_t* component_ids,
                                                  int correction_applied,
                                                  uint32_t num_bad_rows,
                                                  const uint32_t* bad_rows,
@@ -269,7 +286,7 @@ heif_error heif_image_add_sensor_bad_pixels_map(heif_image* image,
     return heif_error_null_pointer_argument;
   }

-  if (num_component_indices > 0 && component_indices == nullptr) {
+  if (num_component_ids > 0 && component_ids == nullptr) {
     return heif_error_null_pointer_argument;
   }

@@ -286,7 +303,7 @@ heif_error heif_image_add_sensor_bad_pixels_map(heif_image* image,
   }

   SensorBadPixelsMap map;
-  map.component_indices.assign(component_indices, component_indices + num_component_indices);
+  map.component_ids.assign(component_ids, component_ids + num_component_ids);
   map.correction_applied = (correction_applied != 0);

   map.bad_rows.assign(bad_rows, bad_rows + num_bad_rows);
@@ -316,7 +333,7 @@ int heif_image_get_number_of_sensor_bad_pixels_maps(const heif_image* image)

 heif_error heif_image_get_sensor_bad_pixels_map_info(const heif_image* image,
                                                       int map_index,
-                                                      uint32_t* out_num_component_indices,
+                                                      uint32_t* out_num_component_ids,
                                                       int* out_correction_applied,
                                                       uint32_t* out_num_bad_rows,
                                                       uint32_t* out_num_bad_columns,
@@ -334,8 +351,8 @@ heif_error heif_image_get_sensor_bad_pixels_map_info(const heif_image* image,
   }

   const auto& m = maps[map_index];
-  if (out_num_component_indices) {
-    *out_num_component_indices = static_cast<uint32_t>(m.component_indices.size());
+  if (out_num_component_ids) {
+    *out_num_component_ids = static_cast<uint32_t>(m.component_ids.size());
   }
   if (out_correction_applied) {
     *out_correction_applied = m.correction_applied ? 1 : 0;
@@ -356,7 +373,7 @@ heif_error heif_image_get_sensor_bad_pixels_map_info(const heif_image* image,

 heif_error heif_image_get_sensor_bad_pixels_map_data(const heif_image* image,
                                                       int map_index,
-                                                      uint32_t* out_component_indices,
+                                                      uint32_t* out_component_ids,
                                                       uint32_t* out_bad_rows,
                                                       uint32_t* out_bad_columns,
                                                       struct heif_bad_pixel* out_bad_pixels)
@@ -374,8 +391,8 @@ heif_error heif_image_get_sensor_bad_pixels_map_data(const heif_image* image,

   const auto& m = maps[map_index];

-  if (out_component_indices && !m.component_indices.empty()) {
-    std::copy(m.component_indices.begin(), m.component_indices.end(), out_component_indices);
+  if (out_component_ids && !m.component_ids.empty()) {
+    std::copy(m.component_ids.begin(), m.component_ids.end(), out_component_ids);
   }

   if (out_bad_rows && !m.bad_rows.empty()) {
@@ -398,8 +415,8 @@ heif_error heif_image_get_sensor_bad_pixels_map_data(const heif_image* image,


 heif_error heif_image_add_sensor_nuc(heif_image* image,
-                                      uint32_t num_component_indices,
-                                      const uint32_t* component_indices,
+                                      uint32_t num_component_ids,
+                                      const uint32_t* component_ids,
                                       int nuc_is_applied,
                                       uint32_t image_width,
                                       uint32_t image_height,
@@ -410,7 +427,7 @@ heif_error heif_image_add_sensor_nuc(heif_image* image,
     return heif_error_null_pointer_argument;
   }

-  if (num_component_indices > 0 && component_indices == nullptr) {
+  if (num_component_ids > 0 && component_ids == nullptr) {
     return heif_error_null_pointer_argument;
   }

@@ -421,7 +438,7 @@ heif_error heif_image_add_sensor_nuc(heif_image* image,
   }

   SensorNonUniformityCorrection nuc;
-  nuc.component_indices.assign(component_indices, component_indices + num_component_indices);
+  nuc.component_ids.assign(component_ids, component_ids + num_component_ids);
   nuc.nuc_is_applied = (nuc_is_applied != 0);
   nuc.image_width = image_width;
   nuc.image_height = image_height;
@@ -448,7 +465,7 @@ int heif_image_get_number_of_sensor_nucs(const heif_image* image)

 heif_error heif_image_get_sensor_nuc_info(const heif_image* image,
                                            int nuc_index,
-                                           uint32_t* out_num_component_indices,
+                                           uint32_t* out_num_component_ids,
                                            int* out_nuc_is_applied,
                                            uint32_t* out_image_width,
                                            uint32_t* out_image_height)
@@ -465,8 +482,8 @@ heif_error heif_image_get_sensor_nuc_info(const heif_image* image,
   }

   const auto& n = nucs[nuc_index];
-  if (out_num_component_indices) {
-    *out_num_component_indices = static_cast<uint32_t>(n.component_indices.size());
+  if (out_num_component_ids) {
+    *out_num_component_ids = static_cast<uint32_t>(n.component_ids.size());
   }
   if (out_nuc_is_applied) {
     *out_nuc_is_applied = n.nuc_is_applied ? 1 : 0;
@@ -484,7 +501,7 @@ heif_error heif_image_get_sensor_nuc_info(const heif_image* image,

 heif_error heif_image_get_sensor_nuc_data(const heif_image* image,
                                            int nuc_index,
-                                           uint32_t* out_component_indices,
+                                           uint32_t* out_component_ids,
                                            float* out_nuc_gains,
                                            float* out_nuc_offsets)
 {
@@ -501,8 +518,8 @@ heif_error heif_image_get_sensor_nuc_data(const heif_image* image,

   const auto& n = nucs[nuc_index];

-  if (out_component_indices && !n.component_indices.empty()) {
-    std::copy(n.component_indices.begin(), n.component_indices.end(), out_component_indices);
+  if (out_component_ids && !n.component_ids.empty()) {
+    std::copy(n.component_ids.begin(), n.component_ids.end(), out_component_ids);
   }

   size_t num_pixels = size_t{n.image_width} * n.image_height;
@@ -605,7 +622,7 @@ void heif_unci_image_parameters_release(heif_unci_image_parameters* params)
 }


-// --- index-based component access
+// --- id-based component access

 uint32_t heif_image_get_number_of_used_components(const heif_image* image)
 {
@@ -616,24 +633,15 @@ uint32_t heif_image_get_number_of_used_components(const heif_image* image)
 }


-uint32_t heif_image_get_total_number_of_cmpd_components(const heif_image* image)
-{
-  if (!image || !image->image) {
-    return 0;
-  }
-  return image->image->get_total_number_of_cmpd_components();
-}
-
-
-void heif_image_get_used_component_indices(const heif_image* image, uint32_t* out_component_indices)
+void heif_image_get_used_component_ids(const heif_image* image, uint32_t* out_component_ids)
 {
-  if (!image || !image->image || !out_component_indices) {
+  if (!image || !image->image || !out_component_ids) {
     return;
   }

-  auto indices = image->image->get_used_component_indices();
+  auto indices = image->image->get_used_component_ids();
   for (size_t i = 0; i < indices.size(); i++) {
-    out_component_indices[i] = indices[i];
+    out_component_ids[i] = indices[i];
   }
 }

@@ -686,7 +694,7 @@ uint16_t heif_image_get_component_type(const heif_image* image, uint32_t compone
 heif_error heif_image_add_component(heif_image* image,
                                     int width, int height,
                                     uint16_t component_type,
-                                    heif_channel_datatype datatype,
+                                    heif_component_datatype datatype,
                                     int bit_depth,
                                     uint32_t* out_component_idx)
 {
diff --git a/libheif/api/libheif/heif_uncompressed.h b/libheif/api/libheif/heif_uncompressed.h
index 966c5b59..a406ff26 100644
--- a/libheif/api/libheif/heif_uncompressed.h
+++ b/libheif/api/libheif/heif_uncompressed.h
@@ -46,24 +46,32 @@ extern "C" {
 // On the decoder path, they come directly from the cpat box.
 LIBHEIF_API
 heif_error heif_image_set_bayer_pattern(heif_image*,
+                                        uint32_t bayer_component_id,
                                         uint16_t pattern_width,
                                         uint16_t pattern_height,
                                         const heif_bayer_pattern_pixel* patternPixels);

+LIBHEIF_API
+heif_error heif_image_add_bayer_component(heif_image*,
+                                          uint16_t component_type,
+                                          uint32_t* out_component_id);
+
 // Returns whether the image has a Bayer / filter array pattern.
 // If the image has a pattern, out_pattern_width and out_pattern_height are set.
 // Either output pointer may be NULL if the caller does not need that value.
 LIBHEIF_API
-int heif_image_has_bayer_pattern(const heif_image*,
-                                 uint16_t* out_pattern_width,
-                                 uint16_t* out_pattern_height);
+int heif_image_get_bayer_pattern_size(const heif_image*,
+                                      uint32_t bayer_component_id,
+                                      uint16_t* out_pattern_width,
+                                      uint16_t* out_pattern_height);

 // Get the Bayer / filter array pattern pixels.
 // The caller must provide an array large enough for pattern_width * pattern_height entries
-// (use heif_image_has_bayer_pattern() to query the dimensions first).
+// (use heif_image_get_bayer_pattern_size() to query the dimensions first).
 // Returns heif_error_Ok on success, or an error if no pattern is set.
 LIBHEIF_API
 heif_error heif_image_get_bayer_pattern(const heif_image*,
+                                        uint32_t bayer_component_id,
                                         heif_bayer_pattern_pixel* out_patternPixels);

 // --- Polarization pattern (ISO 23001-17, Section 6.1.5)
@@ -283,14 +291,10 @@ heif_error heif_context_add_empty_unci_image(heif_context* ctx,
 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
-void heif_image_get_used_component_indices(const heif_image*, uint32_t* out_component_indices);
+void heif_image_get_used_component_ids(const heif_image*, uint32_t* out_component_ids);

 LIBHEIF_API
 enum heif_channel heif_image_get_component_channel(const heif_image*, uint32_t component_idx);
@@ -315,7 +319,7 @@ LIBHEIF_API
 heif_error heif_image_add_component(heif_image* image,
                                     int width, int height,
                                     uint16_t component_type,
-                                    heif_channel_datatype datatype,
+                                    heif_component_datatype datatype,
                                     int bit_depth,
                                     uint32_t* out_component_idx);

diff --git a/libheif/api/libheif/heif_uncompressed_types.h b/libheif/api/libheif/heif_uncompressed_types.h
index 1a00dcc9..2366bf7d 100644
--- a/libheif/api/libheif/heif_uncompressed_types.h
+++ b/libheif/api/libheif/heif_uncompressed_types.h
@@ -29,33 +29,33 @@ extern "C" {

 // --- ISO 23001-17 component types (Table 1)

-typedef enum heif_uncompressed_component_type
+typedef enum heif_unci_component_type
 {
-  heif_uncompressed_component_type_monochrome = 0,
-  heif_uncompressed_component_type_Y = 1,
-  heif_uncompressed_component_type_Cb = 2,
-  heif_uncompressed_component_type_Cr = 3,
-  heif_uncompressed_component_type_red = 4,
-  heif_uncompressed_component_type_green = 5,
-  heif_uncompressed_component_type_blue = 6,
-  heif_uncompressed_component_type_alpha = 7,
-  heif_uncompressed_component_type_depth = 8,
-  heif_uncompressed_component_type_disparity = 9,
-  heif_uncompressed_component_type_palette = 10,
-  heif_uncompressed_component_type_filter_array = 11,
-  heif_uncompressed_component_type_padded = 12,
-  heif_uncompressed_component_type_cyan = 13,
-  heif_uncompressed_component_type_magenta = 14,
-  heif_uncompressed_component_type_yellow = 15,
-  heif_uncompressed_component_type_key_black = 16
-} heif_uncompressed_component_type;
+  heif_unci_component_type_monochrome = 0,
+  heif_unci_component_type_Y = 1,
+  heif_unci_component_type_Cb = 2,
+  heif_unci_component_type_Cr = 3,
+  heif_unci_component_type_red = 4,
+  heif_unci_component_type_green = 5,
+  heif_unci_component_type_blue = 6,
+  heif_unci_component_type_alpha = 7,
+  heif_unci_component_type_depth = 8,
+  heif_unci_component_type_disparity = 9,
+  heif_unci_component_type_palette = 10,
+  heif_unci_component_type_filter_array = 11,
+  heif_unci_component_type_padded = 12,
+  heif_unci_component_type_cyan = 13,
+  heif_unci_component_type_magenta = 14,
+  heif_unci_component_type_yellow = 15,
+  heif_unci_component_type_key_black = 16
+} heif_unci_component_type;


 // --- Bayer / filter array pattern

 typedef struct heif_bayer_pattern_pixel
 {
-  uint16_t component_index;  // index into the component definition (cmpd)
+  uint32_t component_id;
   float component_gain;
 } heif_bayer_pattern_pixel;

@@ -117,14 +117,14 @@ typedef struct heif_unci_image_parameters

 // --- pixel datatype support

-typedef enum heif_channel_datatype
+typedef enum heif_component_datatype
 {
-  heif_channel_datatype_undefined = 0,
-  heif_channel_datatype_unsigned_integer = 1,
-  heif_channel_datatype_signed_integer = 2,
-  heif_channel_datatype_floating_point = 3,
-  heif_channel_datatype_complex_number = 4
-} heif_channel_datatype;
+  heif_component_datatype_undefined = 0,
+  heif_component_datatype_unsigned_integer = 1,
+  heif_component_datatype_signed_integer = 2,
+  heif_component_datatype_floating_point = 3,
+  heif_component_datatype_complex_number = 4
+} heif_component_datatype;

 typedef struct heif_complex32
 {
diff --git a/libheif/codecs/uncompressed/unc_boxes.cc b/libheif/codecs/uncompressed/unc_boxes.cc
index 075ff1a3..b89fde98 100644
--- a/libheif/codecs/uncompressed/unc_boxes.cc
+++ b/libheif/codecs/uncompressed/unc_boxes.cc
@@ -96,27 +96,27 @@ bool is_predefined_component_type(uint16_t type)
 {
   // check whether the component type can be mapped to heif_uncompressed_component_type and we have a name defined for
   // it in sNames_uncompressed_component_type.
-  return type <= heif_uncompressed_component_type_max_valid;
+  return type <= heif_unci_component_type_max_valid;
 }

-static std::map<heif_uncompressed_component_type, const char*> sNames_uncompressed_component_type{
-    {heif_uncompressed_component_type_monochrome,   "monochrome"},
-    {heif_uncompressed_component_type_Y,            "Y"},
-    {heif_uncompressed_component_type_Cb,           "Cb"},
-    {heif_uncompressed_component_type_Cr,           "Cr"},
-    {heif_uncompressed_component_type_red,          "red"},
-    {heif_uncompressed_component_type_green,        "green"},
-    {heif_uncompressed_component_type_blue,         "blue"},
-    {heif_uncompressed_component_type_alpha,        "alpha"},
-    {heif_uncompressed_component_type_depth,        "depth"},
-    {heif_uncompressed_component_type_disparity,    "disparity"},
-    {heif_uncompressed_component_type_palette,      "palette"},
-    {heif_uncompressed_component_type_filter_array, "filter-array"},
-    {heif_uncompressed_component_type_padded,       "padded"},
-    {heif_uncompressed_component_type_cyan,         "cyan"},
-    {heif_uncompressed_component_type_magenta,      "magenta"},
-    {heif_uncompressed_component_type_yellow,       "yellow"},
-    {heif_uncompressed_component_type_key_black,    "key (black)"}
+static std::map<heif_unci_component_type, const char*> sNames_uncompressed_component_type{
+    {heif_unci_component_type_monochrome,   "monochrome"},
+    {heif_unci_component_type_Y,            "Y"},
+    {heif_unci_component_type_Cb,           "Cb"},
+    {heif_unci_component_type_Cr,           "Cr"},
+    {heif_unci_component_type_red,          "red"},
+    {heif_unci_component_type_green,        "green"},
+    {heif_unci_component_type_blue,         "blue"},
+    {heif_unci_component_type_alpha,        "alpha"},
+    {heif_unci_component_type_depth,        "depth"},
+    {heif_unci_component_type_disparity,    "disparity"},
+    {heif_unci_component_type_palette,      "palette"},
+    {heif_unci_component_type_filter_array, "filter-array"},
+    {heif_unci_component_type_padded,       "padded"},
+    {heif_unci_component_type_cyan,         "cyan"},
+    {heif_unci_component_type_magenta,      "magenta"},
+    {heif_unci_component_type_yellow,       "yellow"},
+    {heif_unci_component_type_key_black,    "key (black)"}
 };

 template <typename T> const char* get_name(T val, const std::map<T, const char*>& table)
@@ -186,7 +186,7 @@ std::string Box_cmpd::Component::get_component_type_name(uint16_t component_type
   std::stringstream sstr;

   if (is_predefined_component_type(component_type)) {
-    sstr << get_name(heif_uncompressed_component_type(component_type), sNames_uncompressed_component_type) << "\n";
+    sstr << get_name(heif_unci_component_type(component_type), sNames_uncompressed_component_type) << "\n";
   }
   else {
     sstr << "0x" << std::hex << component_type << std::dec << "\n";
@@ -196,7 +196,7 @@ std::string Box_cmpd::Component::get_component_type_name(uint16_t component_type
 }


-bool Box_cmpd::has_component(heif_uncompressed_component_type type) const
+bool Box_cmpd::has_component(heif_unci_component_type type) const
 {
   return std::any_of(m_components.begin(), m_components.end(),
                      [type](const auto& cmp) { return cmp.component_type == type; });
@@ -457,9 +457,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_red});
-    cmpd->add_component({heif_uncompressed_component_type_green});
-    cmpd->add_component({heif_uncompressed_component_type_blue});
+    cmpd->add_component({heif_unci_component_type_red});
+    cmpd->add_component({heif_unci_component_type_green});
+    cmpd->add_component({heif_unci_component_type_blue});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
   }
@@ -469,10 +469,10 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
     uncC->add_component({3, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_red});
-    cmpd->add_component({heif_uncompressed_component_type_green});
-    cmpd->add_component({heif_uncompressed_component_type_blue});
-    cmpd->add_component({heif_uncompressed_component_type_alpha});
+    cmpd->add_component({heif_unci_component_type_red});
+    cmpd->add_component({heif_unci_component_type_green});
+    cmpd->add_component({heif_unci_component_type_blue});
+    cmpd->add_component({heif_unci_component_type_alpha});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
   }
@@ -482,10 +482,10 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
     uncC->add_component({3, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_alpha});
-    cmpd->add_component({heif_uncompressed_component_type_blue});
-    cmpd->add_component({heif_uncompressed_component_type_green});
-    cmpd->add_component({heif_uncompressed_component_type_red});
+    cmpd->add_component({heif_unci_component_type_alpha});
+    cmpd->add_component({heif_unci_component_type_blue});
+    cmpd->add_component({heif_unci_component_type_green});
+    cmpd->add_component({heif_unci_component_type_red});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
   }
@@ -496,9 +496,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
   }
@@ -509,9 +509,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
   }
@@ -522,9 +522,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
   }
@@ -535,9 +535,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
   }
@@ -550,9 +550,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_411);
     uncC->set_interleave_type(interleave_mode_multi_y);
   }
@@ -562,9 +562,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
   }
@@ -575,10 +575,10 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
     uncC->add_component({3, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_alpha});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_alpha});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
   }
@@ -590,9 +590,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 10, component_format_unsigned, 0});
     uncC->add_component({0, 10, component_format_unsigned, 0});
     uncC->add_component({2, 10, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
     uncC->set_block_size(2);
@@ -606,9 +606,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 10, component_format_unsigned, 0});
     uncC->add_component({1, 10, component_format_unsigned, 0});
     uncC->add_component({2, 10, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_no_subsampling);
     uncC->set_interleave_type(interleave_mode_pixel);
     uncC->set_block_size(4);
@@ -624,9 +624,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({1, 10, component_format_unsigned, 0});
     uncC->add_component({2, 10, component_format_unsigned, 0});
     uncC->add_component({1, 10, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_multi_y);
     uncC->set_block_size(4);
@@ -639,9 +639,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_420);
     uncC->set_interleave_type(interleave_mode_component);
   }
@@ -651,9 +651,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_420);
     uncC->set_interleave_type(interleave_mode_mixed);
   }
@@ -663,9 +663,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_420);
     uncC->set_interleave_type(interleave_mode_mixed);
   }
@@ -675,9 +675,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Cr});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_component);
   }
@@ -687,9 +687,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_422);
     uncC->set_interleave_type(interleave_mode_component);
   }
@@ -699,9 +699,9 @@ void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
     uncC->add_component({0, 8, component_format_unsigned, 0});
     uncC->add_component({1, 8, component_format_unsigned, 0});
     uncC->add_component({2, 8, component_format_unsigned, 0});
-    cmpd->add_component({heif_uncompressed_component_type_Y});
-    cmpd->add_component({heif_uncompressed_component_type_Cr});
-    cmpd->add_component({heif_uncompressed_component_type_Cb});
+    cmpd->add_component({heif_unci_component_type_Y});
+    cmpd->add_component({heif_unci_component_type_Cr});
+    cmpd->add_component({heif_unci_component_type_Cb});
     uncC->set_sampling_type(sampling_mode_420);
     uncC->set_interleave_type(interleave_mode_component);
   }
@@ -989,8 +989,8 @@ Error Box_cpat::parse(BitstreamRange& range, const heif_security_limits* limits)
   m_pattern.pixels.resize(num_pixels);

   for (size_t i = 0; i < num_pixels; i++) {
-    heif_bayer_pattern_pixel pixel{};
-    pixel.component_index = static_cast<uint16_t>(range.read32());
+    bayer_pattern_pixel_cmpd pixel{};
+    pixel.cmpd_index = range.read32();
     pixel.component_gain = range.read_float32();
     m_pattern.pixels[i] = pixel;
   }
@@ -1008,7 +1008,7 @@ std::string Box_cpat::dump(Indent& indent) const
   sstr << indent << "pattern_height: " << get_pattern_height() << "\n";

   for (const auto& pixel : m_pattern.pixels) {
-    sstr << indent << "component index: " << pixel.component_index << ", gain: " << pixel.component_gain << "\n";
+    sstr << indent << "component index: " << pixel.cmpd_index << ", gain: " << pixel.component_gain << "\n";
   }
   return sstr.str();
 }
@@ -1028,7 +1028,7 @@ Error Box_cpat::write(StreamWriter& writer) const
   writer.write16(m_pattern.pattern_height);

   for (const auto& pixel : m_pattern.pixels) {
-    writer.write32(pixel.component_index);
+    writer.write32(pixel.cmpd_index);
     writer.write_float32(pixel.component_gain);
   }

@@ -1053,9 +1053,9 @@ Error Box_splz::parse(BitstreamRange& range, const heif_security_limits* limits)
             "Number of components in splz box exceeds the security limits."};
   }

-  m_pattern.component_indices.resize(component_count);
+  m_pattern.component_ids.resize(component_count);
   for (uint32_t i = 0; i < component_count; i++) {
-    m_pattern.component_indices[i] = range.read32();
+    m_pattern.component_ids[i] = range.read32();
   }

   m_pattern.pattern_width = range.read16();
@@ -1091,9 +1091,9 @@ std::string Box_splz::dump(Indent& indent) const

   sstr << FullBox::dump(indent);

-  sstr << indent << "component_count: " << m_pattern.component_indices.size() << "\n";
-  for (size_t i = 0; i < m_pattern.component_indices.size(); i++) {
-    sstr << indent << "  component_index[" << i << "]: " << m_pattern.component_indices[i] << "\n";
+  sstr << indent << "component_count: " << m_pattern.component_ids.size() << "\n";
+  for (size_t i = 0; i < m_pattern.component_ids.size(); i++) {
+    sstr << indent << "  component_index[" << i << "]: " << m_pattern.component_ids[i] << "\n";
   }

   sstr << indent << "pattern_width: " << m_pattern.pattern_width << "\n";
@@ -1125,8 +1125,8 @@ Error Box_splz::write(StreamWriter& writer) const
             "incorrect number of polarization pattern angles"};
   }

-  writer.write32(static_cast<uint32_t>(m_pattern.component_indices.size()));
-  for (uint32_t idx : m_pattern.component_indices) {
+  writer.write32(static_cast<uint32_t>(m_pattern.component_ids.size()));
+  for (uint32_t idx : m_pattern.component_ids) {
     writer.write32(idx);
   }

@@ -1159,9 +1159,9 @@ Error Box_sbpm::parse(BitstreamRange& range, const heif_security_limits* limits)
             "sbpm component_count exceeds security limit."};
   }

-  m_map.component_indices.resize(component_count);
+  m_map.component_ids.resize(component_count);
   for (uint32_t i = 0; i < component_count; i++) {
-    m_map.component_indices[i] = range.read32();
+    m_map.component_ids[i] = range.read32();
   }

   uint8_t flags = range.read8();
@@ -1205,9 +1205,9 @@ std::string Box_sbpm::dump(Indent& indent) const

   sstr << FullBox::dump(indent);

-  sstr << indent << "component_count: " << m_map.component_indices.size() << "\n";
-  for (size_t i = 0; i < m_map.component_indices.size(); i++) {
-    sstr << indent << "  component_index[" << i << "]: " << m_map.component_indices[i] << "\n";
+  sstr << indent << "component_count: " << m_map.component_ids.size() << "\n";
+  for (size_t i = 0; i < m_map.component_ids.size(); i++) {
+    sstr << indent << "  component_index[" << i << "]: " << m_map.component_ids[i] << "\n";
   }

   sstr << indent << "correction_applied: " << m_map.correction_applied << "\n";
@@ -1236,8 +1236,8 @@ Error Box_sbpm::write(StreamWriter& writer) const
 {
   size_t box_start = reserve_box_header_space(writer);

-  writer.write32(static_cast<uint32_t>(m_map.component_indices.size()));
-  for (uint32_t idx : m_map.component_indices) {
+  writer.write32(static_cast<uint32_t>(m_map.component_ids.size()));
+  for (uint32_t idx : m_map.component_ids) {
     writer.write32(idx);
   }

@@ -1283,9 +1283,9 @@ Error Box_snuc::parse(BitstreamRange& range, const heif_security_limits* limits)
             "snuc component_count exceeds security limit."};
   }

-  m_nuc.component_indices.resize(component_count);
+  m_nuc.component_ids.resize(component_count);
   for (uint32_t i = 0; i < component_count; i++) {
-    m_nuc.component_indices[i] = range.read32();
+    m_nuc.component_ids[i] = range.read32();
   }

   uint8_t flags = range.read8();
@@ -1340,9 +1340,9 @@ std::string Box_snuc::dump(Indent& indent) const

   sstr << FullBox::dump(indent);

-  sstr << indent << "component_count: " << m_nuc.component_indices.size() << "\n";
-  for (size_t i = 0; i < m_nuc.component_indices.size(); i++) {
-    sstr << indent << "  component_index[" << i << "]: " << m_nuc.component_indices[i] << "\n";
+  sstr << indent << "component_count: " << m_nuc.component_ids.size() << "\n";
+  for (size_t i = 0; i < m_nuc.component_ids.size(); i++) {
+    sstr << indent << "  component_index[" << i << "]: " << m_nuc.component_ids[i] << "\n";
   }

   sstr << indent << "nuc_is_applied: " << m_nuc.nuc_is_applied << "\n";
@@ -1361,8 +1361,8 @@ Error Box_snuc::write(StreamWriter& writer) const
 {
   size_t box_start = reserve_box_header_space(writer);

-  writer.write32(static_cast<uint32_t>(m_nuc.component_indices.size()));
-  for (uint32_t idx : m_nuc.component_indices) {
+  writer.write32(static_cast<uint32_t>(m_nuc.component_ids.size()));
+  for (uint32_t idx : m_nuc.component_ids) {
     writer.write32(idx);
   }

diff --git a/libheif/codecs/uncompressed/unc_boxes.h b/libheif/codecs/uncompressed/unc_boxes.h
index 1ce7ef48..36685159 100644
--- a/libheif/codecs/uncompressed/unc_boxes.h
+++ b/libheif/codecs/uncompressed/unc_boxes.h
@@ -64,7 +64,7 @@ public:

   const std::vector<Component>& get_components() const { return m_components; }

-  bool has_component(heif_uncompressed_component_type) const;
+  bool has_component(heif_unci_component_type) const;

   uint16_t add_component(const Component& component)
   {
@@ -363,9 +363,9 @@ public:

   uint16_t get_pattern_height() const { return m_pattern.pattern_height; }

-  const BayerPattern& get_pattern() const { return m_pattern; }
+  const BayerPatternCmpd& get_pattern() const { return m_pattern; }

-  void set_pattern(const BayerPattern& pattern) { m_pattern = pattern; }
+  void set_pattern(const BayerPatternCmpd& pattern) { m_pattern = pattern; }

   std::string dump(Indent&) const override;

@@ -374,7 +374,7 @@ public:
 protected:
   Error parse(BitstreamRange& range, const heif_security_limits* limits) override;

-  BayerPattern m_pattern;
+  BayerPatternCmpd m_pattern;
 };


diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index 741d78ad..cddb2681 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -88,27 +88,27 @@ Error UncompressedImageCodec::get_heif_chroma_uncompressed(const std::shared_ptr
     uint32_t component_index = component.component_index;
     uint16_t component_type = cmpd->get_components()[component_index].component_type;

-    if (component_type > heif_uncompressed_component_type_max_valid) {
+    if (component_type > heif_unci_component_type_max_valid) {
       std::stringstream sstr;
-      sstr << "a component_type > " << heif_uncompressed_component_type_max_valid << " is not supported";
+      sstr << "a component_type > " << heif_unci_component_type_max_valid << " is not supported";
       return {heif_error_Unsupported_feature, heif_suberror_Invalid_parameter_value, sstr.str()};
     }
-    if (component_type == heif_uncompressed_component_type_padded) {
+    if (component_type == heif_unci_component_type_padded) {
       // not relevant for determining chroma
       continue;
     }
     componentSet |= (1 << component_type);
   }

-  *out_has_alpha = (componentSet & (1 << heif_uncompressed_component_type_alpha)) != 0;
+  *out_has_alpha = (componentSet & (1 << heif_unci_component_type_alpha)) != 0;

-  if (componentSet == ((1 << heif_uncompressed_component_type_red) | (1 << heif_uncompressed_component_type_green) | (1 << heif_uncompressed_component_type_blue)) ||
-      componentSet == ((1 << heif_uncompressed_component_type_red) | (1 << heif_uncompressed_component_type_green) | (1 << heif_uncompressed_component_type_blue) | (1 << heif_uncompressed_component_type_alpha))) {
+  if (componentSet == ((1 << heif_unci_component_type_red) | (1 << heif_unci_component_type_green) | (1 << heif_unci_component_type_blue)) ||
+      componentSet == ((1 << heif_unci_component_type_red) | (1 << heif_unci_component_type_green) | (1 << heif_unci_component_type_blue) | (1 << heif_unci_component_type_alpha))) {
     *out_chroma = heif_chroma_444;
     *out_colourspace = heif_colorspace_RGB;
   }

-  if (componentSet == ((1 << heif_uncompressed_component_type_Y) | (1 << heif_uncompressed_component_type_Cb) | (1 << heif_uncompressed_component_type_Cr))) {
+  if (componentSet == ((1 << heif_unci_component_type_Y) | (1 << heif_unci_component_type_Cb) | (1 << heif_unci_component_type_Cr))) {
     switch (uncC->get_sampling_type()) {
       case sampling_mode_no_subsampling:
         *out_chroma = heif_chroma_444;
@@ -123,14 +123,14 @@ Error UncompressedImageCodec::get_heif_chroma_uncompressed(const std::shared_ptr
     *out_colourspace = heif_colorspace_YCbCr;
   }

-  if (componentSet == (1 << heif_uncompressed_component_type_monochrome) || componentSet == ((1 << heif_uncompressed_component_type_monochrome) | (1 << heif_uncompressed_component_type_alpha)) ||
-      componentSet == (1 << heif_uncompressed_component_type_Y) || componentSet == ((1 << heif_uncompressed_component_type_Y) | (1 << heif_uncompressed_component_type_alpha))) {
+  if (componentSet == (1 << heif_unci_component_type_monochrome) || componentSet == ((1 << heif_unci_component_type_monochrome) | (1 << heif_unci_component_type_alpha)) ||
+      componentSet == (1 << heif_unci_component_type_Y) || componentSet == ((1 << heif_unci_component_type_Y) | (1 << heif_unci_component_type_alpha))) {
     // mono or mono + alpha input, mono output.
     *out_chroma = heif_chroma_monochrome;
     *out_colourspace = heif_colorspace_monochrome;
   }

-  if (componentSet == (1 << heif_uncompressed_component_type_filter_array)) {
+  if (componentSet == (1 << heif_unci_component_type_filter_array)) {
     // TODO - we should look up the components
     *out_chroma = heif_chroma_monochrome;
     *out_colourspace = heif_colorspace_filter_array;
@@ -165,33 +165,50 @@ bool map_uncompressed_component_to_channel(const std::shared_ptr<const Box_cmpd>
 }


-heif_channel_datatype unc_component_format_to_datatype(uint8_t format)
+heif_component_datatype unc_component_format_to_datatype(uint8_t format)
 {
   switch (format) {
     case component_format_unsigned:
-      return heif_channel_datatype_unsigned_integer;
+      return heif_component_datatype_unsigned_integer;

     case component_format_signed:
-      return heif_channel_datatype_signed_integer;
+      return heif_component_datatype_signed_integer;

     case component_format_float:
-      return heif_channel_datatype_floating_point;
+      return heif_component_datatype_floating_point;

     case component_format_complex:
-      return heif_channel_datatype_complex_number;
+      return heif_component_datatype_complex_number;

     default:
-      return heif_channel_datatype_undefined;
+      return heif_component_datatype_undefined;
   }
 }


-Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(const std::shared_ptr<const Box_cmpd> cmpd,
-                                                                             const std::shared_ptr<const Box_uncC> uncC,
+static Error validate_component_indices(const std::vector<uint32_t>& indices,
+                                        size_t cmpd_size,
+                                        const char* box_name)
+{
+  for (uint32_t idx : indices) {
+    if (idx >= cmpd_size) {
+      return {heif_error_Invalid_input,
+              heif_suberror_Invalid_parameter_value,
+              std::string(box_name) + " component index out of range of cmpd table"};
+    }
+  }
+  return Error::Ok;
+}
+
+
+Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(const unci_properties& properties,
                                                                              uint32_t width,
                                                                              uint32_t height,
                                                                              const heif_security_limits* limits)
 {
+  auto cmpd = properties.cmpd;
+  auto uncC = properties.uncC;
+
   const auto& components = cmpd->get_components();

   auto img = std::make_shared<HeifPixelImage>();
@@ -206,15 +223,10 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con
               colourspace,
               chroma);

-  // Populate the cmpd table on the image so add_component_for_index() can look up types.
-  {
-    std::vector<uint16_t> cmpd_types;
-    cmpd_types.reserve(components.size());
-    for (const auto& c : components) {
-      cmpd_types.push_back(c.component_type);
-    }
-    img->set_cmpd_component_types(std::move(cmpd_types));
-  }
+
+  // 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(components.size());

   for (Box_uncC::Component component : uncC->get_components()) {
     if (component.component_index >= components.size()) {
@@ -227,31 +239,103 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con

     auto component_type = components[component.component_index].component_type;

-    if ((component_type == heif_uncompressed_component_type_Cb) ||
-        (component_type == heif_uncompressed_component_type_Cr)) {
-      Result<uint32_t> result = img->add_component_for_index(component.component_index,
-                                                              (width / chroma_h_subsampling(chroma)),
-                                                              (height / chroma_v_subsampling(chroma)),
-                                                              unc_component_format_to_datatype(component.component_format),
-                                                              component.component_bit_depth,
-                                                              limits);
+    if ((component_type == heif_unci_component_type_Cb) ||
+        (component_type == heif_unci_component_type_Cr)) {
+      Result<uint32_t> result = img->add_component((width / chroma_h_subsampling(chroma)),
+                                                   (height / chroma_v_subsampling(chroma)),
+                                                   cmpd->get_components()[component.component_index].component_type,
+                                                   unc_component_format_to_datatype(component.component_format),
+                                                   component.component_bit_depth,
+                                                   limits);
       if (result.is_error()) {
         return result.error();
       }
+
+      cmpd_index_to_comp_ids[component.component_index].push_back(*result);
     }
     else {
-      Result<uint32_t> result = img->add_component_for_index(component.component_index,
-                                                              width,
-                                                              height,
-                                                              unc_component_format_to_datatype(component.component_format),
-                                                              component.component_bit_depth,
-                                                              limits);
+      Result<uint32_t> result = img->add_component(width,
+                                                   height,
+                                                   cmpd->get_components()[component.component_index].component_type,
+                                                   unc_component_format_to_datatype(component.component_format),
+                                                   component.component_bit_depth,
+                                                   limits);
       if (result.is_error()) {
         return result.error();
       }
+
+      cmpd_index_to_comp_ids[component.component_index].push_back(*result);
     }
   }

+
+  // --- assign the metadata boxes
+
+  size_t cmpd_size = cmpd ? cmpd->get_components().size() : 0;
+
+  if (properties.cpat) {
+    const auto& pattern_cmpd = properties.cpat->get_pattern();
+    std::vector<uint32_t> cpat_indices;
+    for (const auto& pixel : pattern_cmpd.pixels) {
+      cpat_indices.push_back(pixel.cmpd_index);
+    }
+    Error err = validate_component_indices(cpat_indices, cmpd_size, "cpat");
+    if (err) {
+      return err;
+    }
+
+    // translate BayerPattern, adding new components to the HeifPixelImage
+
+    BayerPattern pattern;
+    pattern.pattern_width = pattern_cmpd.pattern_width;
+    pattern.pattern_height = pattern_cmpd.pattern_height;
+    for (auto p : pattern_cmpd.pixels) {
+      uint32_t comp_id = img->add_component_without_data(components[p.cmpd_index].component_type);
+      pattern.pixels.push_back({comp_id, p.component_gain});
+
+      cmpd_index_to_comp_ids[p.cmpd_index].push_back(comp_id);
+    }
+
+    img->set_bayer_pattern(pattern);
+  }
+
+  for (const auto& splz_box : properties.splz) {
+    const auto& pattern_cmpd = splz_box->get_pattern();
+    Error err = validate_component_indices(pattern_cmpd.component_ids, cmpd_size, "splz");
+    if (err) {
+      return err;
+    }
+    PolarizationPattern pattern = pattern_cmpd;
+    pattern.component_ids = map_cmpd_to_component_ids(pattern_cmpd.component_ids, cmpd_index_to_comp_ids);
+    img->add_polarization_pattern(pattern);
+  }
+
+  for (const auto& sbpm_box : properties.sbpm) {
+    const auto& bad_pixels_map_cmpd = sbpm_box->get_bad_pixels_map();
+    Error err = validate_component_indices(bad_pixels_map_cmpd.component_ids, cmpd_size, "sbpm");
+    if (err) {
+      return err;
+    }
+    SensorBadPixelsMap bad_pixels_map = bad_pixels_map_cmpd;
+    bad_pixels_map.component_ids = map_cmpd_to_component_ids(bad_pixels_map_cmpd.component_ids, cmpd_index_to_comp_ids);
+    img->add_sensor_bad_pixels_map(bad_pixels_map);
+  }
+
+  for (const auto& snuc_box : properties.snuc) {
+    const auto& nuc_cmpd = snuc_box->get_nuc();
+    Error err = validate_component_indices(nuc_cmpd.component_ids, cmpd_size, "snuc");
+    if (err) {
+      return err;
+    }
+    SensorNonUniformityCorrection nuc = nuc_cmpd;
+    nuc.component_ids = map_cmpd_to_component_ids(nuc_cmpd.component_ids, cmpd_index_to_comp_ids);
+    img->add_sensor_nuc(nuc);
+  }
+
+  if (properties.cloc) {
+    img->set_chroma_location(properties.cloc->get_chroma_location());
+  }
+
   return img;
 }

@@ -283,7 +367,12 @@ Error UncompressedImageCodec::decode_uncompressed_image_tile(const HeifContext*
   uint32_t tile_width = ispe->get_width() / uncC->get_number_of_tile_columns();
   uint32_t tile_height = ispe->get_height() / uncC->get_number_of_tile_rows();

-  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(cmpd, uncC, tile_width, tile_height, context->get_security_limits());
+
+  // 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;
+
+  Result<std::shared_ptr<HeifPixelImage>> createImgResult = create_image(properties, tile_width, tile_height, context->get_security_limits());
   if (!createImgResult) {
     return createImgResult.error();
   }
@@ -339,7 +428,7 @@ Error UncompressedImageCodec::check_header_validity(std::optional<const std::sha
       }

       uint16_t component_type = cmpd->get_components()[comp.component_index].component_type;
-      if (component_type > 7 && component_type != heif_uncompressed_component_type_padded && component_type != heif_uncompressed_component_type_filter_array) {
+      if (component_type > 7 && component_type != heif_unci_component_type_padded && component_type != heif_unci_component_type_filter_array) {
         std::stringstream sstr;
         sstr << "Uncompressed image with component_type " << ((int) component_type) << " is not implemented yet";
         return {heif_error_Unsupported_feature,
diff --git a/libheif/codecs/uncompressed/unc_codec.h b/libheif/codecs/uncompressed/unc_codec.h
index eb08061a..28ca6c60 100644
--- a/libheif/codecs/uncompressed/unc_codec.h
+++ b/libheif/codecs/uncompressed/unc_codec.h
@@ -83,8 +83,7 @@ public:
                                             heif_colorspace* out_colourspace,
                                             bool* out_has_alpha);

-  static Result<std::shared_ptr<HeifPixelImage>> create_image(std::shared_ptr<const Box_cmpd>,
-                                                              std::shared_ptr<const Box_uncC>,
+  static Result<std::shared_ptr<HeifPixelImage>> create_image(const unci_properties& properties,
                                                               uint32_t width,
                                                               uint32_t height,
                                                               const heif_security_limits* limits);
diff --git a/libheif/codecs/uncompressed/unc_dec.cc b/libheif/codecs/uncompressed/unc_dec.cc
index c831d0e3..23a60e15 100644
--- a/libheif/codecs/uncompressed/unc_dec.cc
+++ b/libheif/codecs/uncompressed/unc_dec.cc
@@ -65,14 +65,14 @@ int Decoder_uncompressed::get_luma_bits_per_pixel() const
     }
     auto component_type = m_cmpd->get_components()[component_index].component_type;
     switch (component_type) {
-      case heif_uncompressed_component_type_monochrome:
-      case heif_uncompressed_component_type_red:
-      case heif_uncompressed_component_type_green:
-      case heif_uncompressed_component_type_blue:
-      case heif_uncompressed_component_type_filter_array:
+      case heif_unci_component_type_monochrome:
+      case heif_unci_component_type_red:
+      case heif_unci_component_type_green:
+      case heif_unci_component_type_blue:
+      case heif_unci_component_type_filter_array:
         alternate_channel_bits = std::max(alternate_channel_bits, (int) component.component_bit_depth);
         break;
-      case heif_uncompressed_component_type_Y:
+      case heif_unci_component_type_Y:
         luma_bits = std::max(luma_bits, (int) component.component_bit_depth);
         break;
         // TODO: there are other things we'll need to handle eventually, like palette.
@@ -109,15 +109,15 @@ int Decoder_uncompressed::get_chroma_bits_per_pixel() const
     }
     auto component_type = m_cmpd->get_components()[component_index].component_type;
     switch (component_type) {
-      case heif_uncompressed_component_type_monochrome:
-      case heif_uncompressed_component_type_red:
-      case heif_uncompressed_component_type_green:
-      case heif_uncompressed_component_type_blue:
-      case heif_uncompressed_component_type_filter_array:
+      case heif_unci_component_type_monochrome:
+      case heif_unci_component_type_red:
+      case heif_unci_component_type_green:
+      case heif_unci_component_type_blue:
+      case heif_unci_component_type_filter_array:
         alternate_channel_bits = std::max(alternate_channel_bits, (int) component.component_bit_depth);
         break;
-      case heif_uncompressed_component_type_Cb:
-      case heif_uncompressed_component_type_Cr:
+      case heif_unci_component_type_Cb:
+      case heif_unci_component_type_Cr:
         chroma_bits = std::max(chroma_bits, (int) component.component_bit_depth);
         break;
         // TODO: there are other things we'll need to handle eventually, like palette.
diff --git a/libheif/codecs/uncompressed/unc_decoder.cc b/libheif/codecs/uncompressed/unc_decoder.cc
index c5fa4ac8..1d15eaa9 100644
--- a/libheif/codecs/uncompressed/unc_decoder.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -39,21 +39,6 @@
 #include <string>


-static Error validate_component_indices(const std::vector<uint32_t>& indices,
-                                        size_t cmpd_size,
-                                        const char* box_name)
-{
-  for (uint32_t idx : indices) {
-    if (idx >= cmpd_size) {
-      return {heif_error_Invalid_input,
-              heif_suberror_Invalid_parameter_value,
-              std::string(box_name) + " component index out of range of cmpd table"};
-    }
-  }
-  return Error::Ok;
-}
-
-
 // --- unc_decoder ---

 unc_decoder::unc_decoder(uint32_t width, uint32_t height,
@@ -471,58 +456,13 @@ Result<std::shared_ptr<HeifPixelImage> > unc_decoder::decode_full_image(
     return {global_limit_error};
   }

-  Result<std::shared_ptr<HeifPixelImage> > createImgResult = UncompressedImageCodec::create_image(cmpd, uncC, width, height, limits);
+  Result<std::shared_ptr<HeifPixelImage> > createImgResult = UncompressedImageCodec::create_image(properties, width, height, limits);
   if (!createImgResult) {
     return createImgResult.error();
   }

   auto img = *createImgResult;

-  size_t cmpd_size = cmpd ? cmpd->get_components().size() : 0;
-
-  if (properties.cpat) {
-    const auto& pattern = properties.cpat->get_pattern();
-    std::vector<uint32_t> cpat_indices;
-    for (const auto& pixel : pattern.pixels) {
-      cpat_indices.push_back(pixel.component_index);
-    }
-    Error err = validate_component_indices(cpat_indices, cmpd_size, "cpat");
-    if (err) {
-      return err;
-    }
-    img->set_bayer_pattern(pattern);
-  }
-
-  for (const auto& splz_box : properties.splz) {
-    const auto& pattern = splz_box->get_pattern();
-    Error err = validate_component_indices(pattern.component_indices, cmpd_size, "splz");
-    if (err) {
-      return err;
-    }
-    img->add_polarization_pattern(pattern);
-  }
-
-  for (const auto& sbpm_box : properties.sbpm) {
-    const auto& bad_pixels_map = sbpm_box->get_bad_pixels_map();
-    Error err = validate_component_indices(bad_pixels_map.component_indices, cmpd_size, "sbpm");
-    if (err) {
-      return err;
-    }
-    img->add_sensor_bad_pixels_map(bad_pixels_map);
-  }
-
-  for (const auto& snuc_box : properties.snuc) {
-    const auto& nuc = snuc_box->get_nuc();
-    Error err = validate_component_indices(nuc.component_indices, cmpd_size, "snuc");
-    if (err) {
-      return err;
-    }
-    img->add_sensor_nuc(nuc);
-  }
-
-  if (properties.cloc) {
-    img->set_chroma_location(properties.cloc->get_chroma_location());
-  }

   auto decoderResult = unc_decoder_factory::get_unc_decoder(width, height, cmpd, uncC);
   if (!decoderResult) {
diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
index 1ba6e1c4..77f67ba2 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
@@ -87,6 +87,7 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
     comp[i].use = true; // map_uncompressed_component_to_channel(m_cmpd, c, &channel);
     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);
     }
     else {
       comp[i].dst_plane = nullptr;
diff --git a/libheif/codecs/uncompressed/unc_encoder.cc b/libheif/codecs/uncompressed/unc_encoder.cc
index c07fcc41..ca277b9c 100644
--- a/libheif/codecs/uncompressed/unc_encoder.cc
+++ b/libheif/codecs/uncompressed/unc_encoder.cc
@@ -36,42 +36,42 @@
 #include <utility>


-heif_uncompressed_component_type heif_channel_to_component_type(heif_channel channel)
+heif_unci_component_type heif_channel_to_component_type(heif_channel channel)
 {
   switch (channel) {
-    case heif_channel_Y: return heif_uncompressed_component_type_Y;
-    case heif_channel_Cb: return heif_uncompressed_component_type_Cb;
-    case heif_channel_Cr: return heif_uncompressed_component_type_Cr;
-    case heif_channel_R: return heif_uncompressed_component_type_red;
-    case heif_channel_G: return heif_uncompressed_component_type_green;
-    case heif_channel_B: return heif_uncompressed_component_type_blue;
-    case heif_channel_Alpha: return heif_uncompressed_component_type_alpha;
+    case heif_channel_Y: return heif_unci_component_type_Y;
+    case heif_channel_Cb: return heif_unci_component_type_Cb;
+    case heif_channel_Cr: return heif_unci_component_type_Cr;
+    case heif_channel_R: return heif_unci_component_type_red;
+    case heif_channel_G: return heif_unci_component_type_green;
+    case heif_channel_B: return heif_unci_component_type_blue;
+    case heif_channel_Alpha: return heif_unci_component_type_alpha;
     case heif_channel_interleaved: assert(false);
       break;
-    case heif_channel_filter_array: return heif_uncompressed_component_type_filter_array;
-    case heif_channel_depth: return heif_uncompressed_component_type_depth;
-    case heif_channel_disparity: return heif_uncompressed_component_type_disparity;
-    case heif_channel_unknown: return heif_uncompressed_component_type_padded;
+    case heif_channel_filter_array: return heif_unci_component_type_filter_array;
+    case heif_channel_depth: return heif_unci_component_type_depth;
+    case heif_channel_disparity: return heif_unci_component_type_disparity;
+    case heif_channel_unknown: return heif_unci_component_type_padded;
   }

-  return heif_uncompressed_component_type_padded;
+  return heif_unci_component_type_padded;
 }


-heif_uncompressed_component_format to_unc_component_format(heif_channel_datatype channel_datatype)
+heif_uncompressed_component_format to_unc_component_format(heif_component_datatype channel_datatype)
 {
   switch (channel_datatype) {
-    case heif_channel_datatype_signed_integer:
+    case heif_component_datatype_signed_integer:
       return component_format_signed;

-    case heif_channel_datatype_floating_point:
+    case heif_component_datatype_floating_point:
       return component_format_float;

-    case heif_channel_datatype_complex_number:
+    case heif_component_datatype_complex_number:
       return component_format_complex;

-    case heif_channel_datatype_unsigned_integer:
-    case heif_channel_datatype_undefined:
+    case heif_component_datatype_unsigned_integer:
+    case heif_component_datatype_undefined:
     default:
       return component_format_unsigned;
   }
@@ -83,68 +83,69 @@ unc_encoder::unc_encoder(const std::shared_ptr<const HeifPixelImage>& image)
   m_cmpd = std::make_shared<Box_cmpd>();
   m_uncC = std::make_shared<Box_uncC>();

-  m_cmpd->set_components(image->get_cmpd_component_types());
+  // --- fill component-id to cmpd-index map

-  // --- Bayer pattern: add reference components to cmpd and generate cpat box
+  std::vector<uint32_t> ids = image->get_used_component_ids();

-  if (image->has_bayer_pattern()) {
-    const BayerPattern& bayer = image->get_bayer_pattern();
-
-    // The bayer pattern stores component_index values. When the image has a cmpd
-    // table (add_component path), we look up the component type from it. When it
-    // doesn't (legacy add_plane path), the component_index IS the component type.
-
-    // Collect unique component types from the pattern (in order of first appearance)
-    std::vector<uint16_t> unique_types;
-    std::set<uint16_t> seen;
-    for (const auto& pixel : bayer.pixels) {
-      uint16_t comp_type = pixel.component_index;  // legacy: index IS the type
-      if (seen.insert(comp_type).second) {
-        unique_types.push_back(comp_type);
-      }
-    }
+  for (size_t i = 0; i < ids.size(); i++) {
+    m_map_id_to_cmpd_index[ids[i]] = static_cast<uint32_t>(i);
+  }

-    // Add reference components to cmpd (these have no uncC entries).
-    std::map<uint16_t, uint16_t> type_to_cmpd_index;
-    for (uint16_t type : unique_types) {
-      type_to_cmpd_index[type] = m_cmpd->add_component({type});
-    }
+  // TODO: we could combine component_ids with similar types if they are also used in the same way in the metadata boxes
+
+  // --- create cmpd component types
+
+  uint32_t max_cmpd_index=0;
+  for (auto iter : m_map_id_to_cmpd_index) {
+    max_cmpd_index = std::max(max_cmpd_index, iter.second);
+  }
+
+  std::vector<uint16_t> cmpd_types(static_cast<size_t>(max_cmpd_index) + 1);
+
+  for (auto iter : m_map_id_to_cmpd_index) {
+    uint16_t comp_type = image->get_component_type(iter.first);
+    cmpd_types[iter.second] = comp_type;
+  }
+
+  m_cmpd->set_components(cmpd_types);
+
+  // --- Bayer pattern: add reference components to cmpd and generate cpat box
+
+  if (image->has_any_bayer_pattern()) {
+    const BayerPattern& bayer = image->get_any_bayer_pattern();

     // Build cpat box with resolved cmpd indices
-    BayerPattern cpat_pattern;
-    cpat_pattern.pattern_width = bayer.pattern_width;
-    cpat_pattern.pattern_height = bayer.pattern_height;
-    cpat_pattern.pixels.resize(bayer.pixels.size());
-    for (size_t i = 0; i < bayer.pixels.size(); i++) {
-      uint16_t comp_type = bayer.pixels[i].component_index;  // legacy: index IS the type
-      cpat_pattern.pixels[i].component_index = type_to_cmpd_index[comp_type];
-      cpat_pattern.pixels[i].component_gain = bayer.pixels[i].component_gain;
-    }

     m_cpat = std::make_shared<Box_cpat>();
-    m_cpat->set_pattern(cpat_pattern);
+    m_cpat->set_pattern(bayer.resolve_to_cmpd(m_map_id_to_cmpd_index));
   }

   if (image->has_polarization_patterns()) {
     for (const auto& pol : image->get_polarization_patterns()) {
+      PolarizationPattern polCmpd = pol;
+      polCmpd.component_ids = map_component_ids_to_cmpd(pol.component_ids, m_map_id_to_cmpd_index);
       auto splz = std::make_shared<Box_splz>();
-      splz->set_pattern(pol);
+      splz->set_pattern(polCmpd);
       m_splz.push_back(splz);
     }
   }

   if (image->has_sensor_bad_pixels_maps()) {
     for (const auto& bpm : image->get_sensor_bad_pixels_maps()) {
+      SensorBadPixelsMap bpmCmpd = bpm;
+      bpmCmpd.component_ids = map_component_ids_to_cmpd(bpm.component_ids, m_map_id_to_cmpd_index);
       auto sbpm = std::make_shared<Box_sbpm>();
-      sbpm->set_bad_pixels_map(bpm);
+      sbpm->set_bad_pixels_map(bpmCmpd);
       m_sbpm.push_back(sbpm);
     }
   }

   if (image->has_sensor_nuc()) {
     for (const auto& nuc : image->get_sensor_nuc()) {
+      SensorNonUniformityCorrection nucCmpd = nuc;
+      nucCmpd.component_ids = map_component_ids_to_cmpd(nuc.component_ids, m_map_id_to_cmpd_index);
       auto snuc = std::make_shared<Box_snuc>();
-      snuc->set_nuc(nuc);
+      snuc->set_nuc(nucCmpd);
       m_snuc.push_back(snuc);
     }
   }
@@ -187,7 +188,7 @@ Result<std::unique_ptr<const unc_encoder> > unc_encoder_factory::get_unc_encoder

 heif_uncompressed_component_format to_unc_component_format(const std::shared_ptr<const HeifPixelImage>& image, heif_channel channel)
 {
-  heif_channel_datatype datatype = image->get_datatype(channel);
+  heif_component_datatype datatype = image->get_datatype(channel);
   heif_uncompressed_component_format component_format = to_unc_component_format(datatype);
   return component_format;
 }
diff --git a/libheif/codecs/uncompressed/unc_encoder.h b/libheif/codecs/uncompressed/unc_encoder.h
index 40d2a8d9..c613926f 100644
--- a/libheif/codecs/uncompressed/unc_encoder.h
+++ b/libheif/codecs/uncompressed/unc_encoder.h
@@ -23,6 +23,7 @@

 #include <memory>
 #include <vector>
+#include <map>

 #include "error.h"
 #include "codecs/encoder.h"
@@ -38,9 +39,9 @@ class Box_snuc;
 class Box_cloc;
 class HeifPixelImage;

-heif_uncompressed_component_type heif_channel_to_component_type(heif_channel channel);
+heif_unci_component_type heif_channel_to_component_type(heif_channel channel);

-heif_uncompressed_component_format to_unc_component_format(heif_channel_datatype channel_datatype);
+heif_uncompressed_component_format to_unc_component_format(heif_component_datatype channel_datatype);


 class unc_encoder
@@ -58,6 +59,8 @@ public:
   std::vector<std::shared_ptr<Box_snuc>> get_snuc() const { return m_snuc; }
   std::shared_ptr<Box_cloc> get_cloc() const { return m_cloc; }

+  // const std::map<uint32_t, uint32_t>& map_id_to_cmpd_index() { return m_map_id_to_cmpd_index; } // do we need this ?
+

   virtual uint64_t compute_tile_data_size_bytes(uint32_t tile_width, uint32_t tile_height) const = 0;

@@ -74,6 +77,8 @@ protected:
   std::vector<std::shared_ptr<Box_sbpm>> m_sbpm;
   std::vector<std::shared_ptr<Box_snuc>> m_snuc;
   std::shared_ptr<Box_cloc> m_cloc;
+
+  std::map<uint32_t, uint32_t> m_map_id_to_cmpd_index;
 };


diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
index d2cc3143..a161492b 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
@@ -90,16 +90,16 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
   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;
+    heif_unci_component_type comp_type;
     heif_channel ch = heif_channel_Y; // default for nonvisual

     if (is_nonvisual) {
-      comp_type = static_cast<heif_uncompressed_component_type>(image->get_component_type(idx));
+      comp_type = static_cast<heif_unci_component_type>(image->get_component_type(idx));
     }
     else {
       ch = image->get_component_channel(idx);
       if (ch == heif_channel_Y && !image->has_channel(heif_channel_Cb)) {
-        comp_type = heif_uncompressed_component_type_monochrome;
+        comp_type = heif_unci_component_type_monochrome;
       }
       else {
         comp_type = heif_channel_to_component_type(ch);
diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.h b/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
index db84e99b..834a093f 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
@@ -42,7 +42,7 @@ private:
   {
     uint32_t component_idx;
     heif_channel channel;
-    heif_uncompressed_component_type component_type;
+    heif_unci_component_type component_type;
     heif_uncompressed_component_format component_format;
     uint16_t bpp;
     bool byte_aligned;
diff --git a/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc
index 59ec4eaf..4e5062a7 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc
@@ -49,18 +49,18 @@ bool unc_encoder_factory_rgb_block_pixel_interleave::can_encode(const std::share


 std::unique_ptr<const unc_encoder> unc_encoder_factory_rgb_block_pixel_interleave::create(const std::shared_ptr<const HeifPixelImage>& image,
-                                                                                         const heif_encoding_options& options) const
+                                                                                          const heif_encoding_options& options) const
 {
   return std::make_unique<unc_encoder_rgb_block_pixel_interleave>(image, options);
 }


 unc_encoder_rgb_block_pixel_interleave::unc_encoder_rgb_block_pixel_interleave(const std::shared_ptr<const HeifPixelImage>& image,
-                                                                             const heif_encoding_options& options)
+                                                                               const heif_encoding_options& options)
     : unc_encoder(image)
 {
-  auto cmpd_idx = image->get_component_cmpd_indices_interleaved();
-  assert(cmpd_idx.size() == 3);
+  auto ids = image->get_component_ids_interleaved();
+  assert(ids.size() == 3);

   uint16_t bpp = image->get_bits_per_pixel(heif_channel_interleaved);

@@ -74,9 +74,9 @@ unc_encoder_rgb_block_pixel_interleave::unc_encoder_rgb_block_pixel_interleave(c
   m_uncC->set_sampling_type(sampling_mode_no_subsampling);
   m_uncC->set_block_little_endian(false);

-  m_uncC->add_component({cmpd_idx[0], bpp, component_format_unsigned, 0});
-  m_uncC->add_component({cmpd_idx[1], bpp, component_format_unsigned, 0});
-  m_uncC->add_component({cmpd_idx[2], bpp, component_format_unsigned, 0});
+  m_uncC->add_component({m_map_id_to_cmpd_index.find(ids[0])->second, bpp, component_format_unsigned, 0});
+  m_uncC->add_component({m_map_id_to_cmpd_index.find(ids[1])->second, bpp, component_format_unsigned, 0});
+  m_uncC->add_component({m_map_id_to_cmpd_index.find(ids[2])->second, bpp, component_format_unsigned, 0});
 }


diff --git a/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.h b/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.h
index 085c9f3d..170a5554 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.h
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.h
@@ -25,12 +25,14 @@

 #include <memory>
 #include <vector>
+#include <map>
+

 class unc_encoder_rgb_block_pixel_interleave : public unc_encoder
 {
 public:
   unc_encoder_rgb_block_pixel_interleave(const std::shared_ptr<const HeifPixelImage>& image,
-                                        const heif_encoding_options& options);
+                                         const heif_encoding_options& options);

   uint64_t compute_tile_data_size_bytes(uint32_t tile_width, uint32_t tile_height) const override;

diff --git a/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc
index c337f643..c46cd7b8 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc
@@ -59,12 +59,12 @@ unc_encoder_rgb_bytealign_pixel_interleave::unc_encoder_rgb_bytealign_pixel_inte
                                        const heif_encoding_options& options)
     : unc_encoder(image)
 {
-  auto cmpd_idx = image->get_component_cmpd_indices_interleaved();
+  auto cmpd_ids = image->get_component_ids_interleaved();

   bool save_alpha = image->has_alpha();

   m_bytes_per_pixel = save_alpha ? 8 : 6;
-  assert(cmpd_idx.size() == m_bytes_per_pixel/2);
+  assert(cmpd_ids.size() == m_bytes_per_pixel/2);

   bool little_endian = (image->get_chroma_format() == heif_chroma_interleaved_RRGGBB_LE ||
                         image->get_chroma_format() == heif_chroma_interleaved_RRGGBBAA_LE);
@@ -84,11 +84,11 @@ unc_encoder_rgb_bytealign_pixel_interleave::unc_encoder_rgb_bytealign_pixel_inte
   m_uncC->set_components_little_endian(false); // little_endian);
   m_uncC->set_pixel_size(m_bytes_per_pixel);

-  m_uncC->add_component({cmpd_idx[0], bpp, component_format_unsigned, component_align_size});
-  m_uncC->add_component({cmpd_idx[1], bpp, component_format_unsigned, component_align_size});
-  m_uncC->add_component({cmpd_idx[2], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[0]], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[1]], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[2]], bpp, component_format_unsigned, component_align_size});
   if (save_alpha) {
-    m_uncC->add_component({cmpd_idx[3], bpp, component_format_unsigned, component_align_size});
+    m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[3]], bpp, component_format_unsigned, component_align_size});
   }
 }

diff --git a/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc
index 484ac5ef..eb4e6a3b 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc
@@ -55,11 +55,11 @@ unc_encoder_rgb_pixel_interleave::unc_encoder_rgb_pixel_interleave(const std::sh
                                              const heif_encoding_options& options)
     : unc_encoder(image)
 {
-  auto cmpd_idx = image->get_component_cmpd_indices_interleaved();
+  auto cmpd_ids = image->get_component_ids_interleaved();
   bool save_alpha = image->has_alpha();

   m_bytes_per_pixel = save_alpha ? 4 : 3;
-  assert(cmpd_idx.size() == m_bytes_per_pixel);
+  assert(cmpd_ids.size() == m_bytes_per_pixel);

   uint16_t bpp = image->get_bits_per_pixel(heif_channel_interleaved);

@@ -79,11 +79,11 @@ unc_encoder_rgb_pixel_interleave::unc_encoder_rgb_pixel_interleave(const std::sh

   m_uncC->set_interleave_type(interleave_mode_pixel);
   m_uncC->set_sampling_type(sampling_mode_no_subsampling);
-  m_uncC->add_component({cmpd_idx[0], bpp, component_format_unsigned, component_align_size});
-  m_uncC->add_component({cmpd_idx[1], bpp, component_format_unsigned, component_align_size});
-  m_uncC->add_component({cmpd_idx[2], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[0]], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[1]], bpp, component_format_unsigned, component_align_size});
+  m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[2]], bpp, component_format_unsigned, component_align_size});
   if (save_alpha) {
-    m_uncC->add_component({cmpd_idx[3], bpp, component_format_unsigned, component_align_size});
+    m_uncC->add_component({m_map_id_to_cmpd_index[cmpd_ids[3]], bpp, component_format_unsigned, component_align_size});
   }
 }

diff --git a/libheif/codecs/uncompressed/unc_types.h b/libheif/codecs/uncompressed/unc_types.h
index 7dfb16c0..f5de9fef 100644
--- a/libheif/codecs/uncompressed/unc_types.h
+++ b/libheif/codecs/uncompressed/unc_types.h
@@ -26,7 +26,7 @@
 #include <libheif/heif_uncompressed.h>

 // Update this when adding new values to heif_uncompressed_component_type.
-#define heif_uncompressed_component_type_max_valid heif_uncompressed_component_type_key_black
+#define heif_unci_component_type_max_valid heif_unci_component_type_key_black

 /**
  * HEIF uncompressed component format.
diff --git a/libheif/color-conversion/bayer_bilinear.cc b/libheif/color-conversion/bayer_bilinear.cc
index 9e0ef309..210e1be2 100644
--- a/libheif/color-conversion/bayer_bilinear.cc
+++ b/libheif/color-conversion/bayer_bilinear.cc
@@ -65,11 +65,11 @@ Op_bayer_bilinear_to_RGB24_32::state_after_conversion(const ColorState& input_st
 static int component_type_to_rgb_index(uint16_t component_type)
 {
   switch (component_type) {
-    case heif_uncompressed_component_type_red:
+    case heif_unci_component_type_red:
       return 0;
-    case heif_uncompressed_component_type_green:
+    case heif_unci_component_type_green:
       return 1;
-    case heif_uncompressed_component_type_blue:
+    case heif_unci_component_type_blue:
       return 2;
     default:
       return -1;
@@ -88,11 +88,11 @@ Op_bayer_bilinear_to_RGB24_32::convert_colorspace(const std::shared_ptr<const He
   uint32_t width = input->get_width();
   uint32_t height = input->get_height();

-  if (!input->has_bayer_pattern()) {
+  if (!input->has_any_bayer_pattern()) {
     return Error::InternalError;
   }

-  const BayerPattern& pattern = input->get_bayer_pattern();
+  const BayerPattern& pattern = input->get_any_bayer_pattern();
   uint16_t pw = pattern.pattern_width;
   uint16_t ph = pattern.pattern_height;

@@ -122,7 +122,7 @@ Op_bayer_bilinear_to_RGB24_32::convert_colorspace(const std::shared_ptr<const He
   // Build a lookup table: for each pattern position, which RGB channel (0=R,1=G,2=B) does it provide?
   std::vector<int> pattern_channel(pw * ph);
   for (int i = 0; i < pw * ph; i++) {
-    uint16_t comp_type = input->get_component_type(pattern.pixels[i].component_index);
+    uint16_t comp_type = input->get_component_type(pattern.pixels[i].component_id);
     pattern_channel[i] = component_type_to_rgb_index(comp_type);
     if (pattern_channel[i] < 0) {
       return Error(heif_error_Unsupported_feature,
diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index aec45672..55c5e4f5 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -100,29 +100,29 @@ uint32_t channel_height(uint32_t h, heif_chroma chroma, heif_channel channel)
 heif_channel map_uncompressed_component_to_channel(uint16_t component_type)
 {
   switch (component_type) {
-    case heif_uncompressed_component_type_monochrome:
-    case heif_uncompressed_component_type_Y:
+    case heif_unci_component_type_monochrome:
+    case heif_unci_component_type_Y:
       return heif_channel_Y;
-    case heif_uncompressed_component_type_Cb:
+    case heif_unci_component_type_Cb:
       return heif_channel_Cb;
-    case heif_uncompressed_component_type_Cr:
+    case heif_unci_component_type_Cr:
       return heif_channel_Cr;
-    case heif_uncompressed_component_type_red:
+    case heif_unci_component_type_red:
       return heif_channel_R;
-    case heif_uncompressed_component_type_green:
+    case heif_unci_component_type_green:
       return heif_channel_G;
-    case heif_uncompressed_component_type_blue:
+    case heif_unci_component_type_blue:
       return heif_channel_B;
-    case heif_uncompressed_component_type_alpha:
+    case heif_unci_component_type_alpha:
       return heif_channel_Alpha;
-    case heif_uncompressed_component_type_filter_array:
+    case heif_unci_component_type_filter_array:
       return heif_channel_filter_array;
-    case heif_uncompressed_component_type_depth:
+    case heif_unci_component_type_depth:
       return heif_channel_depth;
-    case heif_uncompressed_component_type_disparity:
+    case heif_unci_component_type_disparity:
       return heif_channel_disparity;

-    case heif_uncompressed_component_type_padded:
+    case heif_unci_component_type_padded:
     default:
       return heif_channel_unknown;
   }
@@ -133,43 +133,43 @@ static std::vector<uint16_t> map_channel_to_component_type(heif_channel channel,
 {
   switch (channel) {
     case heif_channel_Y:
-      return {heif_uncompressed_component_type_Y};
+      return {heif_unci_component_type_Y};
     case heif_channel_Cb:
-      return {heif_uncompressed_component_type_Cb};
+      return {heif_unci_component_type_Cb};
     case heif_channel_Cr:
-      return {heif_uncompressed_component_type_Cr};
+      return {heif_unci_component_type_Cr};
     case heif_channel_R:
-      return {heif_uncompressed_component_type_red};
+      return {heif_unci_component_type_red};
     case heif_channel_G:
-      return {heif_uncompressed_component_type_green};
+      return {heif_unci_component_type_green};
     case heif_channel_B:
-      return {heif_uncompressed_component_type_blue};
+      return {heif_unci_component_type_blue};
     case heif_channel_Alpha:
-      return {heif_uncompressed_component_type_alpha};
+      return {heif_unci_component_type_alpha};
     case heif_channel_filter_array:
-      return {heif_uncompressed_component_type_filter_array};
+      return {heif_unci_component_type_filter_array};
     case heif_channel_depth:
-      return {heif_uncompressed_component_type_depth};
+      return {heif_unci_component_type_depth};
     case heif_channel_disparity:
-      return {heif_uncompressed_component_type_disparity};
+      return {heif_unci_component_type_disparity};
     case heif_channel_interleaved:
       switch (chroma) {
         case heif_chroma_interleaved_RGB:
         case heif_chroma_interleaved_RRGGBB_BE:
         case heif_chroma_interleaved_RRGGBB_LE:
           return {
-            heif_uncompressed_component_type_red,
-            heif_uncompressed_component_type_green,
-            heif_uncompressed_component_type_blue
+            heif_unci_component_type_red,
+            heif_unci_component_type_green,
+            heif_unci_component_type_blue
           };
         case heif_chroma_interleaved_RGBA:
         case heif_chroma_interleaved_RRGGBBAA_BE:
         case heif_chroma_interleaved_RRGGBBAA_LE:
           return {
-            heif_uncompressed_component_type_red,
-            heif_uncompressed_component_type_green,
-            heif_uncompressed_component_type_blue,
-            heif_uncompressed_component_type_alpha
+            heif_unci_component_type_red,
+            heif_unci_component_type_green,
+            heif_unci_component_type_blue,
+            heif_unci_component_type_alpha
           };
         default:
           assert(false);
@@ -184,6 +184,51 @@ static std::vector<uint16_t> map_channel_to_component_type(heif_channel channel,
 }


+BayerPatternCmpd BayerPattern::resolve_to_cmpd(std::map<uint32_t, uint32_t> comp_id_to_cmap) const
+{
+  BayerPatternCmpd cpat;
+  cpat.pattern_width = pattern_width;
+  cpat.pattern_height = pattern_height;
+
+  for (auto p : pixels) {
+    cpat.pixels.push_back({comp_id_to_cmap[p.component_id], p.component_gain});
+  }
+
+  return cpat;
+}
+
+
+static void remove_duplicates(std::vector<uint32_t>& v)
+{
+  std::sort(v.begin(), v.end());
+  v.erase(std::unique(v.begin(), v.end()), v.end());
+}
+
+
+std::vector<uint32_t> map_component_ids_to_cmpd(const std::vector<uint32_t>& component_ids, const std::map<uint32_t, uint32_t>& comp_id_to_cmpd)
+{
+  std::vector<uint32_t> cmpd_indices;
+
+  for (uint32_t comp_id : component_ids) {
+    cmpd_indices.push_back(comp_id_to_cmpd.find(comp_id)->second);
+  }
+
+  remove_duplicates(cmpd_indices);
+
+  return cmpd_indices;
+}
+
+std::vector<uint32_t> map_cmpd_to_component_ids(const std::vector<uint32_t>& cmpd_indices, const std::vector<std::vector<uint32_t>>& cmpd_to_comp_ids)
+{
+  std::vector<uint32_t> component_ids;
+
+  for (uint32_t idx : cmpd_indices) {
+    component_ids.insert(component_ids.end(), cmpd_to_comp_ids[idx].begin(), cmpd_to_comp_ids[idx].end());
+  }
+
+  return component_ids;
+}
+

 ImageExtraData::~ImageExtraData()
 {
@@ -504,10 +549,11 @@ HeifPixelImage::ImageComponent HeifPixelImage::new_image_plane_for_channel(heif_
   // ISO 23001-17 component types
   // For interleaved planes, several component types are added to cmpd

-  auto cmpd = map_channel_to_component_type(channel, m_chroma);
-  for (size_t i = 0; i < cmpd.size(); i++) {
-    plane.m_component_index.push_back(static_cast<uint32_t>(m_cmpd_component_types.size()));
-    m_cmpd_component_types.push_back(cmpd[i]);
+  auto component_types = map_channel_to_component_type(channel, m_chroma);
+  for (auto type : component_types) {
+    plane.m_component_ids.push_back(m_next_component_id);
+    m_component_types[m_next_component_id] = type;
+    m_next_component_id++;
   }

   return plane;
@@ -531,7 +577,7 @@ Error HeifPixelImage::add_plane(heif_channel channel, uint32_t width, uint32_t h
     bit_depth = 8;
   }

-  if (auto err = plane.alloc(width, height, heif_channel_datatype_unsigned_integer, bit_depth, num_interleaved_pixels, limits, m_memory_handle)) {
+  if (auto err = plane.alloc(width, height, heif_component_datatype_unsigned_integer, bit_depth, num_interleaved_pixels, limits, m_memory_handle)) {
     return err;
   }
   else {
@@ -541,7 +587,7 @@ Error HeifPixelImage::add_plane(heif_channel channel, uint32_t width, uint32_t h
 }


-Error HeifPixelImage::add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
+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);
@@ -556,7 +602,7 @@ Error HeifPixelImage::add_channel(heif_channel channel, uint32_t width, uint32_t
 }


-Error HeifPixelImage::ImageComponent::alloc(uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
+Error HeifPixelImage::ImageComponent::alloc(uint32_t width, uint32_t height, heif_component_datatype datatype, int bit_depth,
                                         int num_interleaved_components,
                                         const heif_security_limits* limits,
                                         MemoryHandle& memory_handle)
@@ -840,7 +886,7 @@ uint32_t HeifPixelImage::get_height(enum heif_channel channel) const

 uint32_t HeifPixelImage::get_width(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   if (!comp) {
     return 0;
   }
@@ -851,7 +897,7 @@ uint32_t HeifPixelImage::get_width(uint32_t component_idx) const

 uint32_t HeifPixelImage::get_height(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   if (!comp) {
     return 0;
   }
@@ -872,7 +918,7 @@ uint32_t HeifPixelImage::get_primary_component() const
       case heif_channel_G:
       case heif_channel_B:
       case heif_channel_filter_array:
-        return m_planes[idx].m_component_index[0];
+        return m_planes[idx].m_component_ids[0];
       default:
         ; // NOP
     }
@@ -880,35 +926,34 @@ uint32_t HeifPixelImage::get_primary_component() const

   // second pass: if we have a cmpd table, use component types

-  if (!m_cmpd_component_types.empty()) {
-    for (uint32_t idx=0; idx<m_planes.size(); idx++) {
-      uint16_t comp_type = get_component_type(m_planes[idx].m_component_index[0]);
-      switch (comp_type) {
-        case heif_uncompressed_component_type_Y:
-        case heif_uncompressed_component_type_monochrome:
-        case heif_uncompressed_component_type_red:
-        case heif_uncompressed_component_type_green:
-        case heif_uncompressed_component_type_blue:
-        case heif_uncompressed_component_type_cyan:
-        case heif_uncompressed_component_type_magenta:
-        case heif_uncompressed_component_type_yellow:
-        case heif_uncompressed_component_type_key_black:
-        case heif_uncompressed_component_type_filter_array:
-        case heif_uncompressed_component_type_palette:
-          return m_planes[idx].m_component_index[0];
+  for (uint32_t idx = 0; idx < m_planes.size(); idx++) {
+    uint16_t comp_type = get_component_type(m_planes[idx].m_component_ids[0]);
+    switch (comp_type) {
+      case heif_unci_component_type_Y:
+      case heif_unci_component_type_monochrome:
+      case heif_unci_component_type_red:
+      case heif_unci_component_type_green:
+      case heif_unci_component_type_blue:
+      case heif_unci_component_type_cyan:
+      case heif_unci_component_type_magenta:
+      case heif_unci_component_type_yellow:
+      case heif_unci_component_type_key_black:
+      case heif_unci_component_type_filter_array:
+      case heif_unci_component_type_palette:
+        return m_planes[idx].m_component_ids[0];

-        default:
-          ; // NOP
-      }
+      default:
+        ; // NOP
     }
   }

   // third pass: allow anything

   if (!m_planes.empty()) {
-    return m_planes[0].m_component_index[0];
+    return m_planes[0].m_component_ids[0];
   }
-  return 0;
+
+  return heif_unci_component_type_UNDEFINED;
 }
 #if 0
 uint32_t HeifPixelImage::get_primary_width() const
@@ -1015,11 +1060,11 @@ uint16_t HeifPixelImage::get_visual_image_bits_per_pixel() const
 }


-heif_channel_datatype HeifPixelImage::get_datatype(enum heif_channel channel) const
+heif_component_datatype HeifPixelImage::get_datatype(enum heif_channel channel) const
 {
   auto* comp = find_component_for_channel(channel);
   if (!comp) {
-    return heif_channel_datatype_undefined;
+    return heif_component_datatype_undefined;
   }

   return comp->m_datatype;
@@ -2104,9 +2149,6 @@ Error HeifPixelImage::create_clone_image_at_new_size(const std::shared_ptr<const

   create(w, h, colorspace, chroma);

-  // Copy the cmpd component type table (needed for nonvisual/component images)
-  m_cmpd_component_types = source->m_cmpd_component_types;
-
   for (const auto& src_plane : source->m_planes) {
     // TODO: do we also support images where some planes (e.g. the alpha-plane) have a different size than the main image?
     //       We could do this by scaling all planes proportionally. This would also handle chroma channels implicitly.
@@ -2115,7 +2157,8 @@ Error HeifPixelImage::create_clone_image_at_new_size(const std::shared_ptr<const

     ImageComponent plane;
     plane.m_channel = src_plane.m_channel;
-    plane.m_component_index = src_plane.m_component_index;
+    plane.m_component_ids = src_plane.m_component_ids;
+
     if (auto err = plane.alloc(plane_w, plane_h, src_plane.m_datatype, src_plane.m_bit_depth,
                                src_plane.m_num_interleaved_components, limits, m_memory_handle)) {
       return err;
@@ -2124,6 +2167,8 @@ Error HeifPixelImage::create_clone_image_at_new_size(const std::shared_ptr<const
     m_planes.push_back(plane);
   }

+  m_component_types = source->m_component_types;
+
   return Error::Ok;
 }

@@ -2189,13 +2234,13 @@ HeifPixelImage::extract_image_area(uint32_t x0, uint32_t y0, uint32_t w, uint32_

 // --- index-based component access methods

-HeifPixelImage::ImageComponent* HeifPixelImage::find_component_by_index(uint32_t component_index)
+HeifPixelImage::ImageComponent* HeifPixelImage::find_component_by_id(uint32_t component_index)
 {
   for (auto& plane : m_planes) {
     // we search through all indices in case we have an interleaved plane
-    if (std::find(plane.m_component_index.begin(),
-                  plane.m_component_index.end(),
-                  component_index) != plane.m_component_index.end()) {
+    if (std::find(plane.m_component_ids.begin(),
+                  plane.m_component_ids.end(),
+                  component_index) != plane.m_component_ids.end()) {
       return &plane;
     }
   }
@@ -2203,15 +2248,15 @@ HeifPixelImage::ImageComponent* HeifPixelImage::find_component_by_index(uint32_t
 }


-const HeifPixelImage::ImageComponent* HeifPixelImage::find_component_by_index(uint32_t component_index) const
+const HeifPixelImage::ImageComponent* HeifPixelImage::find_component_by_id(uint32_t component_index) const
 {
-  return const_cast<HeifPixelImage*>(this)->find_component_by_index(component_index);
+  return const_cast<HeifPixelImage*>(this)->find_component_by_id(component_index);
 }


 heif_channel HeifPixelImage::get_component_channel(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   return comp->m_channel;
 }
@@ -2219,7 +2264,7 @@ heif_channel HeifPixelImage::get_component_channel(uint32_t component_idx) const

 uint32_t HeifPixelImage::get_component_width(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   return comp->m_width;
 }
@@ -2227,7 +2272,7 @@ uint32_t HeifPixelImage::get_component_width(uint32_t component_idx) const

 uint32_t HeifPixelImage::get_component_height(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   return comp->m_height;
 }
@@ -2235,7 +2280,7 @@ uint32_t HeifPixelImage::get_component_height(uint32_t component_idx) const

 uint16_t HeifPixelImage::get_component_bits_per_pixel(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   return comp->m_bit_depth;
 }
@@ -2243,7 +2288,7 @@ uint16_t HeifPixelImage::get_component_bits_per_pixel(uint32_t component_idx) co

 uint16_t HeifPixelImage::get_component_storage_bits_per_pixel(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   uint32_t bpp = comp->get_bytes_per_pixel() * 8;
   assert(bpp);
@@ -2251,55 +2296,58 @@ uint16_t HeifPixelImage::get_component_storage_bits_per_pixel(uint32_t component
 }


-heif_channel_datatype HeifPixelImage::get_component_datatype(uint32_t component_idx) const
+heif_component_datatype HeifPixelImage::get_component_datatype(uint32_t component_idx) const
 {
-  auto* comp = find_component_by_index(component_idx);
+  auto* comp = find_component_by_id(component_idx);
   assert(comp);
   return comp->m_datatype;
 }


-uint16_t HeifPixelImage::get_component_type(uint32_t component_idx) const
+uint16_t HeifPixelImage::get_component_type(uint32_t component_id) const
 {
-  if (component_idx >= m_cmpd_component_types.size()) {
-    return 0;
+  auto iter = m_component_types.find(component_id);
+  if (iter == m_component_types.end()) {
+    return heif_unci_component_type_UNDEFINED;
   }
-  return m_cmpd_component_types[component_idx];
+
+  return iter->second;
 }


-std::vector<uint32_t> HeifPixelImage::get_component_cmpd_indices_interleaved() const
+std::vector<uint32_t> HeifPixelImage::get_component_ids_interleaved() const
 {
   const ImageComponent* comp = find_component_for_channel(heif_channel_interleaved);
   assert(comp);
-  return comp->m_component_index;
+  return comp->m_component_ids;
 }


 Result<uint32_t> HeifPixelImage::add_component(uint32_t width, uint32_t height,
                                                uint16_t component_type,
-                                               heif_channel_datatype datatype, int bit_depth,
+                                               heif_component_datatype datatype, int bit_depth,
                                                const heif_security_limits* limits)
 {
   // Auto-generate component_index by appending to cmpd table
-  uint32_t component_index = static_cast<uint32_t>(m_cmpd_component_types.size());
-  m_cmpd_component_types.push_back(component_type);
+  uint32_t component_id = m_next_component_id++;
+  m_component_types[component_id] = component_type;

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

   m_planes.push_back(plane);
-  return component_index;
+  return component_id;
 }


+#if 0
 Result<uint32_t> HeifPixelImage::add_component_for_index(uint32_t component_index,
                                                           uint32_t width, uint32_t height,
-                                                          heif_channel_datatype datatype, int bit_depth,
+                                                          heif_component_datatype datatype, int bit_depth,
                                                           const heif_security_limits* limits)
 {
   if (component_index >= m_cmpd_component_types.size()) {
@@ -2319,15 +2367,18 @@ Result<uint32_t> HeifPixelImage::add_component_for_index(uint32_t component_inde
   m_planes.push_back(plane);
   return component_index;
 }
+#endif


-std::vector<uint32_t> HeifPixelImage::get_used_component_indices() const
+std::vector<uint32_t> HeifPixelImage::get_used_component_ids() const
 {
   std::vector<uint32_t> indices;
-  indices.reserve(m_planes.size());
-  for (const auto& plane : m_planes) {
-    indices.insert(indices.end(), plane.m_component_index.begin(), plane.m_component_index.end());
+  indices.reserve(m_component_types.size());
+
+  for (const auto& iter : m_component_types) {
+    indices.push_back(iter.first);
   }
+
   return indices;
 }

diff --git a/libheif/pixelimage.h b/libheif/pixelimage.h
index 40c7b92a..c19dd8af 100644
--- a/libheif/pixelimage.h
+++ b/libheif/pixelimage.h
@@ -41,16 +41,37 @@
 #include <cassert>
 #include <string>

+constexpr uint16_t heif_unci_component_type_UNDEFINED = 0xFFFF;
+
+
+struct bayer_pattern_pixel_cmpd
+{
+  uint32_t cmpd_index;
+  float component_gain;
+};
+
+struct BayerPatternCmpd
+{
+  uint16_t pattern_width = 0;
+  uint16_t pattern_height = 0;
+  std::vector<bayer_pattern_pixel_cmpd> pixels;
+};
+
 struct BayerPattern
 {
   uint16_t pattern_width = 0;
   uint16_t pattern_height = 0;
   std::vector<heif_bayer_pattern_pixel> pixels;
+
+  BayerPatternCmpd resolve_to_cmpd(std::map<uint32_t, uint32_t> comp_id_to_cmap) const;
 };

+std::vector<uint32_t> map_component_ids_to_cmpd(const std::vector<uint32_t>& component_ids, const std::map<uint32_t, uint32_t>& comp_id_to_cmpd);
+std::vector<uint32_t> map_cmpd_to_component_ids(const std::vector<uint32_t>& cmpd_indices, const std::vector<std::vector<uint32_t>>& cmpd_to_comp_ids);
+
 struct PolarizationPattern
 {
-  std::vector<uint32_t> component_indices;  // empty = applies to all components
+  std::vector<uint32_t> component_ids;  // empty = applies to all components. Either cmpd-index or component-id, depending on context.
   uint16_t pattern_width = 0;
   uint16_t pattern_height = 0;
   std::vector<float> polarization_angles;   // pattern_width * pattern_height entries
@@ -59,17 +80,21 @@ struct PolarizationPattern

 struct SensorBadPixelsMap
 {
-  std::vector<uint32_t> component_indices;  // empty = applies to all components
+  struct BadPixelCoordinate
+  {
+    uint32_t row, column;
+  };
+
+  std::vector<uint32_t> component_ids;  // empty = applies to all components. Either cmpd-index or component-id, depending on context.
   bool correction_applied = false;
   std::vector<uint32_t> bad_rows;
   std::vector<uint32_t> bad_columns;
-  struct BadPixel { uint32_t row; uint32_t column; };
-  std::vector<BadPixel> bad_pixels;
+  std::vector<BadPixelCoordinate> bad_pixels;
 };

 struct SensorNonUniformityCorrection
 {
-  std::vector<uint32_t> component_indices;  // empty = applies to all components
+  std::vector<uint32_t> component_ids;  // empty = applies to all components. Either cmpd-index or component-id, depending on context.
   bool nuc_is_applied = false;
   uint32_t image_width = 0;
   uint32_t image_height = 0;
@@ -213,12 +238,19 @@ public:

   // --- bayer pattern

-  bool has_bayer_pattern() const { return m_bayer_pattern.has_value(); }
+  bool has_bayer_pattern(uint32_t component_id) const { return m_bayer_pattern.has_value(); }
+
+  bool has_any_bayer_pattern() const { return m_bayer_pattern.has_value(); }

-  const BayerPattern& get_bayer_pattern() const { assert(has_bayer_pattern()); return *m_bayer_pattern; }
+  const BayerPattern& get_bayer_pattern(uint32_t component_id) const { assert(has_bayer_pattern(component_id)); return *m_bayer_pattern; }
+
+  const BayerPattern& get_any_bayer_pattern() const { assert(has_any_bayer_pattern()); return *m_bayer_pattern; }

   virtual void set_bayer_pattern(const BayerPattern& pattern) { m_bayer_pattern = pattern; }

+  // TODO: replace uint16_t component_type with class that also handled the std::string type
+  uint32_t add_component_without_data(uint16_t component_type) { assert(false); /*TODO*/ }
+

   // --- polarization pattern

@@ -342,7 +374,7 @@ public:

   Error add_plane(heif_channel channel, uint32_t width, uint32_t height, int bit_depth, const heif_security_limits* limits);

-  Error add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
+  Error add_channel(heif_channel channel, uint32_t width, uint32_t height, heif_component_datatype datatype, int bit_depth,
                     const heif_security_limits* limits);

   bool has_channel(heif_channel channel) const;
@@ -387,7 +419,7 @@ public:
   // Get the maximum bit depth of a visual channel (YCbCr or RGB).
   uint16_t get_visual_image_bits_per_pixel() const;

-  heif_channel_datatype get_datatype(heif_channel channel) const;
+  heif_component_datatype get_datatype(heif_channel channel) const;

   int get_number_of_interleaved_components(heif_channel channel) const;

@@ -423,11 +455,11 @@ public:
   }


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

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

-  uint32_t get_total_number_of_cmpd_components() const { return static_cast<uint32_t>(m_cmpd_component_types.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;

@@ -435,37 +467,39 @@ public:
   uint32_t get_component_height(uint32_t component_idx) const;
   uint16_t get_component_bits_per_pixel(uint32_t component_idx) const;
   uint16_t get_component_storage_bits_per_pixel(uint32_t component_idx) const;
-  heif_channel_datatype get_component_datatype(uint32_t component_idx) const;
+  heif_component_datatype get_component_datatype(uint32_t component_idx) const;

   // Look up the component type from the cmpd table. Works for any cmpd index,
   // even those that have no image plane (e.g. bayer reference components).
   uint16_t get_component_type(uint32_t component_idx) const;

-  std::vector<uint16_t> get_cmpd_component_types() const { return m_cmpd_component_types; }
+  //std::vector<uint16_t> get_cmpd_component_types() const { return m_cmpd_component_types; }

-  std::vector<uint32_t> get_component_cmpd_indices_interleaved() const;
+  std::vector<uint32_t> get_component_ids_interleaved() const;

-  uint32_t get_component_cmpd_index() const { assert(m_cmpd_component_types.size()==1); return m_cmpd_component_types[0]; }
+  //uint32_t get_component_cmpd_index() const { assert(m_cmpd_component_types.size()==1); return m_cmpd_component_types[0]; }

   // Encoder path: auto-generates component_index by appending to cmpd table.
   Result<uint32_t> add_component(uint32_t width, uint32_t height,
                                  uint16_t component_type,
-                                 heif_channel_datatype datatype, int bit_depth,
+                                 heif_component_datatype datatype, int bit_depth,
                                  const heif_security_limits* limits);

   // Decoder path: uses a pre-populated cmpd table to look up the component type.
+#if 0
   Result<uint32_t> add_component_for_index(uint32_t component_index,
                                             uint32_t width, uint32_t height,
-                                            heif_channel_datatype datatype, int bit_depth,
+                                            heif_component_datatype datatype, int bit_depth,
                                             const heif_security_limits* limits);
+#endif

   // 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); }
+  //void set_cmpd_component_types(std::vector<uint16_t> types) { m_cmpd_component_types = std::move(types); }

-  const std::vector<uint16_t>& get_cmpd_component_types() { return m_cmpd_component_types; }
+  //const std::vector<uint16_t>& get_cmpd_component_types() { return m_cmpd_component_types; }

   // Returns the sorted list of component_indices of all planes that have pixel data.
-  std::vector<uint32_t> get_used_component_indices() const;
+  std::vector<uint32_t> get_used_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;
@@ -473,7 +507,7 @@ public:
   template <typename T>
   T* get_component_data(uint32_t component_idx, size_t* out_stride)
   {
-    auto* comp = find_component_by_index(component_idx);
+    auto* comp = find_component_by_id(component_idx);
     if (!comp) {
       if (out_stride) *out_stride = 0;
       return nullptr;
@@ -558,15 +592,15 @@ private:

     // index into the cmpd component definition table
     // Interleaved channels will have a list of indices in the order R,G,B,A
-    std::vector<uint32_t> m_component_index;
+    std::vector<uint32_t> m_component_ids;

     // limits=nullptr disables the limits
-    Error alloc(uint32_t width, uint32_t height, heif_channel_datatype datatype, int bit_depth,
+    Error alloc(uint32_t width, uint32_t height, heif_component_datatype datatype, int bit_depth,
                 int num_interleaved_components,
                 const heif_security_limits* limits,
                 MemoryHandle& memory_handle);

-    heif_channel_datatype m_datatype = heif_channel_datatype_unsigned_integer;
+    heif_component_datatype m_datatype = heif_component_datatype_unsigned_integer;

     // logical bit depth per component
     // For interleaved formats, it is the number of bits for one component.
@@ -600,8 +634,8 @@ private:
   ImageComponent* find_component_for_channel(heif_channel channel);
   const ImageComponent* find_component_for_channel(heif_channel channel) const;

-  ImageComponent* find_component_by_index(uint32_t component_index);
-  const ImageComponent* find_component_by_index(uint32_t component_index) const;
+  ImageComponent* find_component_by_id(uint32_t component_index);
+  const ImageComponent* find_component_by_id(uint32_t component_index) const;

   ImageComponent new_image_plane_for_channel(heif_channel channel);

@@ -611,11 +645,16 @@ private:
   heif_chroma m_chroma = heif_chroma_undefined;

   std::vector<ImageComponent> m_planes;
-  std::vector<uint16_t> m_cmpd_component_types;  // indexed by cmpd index
+  //std::vector<uint16_t> m_cmpd_component_types;  // indexed by cmpd index
   MemoryHandle m_memory_handle;

+  // maps component_id to component_type (for all components, including cpat and all components in an interleaved plane)
+  std::map<uint32_t, uint16_t> m_component_types;
+
   uint32_t m_sample_duration = 0; // duration of a sequence frame

+  uint32_t m_next_component_id = 1;
+
   std::vector<Error> m_warnings;
 };

diff --git a/libheif/sequences/track_visual.cc b/libheif/sequences/track_visual.cc
index ee982a26..3c3f11ad 100644
--- a/libheif/sequences/track_visual.cc
+++ b/libheif/sequences/track_visual.cc
@@ -158,7 +158,7 @@ bool Track_Visual::has_alpha_channel() const
     if (sampleEntry) {
       if (auto box_uncv = std::dynamic_pointer_cast<const Box_uncv>(sampleEntry)) {
         if (auto cmpd = box_uncv->get_child_box<const Box_cmpd>()) {
-          if (cmpd->has_component(heif_uncompressed_component_type_alpha)) {
+          if (cmpd->has_component(heif_unci_component_type_alpha)) {
             return true;
           }
         }
diff --git a/tests/pixel_data_types.cc b/tests/pixel_data_types.cc
index e57ce733..244295c2 100644
--- a/tests/pixel_data_types.cc
+++ b/tests/pixel_data_types.cc
@@ -33,7 +33,7 @@ TEST_CASE( "uint32_t" )

   auto* limits = heif_get_global_security_limits();
   image.create(3,2, heif_colorspace_nonvisual, heif_chroma_undefined);
-  image.add_channel(heif_channel_Y, 3,2, heif_channel_datatype_unsigned_integer, 32, limits);
+  image.add_channel(heif_channel_Y, 3,2, heif_component_datatype_unsigned_integer, 32, limits);

   size_t stride;
   uint32_t* data = image.get_channel<uint32_t>(heif_channel_Y, &stride);
@@ -43,7 +43,7 @@ TEST_CASE( "uint32_t" )
   REQUIRE(image.get_height(heif_channel_Y) == 2);
   REQUIRE(image.get_bits_per_pixel(heif_channel_Y) == 32);
   REQUIRE(image.get_storage_bits_per_pixel(heif_channel_Y) == 32);
-  REQUIRE(image.get_datatype(heif_channel_Y) == heif_channel_datatype_unsigned_integer);
+  REQUIRE(image.get_datatype(heif_channel_Y) == heif_component_datatype_unsigned_integer);
   REQUIRE(image.get_number_of_interleaved_components(heif_channel_Y) == 1);

   data[0*stride + 0] = 0;
@@ -128,7 +128,7 @@ TEST_CASE( "complex64_t" )

   auto* limits = heif_get_global_security_limits();
   image.create(3,2, heif_colorspace_nonvisual, heif_chroma_undefined);
-  image.add_channel(heif_channel_Y, 3,2, heif_channel_datatype_complex_number, 128, limits);
+  image.add_channel(heif_channel_Y, 3,2, heif_component_datatype_complex_number, 128, limits);

   size_t stride;
   heif_complex64* data = image.get_channel<heif_complex64>(heif_channel_Y, &stride);
@@ -138,7 +138,7 @@ TEST_CASE( "complex64_t" )
   REQUIRE(image.get_height(heif_channel_Y) == 2);
   REQUIRE(image.get_bits_per_pixel(heif_channel_Y) == 128);
   REQUIRE(image.get_storage_bits_per_pixel(heif_channel_Y) == 128);
-  REQUIRE(image.get_datatype(heif_channel_Y) == heif_channel_datatype_complex_number);
+  REQUIRE(image.get_datatype(heif_channel_Y) == heif_component_datatype_complex_number);
   REQUIRE(image.get_number_of_interleaved_components(heif_channel_Y) == 1);

   data[0*stride + 0] = {0.0, -1.0};
@@ -160,7 +160,7 @@ TEST_CASE( "image datatype through public API" )
   REQUIRE(!error.code);

   uint32_t comp_idx;
-  error = heif_image_add_component(image, 3, 2, 0, heif_channel_datatype_unsigned_integer, 32, &comp_idx);
+  error = heif_image_add_component(image, 3, 2, 0, heif_component_datatype_unsigned_integer, 32, &comp_idx);
   REQUIRE(!error.code);

   size_t stride;
diff --git a/tests/uncompressed_box.cc b/tests/uncompressed_box.cc
index 6f6d3a75..c65e1783 100644
--- a/tests/uncompressed_box.cc
+++ b/tests/uncompressed_box.cc
@@ -728,7 +728,7 @@ TEST_CASE("splz")
   // Construct: 2 component indices, 2x1 pattern, angles 45.0 and 90.0
   auto splz = std::make_shared<Box_splz>();
   PolarizationPattern pattern;
-  pattern.component_indices = {0, 1};
+  pattern.component_ids = {0, 1};
   pattern.pattern_width = 2;
   pattern.pattern_height = 1;
   pattern.polarization_angles = {45.0f, 90.0f};
@@ -767,9 +767,9 @@ TEST_CASE("splz")
   REQUIRE(parsed != nullptr);

   const auto& p = parsed->get_pattern();
-  REQUIRE(p.component_indices.size() == 2);
-  REQUIRE(p.component_indices[0] == 0);
-  REQUIRE(p.component_indices[1] == 1);
+  REQUIRE(p.component_ids.size() == 2);
+  REQUIRE(p.component_ids[0] == 0);
+  REQUIRE(p.component_ids[1] == 1);
   REQUIRE(p.pattern_width == 2);
   REQUIRE(p.pattern_height == 1);
   REQUIRE(p.polarization_angles.size() == 2);
@@ -822,7 +822,7 @@ TEST_CASE("snuc")
   // Construct: 1 component index, nuc_is_applied=true, 2x1 image, 2 gains + 2 offsets
   auto snuc = std::make_shared<Box_snuc>();
   SensorNonUniformityCorrection nuc;
-  nuc.component_indices = {0};
+  nuc.component_ids = {0};
   nuc.nuc_is_applied = true;
   nuc.image_width = 2;
   nuc.image_height = 1;
@@ -866,8 +866,8 @@ TEST_CASE("snuc")
   REQUIRE(parsed != nullptr);

   const auto& n = parsed->get_nuc();
-  REQUIRE(n.component_indices.size() == 1);
-  REQUIRE(n.component_indices[0] == 0);
+  REQUIRE(n.component_ids.size() == 1);
+  REQUIRE(n.component_ids[0] == 0);
   REQUIRE(n.nuc_is_applied == true);
   REQUIRE(n.image_width == 2);
   REQUIRE(n.image_height == 1);
diff --git a/tests/uncompressed_encode_multicomponent.cc b/tests/uncompressed_encode_multicomponent.cc
index 3f8ce3ba..05e5c8af 100644
--- a/tests/uncompressed_encode_multicomponent.cc
+++ b/tests/uncompressed_encode_multicomponent.cc
@@ -241,7 +241,7 @@ const int8_t* get_component_ptr_readonly<int8_t>(const heif_image* image, uint32


 template <typename T>
-static heif_image* create_and_fill_image(heif_channel_datatype datatype, int bit_depth)
+static heif_image* create_and_fill_image(heif_component_datatype datatype, int bit_depth)
 {
   heif_image* image = nullptr;
   heif_error err;
@@ -332,7 +332,7 @@ static void verify_image_data(const heif_image* image)


 template <typename T>
-static void test_multi_mono(heif_channel_datatype datatype, int bit_depth, const char* output_filename)
+static void test_multi_mono(heif_component_datatype datatype, int bit_depth, const char* output_filename)
 {
   heif_image* image = create_and_fill_image<T>(datatype, bit_depth);

@@ -380,57 +380,57 @@ static void test_multi_mono(heif_channel_datatype datatype, int bit_depth, const

 TEST_CASE("Multi-mono uint8")
 {
-  test_multi_mono<uint8_t>(heif_channel_datatype_unsigned_integer, 8, "multi_mono_uint8.heif");
+  test_multi_mono<uint8_t>(heif_component_datatype_unsigned_integer, 8, "multi_mono_uint8.heif");
 }

 TEST_CASE("Multi-mono uint16")
 {
-  test_multi_mono<uint16_t>(heif_channel_datatype_unsigned_integer, 16, "multi_mono_uint16.heif");
+  test_multi_mono<uint16_t>(heif_component_datatype_unsigned_integer, 16, "multi_mono_uint16.heif");
 }

 TEST_CASE("Multi-mono uint12")
 {
-  test_multi_mono<uint16_t>(heif_channel_datatype_unsigned_integer, 12, "multi_mono_uint12.heif");
+  test_multi_mono<uint16_t>(heif_component_datatype_unsigned_integer, 12, "multi_mono_uint12.heif");
 }

 TEST_CASE("Multi-mono uint32")
 {
-  test_multi_mono<uint32_t>(heif_channel_datatype_unsigned_integer, 32, "multi_mono_uint32.heif");
+  test_multi_mono<uint32_t>(heif_component_datatype_unsigned_integer, 32, "multi_mono_uint32.heif");
 }

 TEST_CASE("Multi-mono int8")
 {
-  test_multi_mono<int8_t>(heif_channel_datatype_signed_integer, 8, "multi_mono_int8.heif");
+  test_multi_mono<int8_t>(heif_component_datatype_signed_integer, 8, "multi_mono_int8.heif");
 }

 TEST_CASE("Multi-mono int16")
 {
-  test_multi_mono<int16_t>(heif_channel_datatype_signed_integer, 16, "multi_mono_int16.heif");
+  test_multi_mono<int16_t>(heif_component_datatype_signed_integer, 16, "multi_mono_int16.heif");
 }

 TEST_CASE("Multi-mono int32")
 {
-  test_multi_mono<int32_t>(heif_channel_datatype_signed_integer, 32, "multi_mono_int32.heif");
+  test_multi_mono<int32_t>(heif_component_datatype_signed_integer, 32, "multi_mono_int32.heif");
 }

 TEST_CASE("Multi-mono float32")
 {
-  test_multi_mono<float>(heif_channel_datatype_floating_point, 32, "multi_mono_float32.heif");
+  test_multi_mono<float>(heif_component_datatype_floating_point, 32, "multi_mono_float32.heif");
 }

 TEST_CASE("Multi-mono float64")
 {
-  test_multi_mono<double>(heif_channel_datatype_floating_point, 64, "multi_mono_float64.heif");
+  test_multi_mono<double>(heif_component_datatype_floating_point, 64, "multi_mono_float64.heif");
 }

 TEST_CASE("Multi-mono complex32")
 {
-  test_multi_mono<heif_complex32>(heif_channel_datatype_complex_number, 64, "multi_mono_complex32.heif");
+  test_multi_mono<heif_complex32>(heif_component_datatype_complex_number, 64, "multi_mono_complex32.heif");
 }

 TEST_CASE("Multi-mono complex64")
 {
-  test_multi_mono<heif_complex64>(heif_channel_datatype_complex_number, 128, "multi_mono_complex64.heif");
+  test_multi_mono<heif_complex64>(heif_component_datatype_complex_number, 128, "multi_mono_complex64.heif");
 }


@@ -455,13 +455,13 @@ TEST_CASE("Mixed bpp: 16-bit and 14-bit components")
   // Add 16-bit component (byte-aligned)
   uint32_t idx0 = 0;
   err = heif_image_add_component(image, kW, kH, kMonoComponentType,
-                                 heif_channel_datatype_unsigned_integer, kBpp16, &idx0);
+                                 heif_component_datatype_unsigned_integer, kBpp16, &idx0);
   REQUIRE(err.code == heif_error_Ok);

   // Add 14-bit component (non-byte-aligned)
   uint32_t idx1 = 0;
   err = heif_image_add_component(image, kW, kH, kMonoComponentType,
-                                 heif_channel_datatype_unsigned_integer, kBpp14, &idx1);
+                                 heif_component_datatype_unsigned_integer, kBpp14, &idx1);
   REQUIRE(err.code == heif_error_Ok);

   // Fill 16-bit component