Commit be4374aa for libheif
commit be4374aafdf3380f20c30f26e39bbee5eeb7164f
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu Feb 12 20:34:45 2026 +0100
unci: decoding of multi-component images
diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index 82eb29ad..c522cab4 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -195,6 +195,26 @@ bool map_uncompressed_component_to_channel(const std::shared_ptr<const Box_cmpd>
}
+heif_channel_datatype unc_component_format_to_datatype(uint8_t format)
+{
+ switch (format) {
+ case component_format_unsigned:
+ return heif_channel_datatype_unsigned_integer;
+
+ case component_format_signed:
+ return heif_channel_datatype_signed_integer;
+
+ case component_format_float:
+ return heif_channel_datatype_floating_point;
+
+ case component_format_complex:
+ return heif_channel_datatype_complex_number;
+
+ default:
+ return heif_channel_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,
@@ -202,6 +222,8 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con
uint32_t height,
const heif_security_limits* limits)
{
+ const auto& components = cmpd->get_components();
+
auto img = std::make_shared<HeifPixelImage>();
heif_chroma chroma = heif_chroma_undefined;
heif_colorspace colourspace = heif_colorspace_undefined;
@@ -215,24 +237,37 @@ Result<std::shared_ptr<HeifPixelImage>> UncompressedImageCodec::create_image(con
chroma);
for (Box_uncC::Component component : uncC->get_components()) {
- heif_channel channel;
- if (map_uncompressed_component_to_channel(cmpd, component, &channel)) {
- if (img->has_channel(channel)) {
- return Error{heif_error_Unsupported_feature,
- heif_suberror_Unspecified,
- "Cannot generate image with several similar heif_channels."};
- }
+ if (component.component_index >= components.size()) {
+ return Error{
+ heif_error_Invalid_input,
+ heif_suberror_Unspecified,
+ "Component index out of range."
+ };
+ }
- if ((channel == heif_channel_Cb) || (channel == heif_channel_Cr)) {
- if (auto err = img->add_plane(channel, (width / chroma_h_subsampling(chroma)), (height / chroma_v_subsampling(chroma)), component.component_bit_depth,
- limits)) {
- return err;
- }
+ auto component_type = components[component.component_index].component_type;
+
+ if ((component_type == heif_uncompressed_component_type::component_type_Cb) ||
+ (component_type == heif_uncompressed_component_type::component_type_Cr)) {
+ Result<uint32_t> result = img->add_component((width / chroma_h_subsampling(chroma)),
+ (height / chroma_v_subsampling(chroma)),
+ component_type,
+ unc_component_format_to_datatype(component.component_format),
+ component.component_bit_depth,
+ limits);
+ if (result.is_error()) {
+ return result.error();
}
- else {
- if (auto err = img->add_plane(channel, width, height, component.component_bit_depth, limits)) {
- return err;
- }
+ }
+ else {
+ Result<uint32_t> result = img->add_component(width,
+ height,
+ component_type,
+ unc_component_format_to_datatype(component.component_format),
+ component.component_bit_depth,
+ limits);
+ if (result.is_error()) {
+ return result.error();
}
}
}
diff --git a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
index d38a7dcb..daf5696b 100644
--- a/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_decoder_bytealign_component_interleave.cc
@@ -84,10 +84,9 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
const auto& c = components[i];
comp[i].bytes_per_sample = (c.component_bit_depth + 7) / 8;
- heif_channel channel;
- comp[i].use = map_uncompressed_component_to_channel(m_cmpd, c, &channel);
+ comp[i].use = true; // map_uncompressed_component_to_channel(m_cmpd, c, &channel);
if (comp[i].use) {
- comp[i].dst_plane = img->get_plane(channel, &comp[i].dst_plane_stride);
+ comp[i].dst_plane = img->get_component(i, &comp[i].dst_plane_stride);
}
else {
comp[i].dst_plane = nullptr;
@@ -152,7 +151,7 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
}
std::memcpy(dst, &value, 4);
}
- else {
+ else if (comp[c].bytes_per_sample == 8) {
// 8-byte sample
uint64_t value;
if (little_endian) {
@@ -177,6 +176,50 @@ Error unc_decoder_bytealign_component_interleave::decode_tile(const std::vector<
}
std::memcpy(dst, &value, 8);
}
+ else if (comp[c].bytes_per_sample == 16) {
+ // 16-byte sample (2* 8 complex)
+ uint64_t value[2];
+ if (little_endian) {
+ value[0] = static_cast<uint64_t>(src[0])
+ | (static_cast<uint64_t>(src[1]) << 8)
+ | (static_cast<uint64_t>(src[2]) << 16)
+ | (static_cast<uint64_t>(src[3]) << 24)
+ | (static_cast<uint64_t>(src[4]) << 32)
+ | (static_cast<uint64_t>(src[5]) << 40)
+ | (static_cast<uint64_t>(src[6]) << 48)
+ | (static_cast<uint64_t>(src[7]) << 56);
+ value[1] = static_cast<uint64_t>(src[8])
+ | (static_cast<uint64_t>(src[9]) << 8)
+ | (static_cast<uint64_t>(src[10]) << 16)
+ | (static_cast<uint64_t>(src[11]) << 24)
+ | (static_cast<uint64_t>(src[12]) << 32)
+ | (static_cast<uint64_t>(src[13]) << 40)
+ | (static_cast<uint64_t>(src[14]) << 48)
+ | (static_cast<uint64_t>(src[15]) << 56);
+ }
+ else {
+ value[0] = (static_cast<uint64_t>(src[0]) << 56)
+ | (static_cast<uint64_t>(src[1]) << 48)
+ | (static_cast<uint64_t>(src[2]) << 40)
+ | (static_cast<uint64_t>(src[3]) << 32)
+ | (static_cast<uint64_t>(src[4]) << 24)
+ | (static_cast<uint64_t>(src[5]) << 16)
+ | (static_cast<uint64_t>(src[6]) << 8)
+ | static_cast<uint64_t>(src[7]);
+ value[1] = (static_cast<uint64_t>(src[8]) << 56)
+ | (static_cast<uint64_t>(src[9]) << 48)
+ | (static_cast<uint64_t>(src[10]) << 40)
+ | (static_cast<uint64_t>(src[11]) << 32)
+ | (static_cast<uint64_t>(src[12]) << 24)
+ | (static_cast<uint64_t>(src[13]) << 16)
+ | (static_cast<uint64_t>(src[14]) << 8)
+ | static_cast<uint64_t>(src[15]);
+ }
+ std::memcpy(dst, &value, 2*8);
+ }
+ else {
+ assert(false);
+ }
}
src += aligned_bytes_per_sample;
@@ -213,10 +256,11 @@ bool unc_decoder_factory_bytealign_component_interleave::can_decode(const std::s
for (const auto& component : uncC->get_components()) {
uint32_t d = component.component_bit_depth;
- if (d != 8 && d != 16 && d != 32 && d != 64) {
+ if (d != 8 && d != 16 && d != 32 && d != 64 && d != 128) {
return false;
}
- if (component.component_format != component_format_unsigned) {
+
+ if (d == 128 && component.component_format != heif_uncompressed_component_format::component_format_complex) {
return false;
}
}
diff --git a/libheif/codecs/uncompressed/unc_types.h b/libheif/codecs/uncompressed/unc_types.h
index 4406a716..8213051b 100644
--- a/libheif/codecs/uncompressed/unc_types.h
+++ b/libheif/codecs/uncompressed/unc_types.h
@@ -132,7 +132,7 @@ enum heif_uncompressed_component_type : uint16_t
*
* See ISO/IEC 23001-17 Table 2.
*/
-enum heif_uncompressed_component_format
+enum heif_uncompressed_component_format : uint8_t
{
/**
* Unsigned integer.