Commit cb6e5249 for libheif
commit cb6e5249703fa2ca633e4e3129888a7082979f17
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Tue Feb 24 21:36:42 2026 +0100
unci: assign Bayer pattern to heif_image
diff --git a/libheif/api/libheif/heif_image.h b/libheif/api/libheif/heif_image.h
index 7ba290ee..ae24712c 100644
--- a/libheif/api/libheif/heif_image.h
+++ b/libheif/api/libheif/heif_image.h
@@ -75,7 +75,9 @@ typedef enum heif_colorspace
heif_colorspace_monochrome = 2,
// Indicates that this image has no visual channels.
- heif_colorspace_nonvisual = 3
+ heif_colorspace_nonvisual = 3,
+
+ heif_colorspace_filter_array = 4
} heif_colorspace;
typedef enum heif_channel
diff --git a/libheif/codecs/uncompressed/unc_boxes.cc b/libheif/codecs/uncompressed/unc_boxes.cc
index c76a2af2..67797b78 100644
--- a/libheif/codecs/uncompressed/unc_boxes.cc
+++ b/libheif/codecs/uncompressed/unc_boxes.cc
@@ -956,30 +956,30 @@ Error Box_cpat::parse(BitstreamRange& range, const heif_security_limits* limits)
return unsupported_version_error("cpat");
}
- m_pattern_width = range.read16();
- m_pattern_height = range.read16();
+ m_pattern.m_pattern_width = range.read16();
+ m_pattern.m_pattern_height = range.read16();
- if (m_pattern_width == 0 || m_pattern_height == 0) {
+ if (m_pattern.m_pattern_width == 0 || m_pattern.m_pattern_height == 0) {
return {heif_error_Invalid_input,
heif_suberror_Invalid_parameter_value,
"Zero Bayer pattern size."};
}
auto max_bayer_pattern_size = limits->max_bayer_pattern_pixels;
- if (max_bayer_pattern_size && m_pattern_height > max_bayer_pattern_size / m_pattern_width) {
+ if (max_bayer_pattern_size && m_pattern.m_pattern_height > max_bayer_pattern_size / m_pattern.m_pattern_width) {
return {heif_error_Invalid_input,
heif_suberror_Security_limit_exceeded,
"Maximum Bayer pattern size exceeded."};
}
- m_components.resize(size_t{m_pattern_width} * m_pattern_height);
+ m_pattern.m_components.resize(size_t{m_pattern.m_pattern_width} * m_pattern.m_pattern_height);
- for (uint16_t i = 0; i < m_pattern_height; i++) {
- for (uint16_t j = 0; j < m_pattern_width; j++) {
- PatternComponent component{};
+ for (uint16_t i = 0; i < m_pattern.m_pattern_height; i++) {
+ for (uint16_t j = 0; j < m_pattern.m_pattern_width; j++) {
+ BayerPattern::PatternComponent component{};
component.component_index = range.read32();
component.component_gain = range.read_float32();
- m_components[i] = component;
+ m_pattern.m_components[i] = component;
}
}
@@ -995,7 +995,7 @@ std::string Box_cpat::dump(Indent& indent) const
sstr << indent << "pattern_width: " << get_pattern_width() << "\n";
sstr << indent << "pattern_height: " << get_pattern_height() << "\n";
- for (const auto& component : m_components) {
+ for (const auto& component : m_pattern.m_components) {
sstr << indent << "component index: " << component.component_index << ", gain: " << component.component_gain << "\n";
}
return sstr.str();
@@ -1006,17 +1006,17 @@ Error Box_cpat::write(StreamWriter& writer) const
{
size_t box_start = reserve_box_header_space(writer);
- if (m_pattern_width * size_t{m_pattern_height} != m_components.size()) {
+ if (m_pattern.m_pattern_width * size_t{m_pattern.m_pattern_height} != m_pattern.m_components.size()) {
// needs to be rectangular
return {heif_error_Usage_error,
heif_suberror_Invalid_parameter_value,
"incorrect number of pattern components"};
}
- writer.write16(m_pattern_width);
- writer.write16(m_pattern_height);
+ writer.write16(m_pattern.m_pattern_width);
+ writer.write16(m_pattern.m_pattern_height);
- for (const auto& component : m_components) {
+ for (const auto& component : m_pattern.m_components) {
writer.write32(component.component_index);
writer.write_float32(component.component_gain);
}
@@ -1025,3 +1025,9 @@ Error Box_cpat::write(StreamWriter& writer) const
return Error::Ok;
}
+
+
+void Box_cpat::set_bayer_pattern(const BayerPattern& pattern)
+{
+ m_pattern = pattern;
+}
diff --git a/libheif/codecs/uncompressed/unc_boxes.h b/libheif/codecs/uncompressed/unc_boxes.h
index a0dba450..85d7e803 100644
--- a/libheif/codecs/uncompressed/unc_boxes.h
+++ b/libheif/codecs/uncompressed/unc_boxes.h
@@ -354,22 +354,20 @@ public:
set_short_type(fourcc("cpat"));
}
- struct PatternComponent
- {
- uint32_t component_index;
- float component_gain;
- };
-
uint16_t get_pattern_width() const
{
- return m_pattern_width;
+ return m_pattern.m_pattern_width;
}
uint16_t get_pattern_height() const
{
- return m_pattern_height;
+ return m_pattern.m_pattern_height;
}
+ const BayerPattern& get_bayer_pattern() const { return m_pattern; }
+
+ void set_bayer_pattern(const BayerPattern& pattern);
+
std::string dump(Indent&) const override;
Error write(StreamWriter& writer) const override;
@@ -377,9 +375,7 @@ public:
protected:
Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
- uint16_t m_pattern_width = 0;
- uint16_t m_pattern_height = 0;
- std::vector<PatternComponent> m_components;
+ BayerPattern m_pattern;
};
diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc
index 354456b0..b3253a86 100644
--- a/libheif/codecs/uncompressed/unc_codec.cc
+++ b/libheif/codecs/uncompressed/unc_codec.cc
@@ -129,9 +129,8 @@ Error UncompressedImageCodec::get_heif_chroma_uncompressed(const std::shared_ptr
}
if (componentSet == (1 << component_type_filter_array)) {
- // TODO - we should look up the components
- *out_chroma = heif_chroma_monochrome;
- *out_colourspace = heif_colorspace_monochrome;
+ *out_chroma = heif_chroma_monochrome; // TODO: ?
+ *out_colourspace = heif_colorspace_filter_array;
}
// TODO: more combinations
@@ -446,6 +445,7 @@ void UncompressedImageCodec::unci_properties::fill_from_image_item(const std::sh
uncC = uncC_mut;
cmpC = image->get_property<Box_cmpC>();
icef = image->get_property<Box_icef>();
+ cpat = image->get_property<Box_cpat>();
}
diff --git a/libheif/codecs/uncompressed/unc_codec.h b/libheif/codecs/uncompressed/unc_codec.h
index 8d722068..9dadbcdf 100644
--- a/libheif/codecs/uncompressed/unc_codec.h
+++ b/libheif/codecs/uncompressed/unc_codec.h
@@ -63,6 +63,7 @@ public:
std::shared_ptr<const Box_uncC> uncC;
std::shared_ptr<const Box_cmpC> cmpC;
std::shared_ptr<const Box_icef> icef;
+ std::shared_ptr<const Box_cpat> cpat;
// ...
void fill_from_image_item(const std::shared_ptr<const ImageItem>&);
diff --git a/libheif/codecs/uncompressed/unc_decoder.cc b/libheif/codecs/uncompressed/unc_decoder.cc
index f58e0a54..5b287da2 100644
--- a/libheif/codecs/uncompressed/unc_decoder.cc
+++ b/libheif/codecs/uncompressed/unc_decoder.cc
@@ -454,6 +454,10 @@ Result<std::shared_ptr<HeifPixelImage> > unc_decoder::decode_full_image(
auto img = *createImgResult;
+ if (properties.cpat) {
+ img->set_bayer_pattern(properties.cpat->get_bayer_pattern());
+ }
+
auto decoderResult = unc_decoder_factory::get_unc_decoder(width, height, cmpd, uncC);
if (!decoderResult) {
return decoderResult.error();
diff --git a/libheif/codecs/uncompressed/unc_types.h b/libheif/codecs/uncompressed/unc_types.h
index 8213051b..de63f0da 100644
--- a/libheif/codecs/uncompressed/unc_types.h
+++ b/libheif/codecs/uncompressed/unc_types.h
@@ -23,6 +23,7 @@
#define LIBHEIF_UNC_TYPES_H
#include <cstdint>
+#include <vector>
/**
* Component type.
@@ -287,6 +288,18 @@ enum heif_uncompressed_interleave_mode
};
+struct BayerPattern
+{
+ struct PatternComponent
+ {
+ uint32_t component_index;
+ float component_gain;
+ };
+
+ uint16_t m_pattern_width = 0;
+ uint16_t m_pattern_height = 0;
+ std::vector<PatternComponent> m_components;
+};
#endif //LIBHEIF_UNC_TYPES_H
diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index 2ec48234..600c87b8 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -883,6 +883,9 @@ uint8_t HeifPixelImage::get_visual_image_bits_per_pixel() const
case heif_colorspace_nonvisual:
return 0;
break;
+ case heif_colorspace_filter_array:
+ assert(has_channel(heif_channel_filter_array));
+ return get_bits_per_pixel(heif_channel_filter_array);
default:
assert(false);
return 0;
diff --git a/libheif/pixelimage.h b/libheif/pixelimage.h
index 47181119..2d5fba0a 100644
--- a/libheif/pixelimage.h
+++ b/libheif/pixelimage.h
@@ -39,6 +39,8 @@
#include <cassert>
#include <string>
+#include "codecs/uncompressed/unc_types.h"
+
heif_chroma chroma_from_subsampling(int h, int v);
uint32_t chroma_width(uint32_t w, heif_chroma chroma);
@@ -194,6 +196,12 @@ public:
}
#endif
+ void set_bayer_pattern(const BayerPattern& pattern) { m_bayer_pattern = pattern; }
+
+ bool has_bayer_pattern() const { return m_bayer_pattern.has_value(); }
+
+ const BayerPattern& get_bayer_pattern() const { assert(m_bayer_pattern); return *m_bayer_pattern; }
+
private:
bool m_premultiplied_alpha = false;
nclx_profile m_color_profile_nclx = nclx_profile::undefined();
@@ -212,6 +220,8 @@ private:
heif_omaf_image_projection m_omaf_image_projection = heif_omaf_image_projection::heif_omaf_image_projection_flat;
#endif
+ std::optional<BayerPattern> m_bayer_pattern;
+
protected:
std::shared_ptr<Box_clli> get_clli_box() const;