@@ -657,6 +657,80 @@ struct heif_error heif_context_get_primary_image_ID(struct heif_context* ctx, he
657657}
658658
659659
660+ #if WITH_EXPERIMENTAL_GAIN_MAP
661+ heif_error heif_context_get_gain_map_image_handle (heif_context* ctx, heif_image_handle** img) {
662+ if (!img) {
663+ Error err (heif_error_Usage_error, heif_suberror_Null_pointer_argument);
664+ return err.error_struct (ctx->context .get ());
665+ }
666+
667+ std::shared_ptr<ImageItem> gain_map_image = ctx->context ->get_gain_map_image ();
668+ if (!gain_map_image) {
669+ Error err (heif_error_Invalid_input, heif_suberror_No_item_data);
670+ return err.error_struct (ctx->context .get ());
671+ }
672+
673+ *img = new heif_image_handle ();
674+ (*img)->image = std::move (gain_map_image);
675+ (*img)->context = ctx->context ;
676+
677+ return Error::Ok.error_struct (ctx->context .get ());
678+ }
679+
680+ struct heif_error heif_context_get_tmap_nclx_color_profile (
681+ struct heif_context * ctx, struct heif_color_profile_nclx ** out_data) {
682+ if (!out_data) {
683+ Error err (heif_error_Usage_error, heif_suberror_Null_pointer_argument);
684+ return err.error_struct (ctx->context .get ());
685+ }
686+ *out_data = nullptr ;
687+ Error err = ctx->context ->get_tmap_color_profile (out_data);
688+ return err.error_struct (ctx->context .get ());
689+ }
690+
691+ size_t heif_context_get_gain_map_metadata_size (struct heif_context * ctx) {
692+ std::shared_ptr<ImageMetadata> metadata = ctx->context ->get_gain_map_metadata ();
693+ if (metadata) {
694+ return metadata->m_data .size () - 1 ;
695+ } else {
696+ return 0 ;
697+ }
698+ }
699+
700+ struct heif_error heif_context_get_gain_map_metadata (struct heif_context * ctx, void * out_data) {
701+ if (!out_data) {
702+ Error err (heif_error_Usage_error, heif_suberror_Null_pointer_argument);
703+ return err.error_struct (ctx->context .get ());
704+ }
705+
706+ std::shared_ptr<ImageMetadata> metadata = ctx->context ->get_gain_map_metadata ();
707+ if (!metadata) {
708+ Error err (heif_error_Invalid_input, heif_suberror_No_item_data);
709+ return err.error_struct (ctx->context .get ());
710+ }
711+
712+ uint8_t version = 0xff ;
713+ size_t pos = 0 ;
714+ std::vector<uint8_t >& buffer = metadata->m_data ;
715+
716+ if (pos >= buffer.size ()) {
717+ Error err (heif_error_Invalid_input, heif_suberror_End_of_data);
718+ return err.error_struct (ctx->context .get ());
719+ }
720+ version = buffer[pos++];
721+ if (version != 0 ) {
722+ Error err (heif_error_Invalid_input, heif_suberror_Unsupported_data_version,
723+ " Box[tmap] has unsupported version" );
724+ return err.error_struct (ctx->context .get ());
725+ }
726+
727+ memcpy (out_data, buffer.data () + pos, buffer.size () - pos);
728+
729+ return heif_error_success;
730+ }
731+ #endif
732+
733+
660734int heif_context_is_top_level_image_ID (struct heif_context * ctx, heif_item_id id)
661735{
662736 const std::vector<std::shared_ptr<ImageItem>> images = ctx->context ->get_top_level_images (true );
@@ -3442,6 +3516,115 @@ struct heif_error heif_context_encode_image(struct heif_context* ctx,
34423516}
34433517
34443518
3519+ #if WITH_EXPERIMENTAL_GAIN_MAP
3520+ struct heif_error heif_context_encode_gain_map_image (
3521+ struct heif_context * ctx, const struct heif_image * alternate_image,
3522+ const struct heif_image_handle * base_image_handle, struct heif_encoder * encoder,
3523+ const struct heif_encoding_options * input_options, const uint8_t * gain_map_data,
3524+ int gain_map_data_len, const struct heif_color_profile_nclx * targetNclx,
3525+ struct heif_image_handle ** out_image_handle) {
3526+ if (!encoder) {
3527+ return Error (heif_error_Usage_error, heif_suberror_Null_pointer_argument)
3528+ .error_struct (ctx->context .get ());
3529+ }
3530+
3531+ if (out_image_handle) {
3532+ *out_image_handle = nullptr ;
3533+ }
3534+
3535+ if (gain_map_data_len <= 0 ) {
3536+ return Error (heif_error_Invalid_input, heif_suberror_Invalid_parameter_value)
3537+ .error_struct (ctx->context .get ());
3538+ }
3539+
3540+ // --- write tmap item
3541+ std::vector<uint8_t > metadata;
3542+ metadata.push_back (0 ); // version = 0
3543+ for (int i = 0 ; i < gain_map_data_len; i++) {
3544+ metadata.push_back (gain_map_data[i]);
3545+ }
3546+ heif_item_id tmap_item_id = -1 ;
3547+ ctx->context ->add_tmap_item (metadata, tmap_item_id);
3548+
3549+ std::vector<std::shared_ptr<Box>> properties;
3550+
3551+ // --- write ISPE property for tmap item
3552+ std::shared_ptr<Box_ispe> ispe = std::make_shared<Box_ispe>();
3553+ ispe->set_size (base_image_handle->image ->get_ispe_width (),
3554+ base_image_handle->image ->get_ispe_height ());
3555+
3556+ properties.push_back (ispe);
3557+
3558+ // --- write PIXI property for tmap item
3559+ std::shared_ptr<Box_pixi> pixi = std::make_shared<Box_pixi>();
3560+ pixi->add_channel_bits (10 );
3561+ pixi->add_channel_bits (10 );
3562+ pixi->add_channel_bits (10 );
3563+
3564+ properties.push_back (pixi);
3565+
3566+ // --- write COLR property for tmap item
3567+ if (targetNclx != nullptr ) {
3568+ std::shared_ptr<Box_colr> colr = std::make_shared<Box_colr>();
3569+ auto target_nclx_profile = std::make_shared<color_profile_nclx>();
3570+ target_nclx_profile->set_colour_primaries (targetNclx->color_primaries );
3571+ target_nclx_profile->set_transfer_characteristics (targetNclx->transfer_characteristics );
3572+ target_nclx_profile->set_matrix_coefficients (targetNclx->matrix_coefficients );
3573+ target_nclx_profile->set_full_range_flag (targetNclx->full_range_flag );
3574+ colr->set_color_profile (target_nclx_profile);
3575+
3576+ properties.push_back (colr);
3577+ }
3578+ // set item properties
3579+ for (auto & propertyBox : properties) {
3580+ int index =
3581+ ctx->context ->get_heif_file ()->get_ipco_box ()->find_or_append_child_box (propertyBox);
3582+ ctx->context ->get_heif_file ()->get_ipma_box ()->add_property_for_item_ID (
3583+ tmap_item_id,
3584+ Box_ipma::PropertyAssociation{propertyBox->is_essential (), uint16_t (index + 1 )});
3585+ }
3586+
3587+ heif_encoding_options options;
3588+ set_default_encoding_options (options);
3589+ if (input_options != nullptr ) {
3590+ copy_options (options, *input_options);
3591+ }
3592+
3593+ auto gainmap_encoding_result = ctx->context ->encode_image (
3594+ alternate_image->image , encoder, options, heif_image_input_class_gain_map);
3595+ if (gainmap_encoding_result.error ) {
3596+ return gainmap_encoding_result.error .error_struct (ctx->context .get ());
3597+ }
3598+
3599+ std::shared_ptr<ImageItem> gain_map_image = *gainmap_encoding_result;
3600+ Error error = ctx->context ->link_gain_map (base_image_handle->image , gain_map_image, tmap_item_id);
3601+ if (error != Error::Ok) {
3602+ return error.error_struct (ctx->context .get ());
3603+ }
3604+
3605+ if (out_image_handle) {
3606+ *out_image_handle = new heif_image_handle;
3607+ (*out_image_handle)->image = std::move (gain_map_image);
3608+ (*out_image_handle)->context = ctx->context ;
3609+ }
3610+
3611+ // --- generate altr box
3612+ auto altr_box = std::make_shared<Box_EntityToGroup>();
3613+ altr_box->set_short_type (fourcc (" altr" ));
3614+ altr_box->set_group_id (ctx->context ->get_heif_file ()->get_unused_item_id ());
3615+
3616+ std::vector<heif_item_id> ids;
3617+ ids.push_back (tmap_item_id);
3618+ ids.push_back (base_image_handle->image ->get_id ());
3619+
3620+ altr_box->set_item_ids (ids);
3621+ ctx->context ->get_heif_file ()->add_entity_group_box (altr_box);
3622+
3623+ return heif_error_success;
3624+ }
3625+ #endif
3626+
3627+
34453628struct heif_error heif_context_encode_grid (struct heif_context * ctx,
34463629 struct heif_image ** tiles,
34473630 uint16_t columns,
0 commit comments