Commit 1d18b1eb for libheif
commit 1d18b1eb6d2dc5aa2247a982d3905ea89abd7fd0
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Fri Feb 27 15:43:46 2026 +0100
set GIMI component content IDs through image handle
diff --git a/libheif/api/libheif/heif_image_handle.cc b/libheif/api/libheif/heif_image_handle.cc
index d996a7d0..eb4facc9 100644
--- a/libheif/api/libheif/heif_image_handle.cc
+++ b/libheif/api/libheif/heif_image_handle.cc
@@ -192,13 +192,32 @@ void heif_image_handle_set_gimi_content_id(heif_image_handle* handle, const char
}
+#if WITH_UNCOMPRESSED_CODEC
+static std::shared_ptr<Box_cmpd> get_effective_cmpd(const heif_image_handle* handle)
+{
+ // Try explicit cmpd property first.
+ auto cmpd = handle->image->get_property<Box_cmpd>();
+ if (cmpd) {
+ return cmpd;
+ }
+
+ // For profile-based uncC (version 1), the cmpd is synthesized inside the uncC box.
+ auto uncC = handle->image->get_property<Box_uncC>();
+ if (uncC) {
+ fill_uncC_and_cmpd_from_profile(uncC, cmpd);
+ }
+ return cmpd;
+}
+#endif
+
+
uint32_t heif_image_handle_get_number_of_cmpd_components(const heif_image_handle* handle)
{
#if WITH_UNCOMPRESSED_CODEC
if (!handle) {
return 0;
}
- auto cmpd = handle->image->get_property<Box_cmpd>();
+ auto cmpd = get_effective_cmpd(handle);
if (!cmpd) {
return 0;
}
@@ -215,7 +234,7 @@ uint16_t heif_image_handle_get_cmpd_component_type(const heif_image_handle* hand
if (!handle) {
return 0;
}
- auto cmpd = handle->image->get_property<Box_cmpd>();
+ auto cmpd = get_effective_cmpd(handle);
if (!cmpd) {
return 0;
}
@@ -236,7 +255,7 @@ const char* heif_image_handle_get_cmpd_component_type_uri(const heif_image_handl
if (!handle) {
return nullptr;
}
- auto cmpd = handle->image->get_property<Box_cmpd>();
+ auto cmpd = get_effective_cmpd(handle);
if (!cmpd) {
return nullptr;
}
@@ -295,3 +314,34 @@ const char* heif_image_handle_get_gimi_component_content_id(const heif_image_han
return nullptr;
#endif
}
+
+
+void heif_image_handle_set_gimi_component_content_id(heif_image_handle* handle,
+ uint32_t component_idx,
+ const char* content_id)
+{
+#if WITH_UNCOMPRESSED_CODEC
+ if (!handle || !content_id) {
+ return;
+ }
+
+ auto box = handle->image->get_property<Box_gimi_component_content_ids>();
+ if (!box) {
+ // Create a new box and add it as property.
+ auto new_box = std::make_shared<Box_gimi_component_content_ids>();
+ std::vector<std::string> ids(component_idx + 1);
+ ids[component_idx] = content_id;
+ new_box->set_content_ids(ids);
+ handle->context->add_property(handle->image->get_id(), new_box, false);
+ }
+ else {
+ // Mutate the existing box in-place.
+ auto ids = box->get_content_ids();
+ if (component_idx >= ids.size()) {
+ ids.resize(component_idx + 1);
+ }
+ ids[component_idx] = content_id;
+ box->set_content_ids(ids);
+ }
+#endif
+}
diff --git a/libheif/api/libheif/heif_image_handle.h b/libheif/api/libheif/heif_image_handle.h
index 3b4f811b..5bd3f29a 100644
--- a/libheif/api/libheif/heif_image_handle.h
+++ b/libheif/api/libheif/heif_image_handle.h
@@ -156,6 +156,14 @@ int heif_image_handle_has_gimi_component_content_ids(const heif_image_handle*);
LIBHEIF_API
const char* heif_image_handle_get_gimi_component_content_id(const heif_image_handle*, uint32_t component_idx);
+// Set a GIMI component content ID for a single component.
+// If an ItemComponentContentIDProperty does not yet exist, one will be created.
+// The content IDs array is resized as needed (new entries default to empty).
+LIBHEIF_API
+void heif_image_handle_set_gimi_component_content_id(heif_image_handle*,
+ uint32_t component_idx,
+ const char* content_id);
+
#ifdef __cplusplus
}
#endif
diff --git a/libheif/api/libheif/heif_uncompressed.cc b/libheif/api/libheif/heif_uncompressed.cc
index 5ed77ef6..22ea296b 100644
--- a/libheif/api/libheif/heif_uncompressed.cc
+++ b/libheif/api/libheif/heif_uncompressed.cc
@@ -763,40 +763,12 @@ heif_image_get_component_X(complex32, heif_complex32)
heif_image_get_component_X(complex64, heif_complex64)
-// --- GIMI component content IDs
-
-int heif_image_has_component_content_ids(const heif_image* image)
-{
- if (!image || !image->image) {
- return 0;
- }
- return static_cast<int>(image->image->get_component_content_ids().size());
-}
-
-
-const char* heif_image_get_component_content_id(const heif_image* image, uint32_t component_idx)
-{
- if (!image || !image->image || !image->image->has_component_content_ids()) {
- return nullptr;
- }
-
- const auto& ids = image->image->get_component_content_ids();
- if (component_idx >= ids.size()) {
- return nullptr;
- }
-
- char* idstring = new char[ids[component_idx].size() + 1];
- strcpy(idstring, ids[component_idx].c_str());
- return idstring;
-}
-
-
-heif_error heif_image_set_component_content_id(heif_image* image,
- uint32_t component_idx,
- const char* content_id)
+void heif_image_set_gimi_component_content_id(heif_image* image,
+ uint32_t component_idx,
+ const char* content_id)
{
if (!image || !image->image || !content_id) {
- return heif_error_null_pointer_argument;
+ return;
}
auto ids = image->image->get_component_content_ids();
@@ -805,8 +777,6 @@ heif_error heif_image_set_component_content_id(heif_image* image,
}
ids[component_idx] = content_id;
image->image->set_component_content_ids(ids);
-
- return heif_error_success;
}
diff --git a/libheif/api/libheif/heif_uncompressed.h b/libheif/api/libheif/heif_uncompressed.h
index ea36071f..2166aabd 100644
--- a/libheif/api/libheif/heif_uncompressed.h
+++ b/libheif/api/libheif/heif_uncompressed.h
@@ -388,24 +388,15 @@ LIBHEIF_API
heif_complex64* heif_image_get_component_complex64(heif_image*, uint32_t component_idx, size_t* out_stride);
-// --- GIMI component content IDs
+// --- GIMI component content IDs (set before encoding)
-// Returns non-zero (the number of content IDs) if component content IDs are set, 0 otherwise.
-LIBHEIF_API
-int heif_image_has_component_content_ids(const heif_image*);
-
-// Get a component content ID by cmpd component index.
-// Returns NULL if no content IDs are set or if the index is out of range.
-// The returned string must be freed with heif_string_release().
-LIBHEIF_API
-const char* heif_image_get_component_content_id(const heif_image*, uint32_t component_idx);
-
-// Set a component content ID for a single cmpd component.
+// Set a GIMI component content ID for a single cmpd component.
// If the internal array is too small, it will be resized (new entries default to empty strings).
+// These are written into an ItemComponentContentIDProperty box during encoding.
LIBHEIF_API
-heif_error heif_image_set_component_content_id(heif_image*,
- uint32_t component_idx,
- const char* content_id);
+void heif_image_set_gimi_component_content_id(heif_image*,
+ uint32_t component_idx,
+ const char* content_id);
#ifdef __cplusplus
}
diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc
index 18ae7f7f..ab3bf239 100644
--- a/libheif/image-items/image_item.cc
+++ b/libheif/image-items/image_item.cc
@@ -37,10 +37,6 @@
#include "plugin_registry.h"
#include "security_limits.h"
-#if WITH_UNCOMPRESSED_CODEC
-#include "codecs/uncompressed/unc_boxes.h"
-#endif
-
#include <limits>
#include <cassert>
#include <cstring>
@@ -935,15 +931,6 @@ Result<std::shared_ptr<HeifPixelImage>> ImageItem::decode_image(const heif_decod
img->set_gimi_sample_content_id(gimi_content_id->get_content_id());
}
-#if WITH_UNCOMPRESSED_CODEC
- // GIMI component content IDs
-
- auto gimi_comp_ids = get_property<Box_gimi_component_content_ids>();
- if (gimi_comp_ids) {
- img->set_component_content_ids(gimi_comp_ids->get_content_ids());
- }
-#endif
-
#if HEIF_WITH_OMAF
// Image projection (OMAF)
auto prfr = get_property<Box_prfr>();
diff --git a/libheif/pixelimage.cc b/libheif/pixelimage.cc
index a0e0126c..0b95a8df 100644
--- a/libheif/pixelimage.cc
+++ b/libheif/pixelimage.cc
@@ -1973,10 +1973,6 @@ void HeifPixelImage::forward_all_metadata_from(const std::shared_ptr<const HeifP
set_gimi_sample_content_id(src_image->get_gimi_sample_content_id());
}
- if (src_image->has_component_content_ids()) {
- set_component_content_ids(src_image->get_component_content_ids());
- }
-
if (auto* tai = src_image->get_tai_timestamp()) {
set_tai_timestamp(tai);
}