From 3b1cc737fbacb967ec584aa7ad71a81997cc9ffd 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 | 2 ++ libheif/file.cc | 51 +++++++++++++++++++++++++++++++++++++-- libheif/file.h | 6 +++-- libheif/heif.h | 3 +++ libheif/heif_emscripten.h | 1 + 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/go/heif/heif.go b/go/heif/heif.go index ad2fa5b641..e8fe9e11d2 100644 --- a/go/heif/heif.go +++ b/go/heif/heif.go @@ -301,6 +301,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 db8d6eaaa0..401aaf6065 100644 --- a/libheif/error.cc +++ b/libheif/error.cc @@ -158,6 +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"; case heif_suberror_Invalid_J2K_codestream: return "Invalid JPEG 2000 codestream"; diff --git a/libheif/file.cc b/libheif/file.cc index 51786da4eb..1752387bf9 100644 --- a/libheif/file.cc +++ b/libheif/file.cc @@ -398,7 +398,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); @@ -406,7 +406,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, @@ -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) { + 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 18de2962df..b6245776d2 100644 --- a/libheif/file.h +++ b/libheif/file.h @@ -232,15 +232,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 1c3eb7089d..c30ea1bf1b 100644 --- a/libheif/heif.h +++ b/libheif/heif.h @@ -229,6 +229,9 @@ 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, + // Invalid JPEG 2000 codestream - usually a missing marker heif_suberror_Invalid_J2K_codestream = 140, diff --git a/libheif/heif_emscripten.h b/libheif/heif_emscripten.h index fe79be19f6..4aa753b5d1 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_Invalid_J2K_codestream", heif_suberror_Invalid_J2K_codestream) .value("heif_suberror_Unsupported_codec", heif_suberror_Unsupported_codec) .value("heif_suberror_Unsupported_image_type", heif_suberror_Unsupported_image_type)