Commit d10444cb for libheif

commit d10444cb3c12c8a14e391dffcf415f5b9b9fda2b
Author: Dirk Farin <dirk.farin@gmail.com>
Date:   Fri Apr 3 14:38:48 2026 +0200

    unci: support up to 256bpp in unc_encoder_component_interleave

diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
index 67a2e0e8..874b040d 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
@@ -33,6 +33,43 @@ bool unc_encoder_factory_component_interleave::can_encode(const std::shared_ptr<
     return false;
   }

+  // If any component is not byte-aligned, we use the bit-packing path which
+  // reads samples as uint32_t, limiting all components to 32 bpp.
+  bool any_non_aligned = false;
+  uint32_t num_components = image->get_number_of_used_components();
+  for (uint32_t idx = 0; idx < num_components; idx++) {
+    uint16_t bpp = image->get_component_bits_per_pixel(idx);
+    if (bpp % 8 != 0) {
+      any_non_aligned = true;
+    }
+  }
+
+  if (any_non_aligned) {
+    for (uint32_t idx = 0; idx < num_components; idx++) {
+      if (image->get_component_bits_per_pixel(idx) > 32) {
+        return false;
+      }
+    }
+  }
+
+  if (!any_non_aligned) {
+    // All components are byte-aligned. Only accept typical integer widths.
+    for (uint32_t idx = 0; idx < num_components; idx++) {
+      uint16_t bpp = image->get_component_bits_per_pixel(idx);
+      switch (bpp) {
+        case 8:
+        case 16:
+        case 32:
+        case 64:
+        case 128:
+        case 256:
+          break;
+        default:
+          return false;
+      }
+    }
+  }
+
   return true;
 }

@@ -68,7 +105,7 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
       }
     }

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

@@ -153,7 +190,7 @@ std::vector<uint8_t> unc_encoder_component_interleave::encode_tile(const std::sh
   for (const auto& comp : m_components) {
     uint32_t plane_width = src_image->get_component_width(comp.component_idx);
     uint32_t plane_height = src_image->get_component_height(comp.component_idx);
-    uint8_t bpp = comp.bpp;
+    uint16_t bpp = comp.bpp;

     size_t src_stride;
     const uint8_t* src_data = src_image->get_component(comp.component_idx, &src_stride);
diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.h b/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
index b2c954c3..db84e99b 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.h
@@ -44,7 +44,7 @@ private:
     heif_channel channel;
     heif_uncompressed_component_type component_type;
     heif_uncompressed_component_format component_format;
-    uint8_t bpp;
+    uint16_t bpp;
     bool byte_aligned;
   };

diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index 2ce28579..c945976d 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -2233,7 +2233,7 @@ uint32_t HeifPixelImage::get_component_height(uint32_t component_idx) const
 }


-uint8_t HeifPixelImage::get_component_bits_per_pixel(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);
   assert(comp);
@@ -2241,13 +2241,13 @@ uint8_t HeifPixelImage::get_component_bits_per_pixel(uint32_t component_idx) con
 }


-uint8_t HeifPixelImage::get_component_storage_bits_per_pixel(uint32_t component_idx) const
+uint16_t HeifPixelImage::get_component_storage_bits_per_pixel(uint32_t component_idx) const
 {
   auto* comp = find_component_by_index(component_idx);
   assert(comp);
   uint32_t bpp = comp->get_bytes_per_pixel() * 8;
-  assert(bpp <= 255);
-  return static_cast<uint8_t>(bpp);
+  assert(bpp <= 256);
+  return static_cast<uint16_t>(bpp);
 }


diff --git a/libheif/pixelimage.h b/libheif/pixelimage.h
index 56c4d7f0..c07513ce 100644
--- a/libheif/pixelimage.h
+++ b/libheif/pixelimage.h
@@ -433,8 +433,8 @@ public:

   uint32_t get_component_width(uint32_t component_idx) const;
   uint32_t get_component_height(uint32_t component_idx) const;
-  uint8_t get_component_bits_per_pixel(uint32_t component_idx) const;
-  uint8_t get_component_storage_bits_per_pixel(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;

   // Look up the component type from the cmpd table. Works for any cmpd index,
@@ -571,7 +571,7 @@ private:
     // logical bit depth per component
     // For interleaved formats, it is the number of bits for one component.
     // It is not the storage width.
-    uint8_t m_bit_depth = 0;
+    uint16_t m_bit_depth = 0; // 1-256
     uint8_t m_num_interleaved_components = 1;

     // the "visible" area of the plane