Commit e01c2164 for libheif
commit e01c216466cc20e3f48e6e4f1e3ba8a3f3749046
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Thu Mar 12 11:18:40 2026 +0100
unci: generate unci metadata boxes in unc_encoder constructor
diff --git a/libheif/codecs/uncompressed/unc_boxes.h b/libheif/codecs/uncompressed/unc_boxes.h
index a7fa4a30..b2c54183 100644
--- a/libheif/codecs/uncompressed/unc_boxes.h
+++ b/libheif/codecs/uncompressed/unc_boxes.h
@@ -66,9 +66,11 @@ public:
bool has_component(heif_uncompressed_component_type) const;
- void add_component(const Component& component)
+ uint16_t add_component(const Component& component)
{
+ auto index = static_cast<uint16_t>(m_components.size());
m_components.push_back(component);
+ return index;
}
protected:
diff --git a/libheif/codecs/uncompressed/unc_encoder.cc b/libheif/codecs/uncompressed/unc_encoder.cc
index b37ad91c..feb1bb7c 100644
--- a/libheif/codecs/uncompressed/unc_encoder.cc
+++ b/libheif/codecs/uncompressed/unc_encoder.cc
@@ -22,6 +22,8 @@
#include <cassert>
#include <cstring>
+#include <map>
+#include <set>
#include "pixelimage.h"
#include "unc_boxes.h"
@@ -76,10 +78,79 @@ heif_uncompressed_component_format to_unc_component_format(heif_channel_datatype
}
-unc_encoder::unc_encoder()
+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>();
+
+ // --- Bayer pattern: add reference components to cmpd and generate cpat box
+
+ 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);
+ }
+ }
+
+ // 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});
+ }
+
+ // 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);
+ }
+
+ if (image->has_polarization_patterns()) {
+ for (const auto& pol : image->get_polarization_patterns()) {
+ auto splz = std::make_shared<Box_splz>();
+ splz->set_pattern(pol);
+ m_splz.push_back(splz);
+ }
+ }
+
+ if (image->has_sensor_bad_pixels_maps()) {
+ for (const auto& bpm : image->get_sensor_bad_pixels_maps()) {
+ auto sbpm = std::make_shared<Box_sbpm>();
+ sbpm->set_bad_pixels_map(bpm);
+ m_sbpm.push_back(sbpm);
+ }
+ }
+
+ if (image->has_sensor_nuc()) {
+ for (const auto& nuc : image->get_sensor_nuc()) {
+ auto snuc = std::make_shared<Box_snuc>();
+ snuc->set_nuc(nuc);
+ m_snuc.push_back(snuc);
+ }
+ }
+
+ if (image->has_chroma_location()) {
+ m_cloc = std::make_shared<Box_cloc>();
+ m_cloc->set_chroma_location(image->get_chroma_location());
+ }
}
diff --git a/libheif/codecs/uncompressed/unc_encoder.h b/libheif/codecs/uncompressed/unc_encoder.h
index 9b70a725..40d2a8d9 100644
--- a/libheif/codecs/uncompressed/unc_encoder.h
+++ b/libheif/codecs/uncompressed/unc_encoder.h
@@ -46,7 +46,7 @@ heif_uncompressed_component_format to_unc_component_format(heif_channel_datatype
class unc_encoder
{
public:
- unc_encoder();
+ explicit unc_encoder(const std::shared_ptr<const HeifPixelImage>& image);
virtual ~unc_encoder() = default;
diff --git a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
index 0fac9295..620134b6 100644
--- a/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_component_interleave.cc
@@ -21,8 +21,6 @@
#include "unc_encoder_component_interleave.h"
#include <cstring>
-#include <map>
-#include <set>
#include "pixelimage.h"
#include "unc_boxes.h"
@@ -48,6 +46,7 @@ std::unique_ptr<const unc_encoder> unc_encoder_factory_component_interleave::cre
unc_encoder_component_interleave::unc_encoder_component_interleave(const std::shared_ptr<const HeifPixelImage>& image,
const heif_encoding_options& options)
+ : unc_encoder(image)
{
bool is_nonvisual = (image->get_colorspace() == heif_colorspace_nonvisual);
uint32_t num_components = image->get_number_of_used_components();
@@ -79,9 +78,8 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
// Build cmpd/uncC boxes
bool little_endian = false;
- uint16_t box_index = 0;
for (const auto& comp : m_components) {
- m_cmpd->add_component({static_cast<uint16_t>(comp.component_type)});
+ uint16_t cmpd_index = m_cmpd->add_component({static_cast<uint16_t>(comp.component_type)});
uint8_t component_align_size = 0;
@@ -89,8 +87,7 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
little_endian = true;
}
- m_uncC->add_component({box_index, comp.bpp, comp.component_format, component_align_size});
- box_index++;
+ m_uncC->add_component({cmpd_index, comp.bpp, comp.component_format, component_align_size});
}
m_uncC->set_interleave_type(interleave_mode_component);
@@ -106,78 +103,6 @@ unc_encoder_component_interleave::unc_encoder_component_interleave(const std::sh
else {
m_uncC->set_sampling_type(sampling_mode_no_subsampling);
}
-
- // --- Bayer pattern: add reference components to cmpd and generate cpat box
-
- 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);
- }
- }
-
- // Add reference components to cmpd (these have no uncC entries).
- // box_index is already at the next available index after data components.
- std::map<uint16_t, uint16_t> type_to_cmpd_index;
- for (uint16_t type : unique_types) {
- type_to_cmpd_index[type] = box_index;
- m_cmpd->add_component({type});
- box_index++;
- }
-
- // 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);
- }
-
- if (image->has_polarization_patterns()) {
- for (const auto& pol : image->get_polarization_patterns()) {
- auto splz = std::make_shared<Box_splz>();
- splz->set_pattern(pol);
- m_splz.push_back(splz);
- }
- }
-
- if (image->has_sensor_bad_pixels_maps()) {
- for (const auto& bpm : image->get_sensor_bad_pixels_maps()) {
- auto sbpm = std::make_shared<Box_sbpm>();
- sbpm->set_bad_pixels_map(bpm);
- m_sbpm.push_back(sbpm);
- }
- }
-
- if (image->has_sensor_nuc()) {
- for (const auto& nuc : image->get_sensor_nuc()) {
- auto snuc = std::make_shared<Box_snuc>();
- snuc->set_nuc(nuc);
- m_snuc.push_back(snuc);
- }
- }
-
- if (image->has_chroma_location()) {
- m_cloc = std::make_shared<Box_cloc>();
- m_cloc->set_chroma_location(image->get_chroma_location());
- }
}
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 16be6a0e..8b21f55d 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_block_pixel_interleave.cc
@@ -57,10 +57,11 @@ std::unique_ptr<const unc_encoder> unc_encoder_factory_rgb_block_pixel_interleav
unc_encoder_rgb_block_pixel_interleave::unc_encoder_rgb_block_pixel_interleave(const std::shared_ptr<const HeifPixelImage>& image,
const heif_encoding_options& options)
+ : unc_encoder(image)
{
- m_cmpd->add_component({heif_uncompressed_component_type_red});
- m_cmpd->add_component({heif_uncompressed_component_type_green});
- m_cmpd->add_component({heif_uncompressed_component_type_blue});
+ uint16_t idx_r = m_cmpd->add_component({heif_uncompressed_component_type_red});
+ uint16_t idx_g = m_cmpd->add_component({heif_uncompressed_component_type_green});
+ uint16_t idx_b = m_cmpd->add_component({heif_uncompressed_component_type_blue});
uint8_t bpp = image->get_bits_per_pixel(heif_channel_interleaved);
@@ -73,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(true);
- m_uncC->add_component({0, bpp, component_format_unsigned, 0});
- m_uncC->add_component({1, bpp, component_format_unsigned, 0});
- m_uncC->add_component({2, bpp, component_format_unsigned, 0});
+ m_uncC->add_component({idx_r, bpp, component_format_unsigned, 0});
+ m_uncC->add_component({idx_g, bpp, component_format_unsigned, 0});
+ m_uncC->add_component({idx_b, bpp, component_format_unsigned, 0});
}
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 d103abb4..dc183cf4 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_bytealign_pixel_interleave.cc
@@ -57,15 +57,17 @@ std::unique_ptr<const unc_encoder> unc_encoder_factory_rgb_bytealign_pixel_inter
unc_encoder_rgb_bytealign_pixel_interleave::unc_encoder_rgb_bytealign_pixel_interleave(const std::shared_ptr<const HeifPixelImage>& image,
const heif_encoding_options& options)
+ : unc_encoder(image)
{
- m_cmpd->add_component({heif_uncompressed_component_type_red});
- m_cmpd->add_component({heif_uncompressed_component_type_green});
- m_cmpd->add_component({heif_uncompressed_component_type_blue});
+ uint16_t idx_r = m_cmpd->add_component({heif_uncompressed_component_type_red});
+ uint16_t idx_g = m_cmpd->add_component({heif_uncompressed_component_type_green});
+ uint16_t idx_b = m_cmpd->add_component({heif_uncompressed_component_type_blue});
bool save_alpha = image->has_alpha();
+ uint16_t idx_a = 0;
if (save_alpha) {
- m_cmpd->add_component({heif_uncompressed_component_type_alpha});
+ idx_a = m_cmpd->add_component({heif_uncompressed_component_type_alpha});
}
m_bytes_per_pixel = save_alpha ? 8 : 6;
@@ -88,11 +90,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({0, bpp, component_format_unsigned, component_align_size});
- m_uncC->add_component({1, bpp, component_format_unsigned, component_align_size});
- m_uncC->add_component({2, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_r, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_g, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_b, bpp, component_format_unsigned, component_align_size});
if (save_alpha) {
- m_uncC->add_component({3, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_a, 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 6e2fc457..871d314d 100644
--- a/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc
+++ b/libheif/codecs/uncompressed/unc_encoder_rgb_pixel_interleave.cc
@@ -53,15 +53,17 @@ std::unique_ptr<const unc_encoder> unc_encoder_factory_rgb_pixel_interleave::cre
unc_encoder_rgb_pixel_interleave::unc_encoder_rgb_pixel_interleave(const std::shared_ptr<const HeifPixelImage>& image,
const heif_encoding_options& options)
+ : unc_encoder(image)
{
- m_cmpd->add_component({heif_uncompressed_component_type_red});
- m_cmpd->add_component({heif_uncompressed_component_type_green});
- m_cmpd->add_component({heif_uncompressed_component_type_blue});
+ uint16_t idx_r = m_cmpd->add_component({heif_uncompressed_component_type_red});
+ uint16_t idx_g = m_cmpd->add_component({heif_uncompressed_component_type_green});
+ uint16_t idx_b = m_cmpd->add_component({heif_uncompressed_component_type_blue});
bool save_alpha = image->has_alpha();
+ uint16_t idx_a = 0;
if (save_alpha) {
- m_cmpd->add_component({heif_uncompressed_component_type_alpha});
+ idx_a = m_cmpd->add_component({heif_uncompressed_component_type_alpha});
}
m_bytes_per_pixel = save_alpha ? 4 : 3;
@@ -84,11 +86,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({0, bpp, component_format_unsigned, component_align_size});
- m_uncC->add_component({1, bpp, component_format_unsigned, component_align_size});
- m_uncC->add_component({2, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_r, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_g, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_b, bpp, component_format_unsigned, component_align_size});
if (save_alpha) {
- m_uncC->add_component({3, bpp, component_format_unsigned, component_align_size});
+ m_uncC->add_component({idx_a, bpp, component_format_unsigned, component_align_size});
}
}