From 457c78b047dabb3aaf4ea93c1285573705d8842b Mon Sep 17 00:00:00 2001 From: Brad Hards Date: Sat, 6 Jan 2024 12:04:09 +1100 Subject: [PATCH] handle iden derived images --- go/heif/heif.go | 2 ++ libheif/error.cc | 3 ++- libheif/file.cc | 55 ++++++++++++++++++++++++++++++++++++--- libheif/file.h | 6 +++-- libheif/heif.h | 2 ++ libheif/heif_emscripten.h | 1 + 6 files changed, 62 insertions(+), 7 deletions(-) diff --git a/go/heif/heif.go b/go/heif/heif.go index 0c01f362f0..34092c36be 100644 --- a/go/heif/heif.go +++ b/go/heif/heif.go @@ -300,6 +300,8 @@ const ( SuberrorInvalidRegionData = C.heif_suberror_Invalid_region_data + SuberrorMissingIrefReference = C.heif_suberror_missing_iref_reference + SuberrorWrongTileImagePixelDepth = C.heif_suberror_Wrong_tile_image_pixel_depth SuberrorUnknownNCLXColorPrimaries = C.heif_suberror_Unknown_NCLX_color_primaries diff --git a/libheif/error.cc b/libheif/error.cc index 0d78d618ab..fd0a9844b7 100644 --- a/libheif/error.cc +++ b/libheif/error.cc @@ -158,7 +158,8 @@ const char* Error::get_error_string(heif_suberror_code err) return "Unknown NCLX matrix coefficients"; case heif_suberror_Invalid_region_data: return "Invalid region item data"; - + case heif_suberror_missing_iref_reference: + return "'iref' box does not include a referenced item"; // --- Memory_allocation_error --- diff --git a/libheif/file.cc b/libheif/file.cc index cea8f9fcbc..76fbe89c02 100644 --- a/libheif/file.cc +++ b/libheif/file.cc @@ -365,7 +365,7 @@ Error HeifFile::parse_heif_file(BitstreamRange& range) m_iref_box = std::dynamic_pointer_cast(m_meta_box->get_child_box(fourcc("iref"))); if (m_iref_box) { Error error = check_for_ref_cycle(get_primary_image_ID(), m_iref_box); - if (error) { + if (error != Error::Ok) { return error; } } @@ -397,7 +397,7 @@ Error HeifFile::parse_heif_file(BitstreamRange& range) Error HeifFile::check_for_ref_cycle(heif_item_id ID, - std::shared_ptr& iref_box) const + const std::shared_ptr& iref_box) const { std::unordered_set parent_items; return check_for_ref_cycle_recursion(ID, iref_box, parent_items); @@ -405,7 +405,7 @@ Error HeifFile::check_for_ref_cycle(heif_item_id ID, Error HeifFile::check_for_ref_cycle_recursion(heif_item_id ID, - std::shared_ptr& iref_box, + const std::shared_ptr& iref_box, std::unordered_set& parent_items) const { if (parent_items.find(ID) != parent_items.end()) { return Error(heif_error_Invalid_input, @@ -417,7 +417,7 @@ Error HeifFile::check_for_ref_cycle_recursion(heif_item_id ID, std::vector image_references = iref_box->get_references(ID, fourcc("dimg")); for (heif_item_id reference_idx : image_references) { Error error = check_for_ref_cycle_recursion(reference_idx, iref_box, parent_items); - if (error) { + if (error != Error::Ok) { return error; } } @@ -697,6 +697,43 @@ int HeifFile::jpeg_get_bits_per_pixel(heif_item_id imageID) const return -1; } +Error HeifFile::get_source_image_id(const heif_item_id from_ID, heif_item_id *to_ID) const +{ + // At this point iref is required (see ISO/IEC 23008-12:2022 Section 6.6.2.1) + if (!m_iref_box) { + return Error(heif_error_Invalid_input, + heif_suberror_No_iref_box); + } + Error error = check_for_ref_cycle(from_ID, m_iref_box); + if (error != Error::Ok) { + return error; + } + std::vector references = m_iref_box->get_references(from_ID, fourcc_to_uint32("dimg")); + if (references.size() != 1) { + return Error(heif_error_Invalid_input, + heif_suberror_missing_iref_reference); + } + heif_item_id id = references[0]; + + if (!image_exists(id)) { + return Error(heif_error_Usage_error, + heif_suberror_Nonexisting_item_referenced); + } + + auto infe_box = get_infe(id); + if (!infe_box) { + return Error(heif_error_Usage_error, + heif_suberror_Nonexisting_item_referenced); + } + + std::string item_type = infe_box->get_item_type(); + if (item_type == "iden") { + return get_source_image_id(id, to_ID); + } + *to_ID = id; + + return Error::Ok; +} Error HeifFile::get_compressed_image_data(heif_item_id ID, std::vector* data) const { @@ -719,6 +756,16 @@ Error HeifFile::get_compressed_image_data(heif_item_id ID, std::vector* std::string item_type = infe_box->get_item_type(); std::string content_type = infe_box->get_content_type(); + if (item_type == "iden") { + // we want to return the image data for the source image + heif_item_id to_ID = 0; + Error error = get_source_image_id(ID, &to_ID); + if (error.error_code != heif_error_Ok) { + return error; + } + ID = to_ID; + } + // --- get coded image data pointers auto items = m_iloc_box->get_items(); diff --git a/libheif/file.h b/libheif/file.h index 3715bab98c..5aac1abc0a 100644 --- a/libheif/file.h +++ b/libheif/file.h @@ -221,15 +221,17 @@ class HeifFile Error parse_heif_file(BitstreamRange& bitstream); Error check_for_ref_cycle(heif_item_id ID, - std::shared_ptr& iref_box) const; + const std::shared_ptr& iref_box) const; Error check_for_ref_cycle_recursion(heif_item_id ID, - std::shared_ptr& iref_box, + const std::shared_ptr& iref_box, std::unordered_set& parent_items) const; std::shared_ptr get_infe(heif_item_id ID) const; int jpeg_get_bits_per_pixel(heif_item_id imageID) const; + + Error get_source_image_id(const heif_item_id to_ID, heif_item_id *from_ID) const; }; #endif diff --git a/libheif/heif.h b/libheif/heif.h index 2c65a01366..70594be646 100644 --- a/libheif/heif.h +++ b/libheif/heif.h @@ -229,6 +229,8 @@ enum heif_suberror_code // Invalid specification of region item heif_suberror_Invalid_region_data = 136, + // An item was referenced, but the iref entry didn't include it + heif_suberror_missing_iref_reference = 137, // --- Memory_allocation_error --- diff --git a/libheif/heif_emscripten.h b/libheif/heif_emscripten.h index 395e1a7566..4f5453e761 100644 --- a/libheif/heif_emscripten.h +++ b/libheif/heif_emscripten.h @@ -353,6 +353,7 @@ EMSCRIPTEN_BINDINGS(libheif) { .value("heif_suberror_Item_reference_cycle", heif_suberror_Item_reference_cycle) .value("heif_suberror_Invalid_pixi_box", heif_suberror_Invalid_pixi_box) .value("heif_suberror_Invalid_region_data", heif_suberror_Invalid_region_data) + .value("heif_suberror_missing_iref_reference", heif_suberror_missing_iref_reference) .value("heif_suberror_Unsupported_codec", heif_suberror_Unsupported_codec) .value("heif_suberror_Unsupported_image_type", heif_suberror_Unsupported_image_type) .value("heif_suberror_Unsupported_data_version", heif_suberror_Unsupported_data_version)