diff --git a/libheif/api/libheif/heif.cc b/libheif/api/libheif/heif.cc index 9192f5087e..8bdd2add46 100644 --- a/libheif/api/libheif/heif.cc +++ b/libheif/api/libheif/heif.cc @@ -1557,7 +1557,7 @@ void heif_image_get_content_light_level(const struct heif_image* image, struct h int heif_image_handle_get_content_light_level(const struct heif_image_handle* handle, struct heif_content_light_level* out) { - auto clli = handle->image->get_file()->get_property(handle->image->get_id()); + auto clli = handle->image->get_property(); if (out && clli) { *out = clli->clli; } @@ -1587,7 +1587,7 @@ void heif_image_get_mastering_display_colour_volume(const struct heif_image* ima int heif_image_handle_get_mastering_display_colour_volume(const struct heif_image_handle* handle, struct heif_mastering_display_colour_volume* out) { - auto mdcv = handle->image->get_file()->get_property(handle->image->get_id()); + auto mdcv = handle->image->get_property(); if (out && mdcv) { *out = mdcv->mdcv; } @@ -1664,7 +1664,7 @@ void heif_image_get_pixel_aspect_ratio(const struct heif_image* image, uint32_t* int heif_image_handle_get_pixel_aspect_ratio(const struct heif_image_handle* handle, uint32_t* aspect_h, uint32_t* aspect_v) { - auto pasp = handle->image->get_file()->get_property(handle->image->get_id()); + auto pasp = handle->image->get_property(); if (pasp) { *aspect_h = pasp->hSpacing; *aspect_v = pasp->vSpacing; diff --git a/libheif/api/libheif/heif_properties.cc b/libheif/api/libheif/heif_properties.cc index 4b43a02bd3..167e0aefec 100644 --- a/libheif/api/libheif/heif_properties.cc +++ b/libheif/api/libheif/heif_properties.cc @@ -389,7 +389,7 @@ struct heif_error heif_property_set_clock_info(struct heif_context* ctx, } // Create new taic if one doesn't exist for the itemId. - auto taic = ctx->context->get_heif_file()->get_property(itemId); + auto taic = ctx->context->get_heif_file()->get_property_for_item(itemId); if (!taic) { taic = std::make_shared(); } @@ -427,7 +427,7 @@ struct heif_error heif_property_get_clock_info(const struct heif_context* ctx, } // Check if taic exists for itemId - auto taic = file->get_property(itemId); + auto taic = file->get_property_for_item(itemId); if (!taic) { out_clock = nullptr; return {heif_error_Usage_error, heif_suberror_Invalid_property, "TAI Clock property not found for itemId"}; @@ -462,7 +462,7 @@ struct heif_error heif_property_set_tai_timestamp(struct heif_context* ctx, } // Create new itai if one doesn't exist for the itemId. - auto itai = file->get_property(itemId); + auto itai = file->get_property_for_item(itemId); if (!itai) { itai = std::make_shared(); } @@ -475,7 +475,7 @@ struct heif_error heif_property_set_tai_timestamp(struct heif_context* ctx, heif_property_id id = ctx->context->add_property(itemId, itai, false); // Create new taic if one doesn't exist for the itemId. - auto taic = file->get_property(itemId); + auto taic = file->get_property_for_item(itemId); if (!taic) { taic = std::make_shared(); ctx->context->add_property(itemId, taic, false); @@ -505,7 +505,7 @@ struct heif_error heif_property_get_tai_timestamp(const struct heif_context* ctx } //Check if itai exists for itemId - auto itai = file->get_property(itemId); + auto itai = file->get_property_for_item(itemId); if (!itai) { out_timestamp = nullptr; return {heif_error_Usage_error, heif_suberror_Invalid_property, "Timestamp property not found for itemId"}; diff --git a/libheif/box.cc b/libheif/box.cc index 875c1abf53..2070b6df68 100644 --- a/libheif/box.cc +++ b/libheif/box.cc @@ -899,22 +899,24 @@ Error Box::read_children(BitstreamRange& range, uint32_t max_number, const heif_ return error; } - uint32_t max_children; - if (get_short_type() == fourcc("iinf")) { - max_children = limits->max_items; - } - else { - max_children = limits->max_children_per_box; - } + if (max_number == READ_CHILDREN_ALL) { + uint32_t max_children; + if (get_short_type() == fourcc("iinf")) { + max_children = limits->max_items; + } + else { + max_children = limits->max_children_per_box; + } - if (max_children && m_children.size() > max_children) { - std::stringstream sstr; - sstr << "Maximum number of child boxes (" << max_children << ") in '" << get_type_string() << "' box exceeded."; + if (max_children && m_children.size() > max_children) { + std::stringstream sstr; + sstr << "Maximum number of child boxes (" << max_children << ") in '" << get_type_string() << "' box exceeded."; - // Sanity check. - return Error(heif_error_Memory_allocation_error, - heif_suberror_Security_limit_exceeded, - sstr.str()); + // Sanity check. + return Error(heif_error_Memory_allocation_error, + heif_suberror_Security_limit_exceeded, + sstr.str()); + } } m_children.push_back(std::move(box)); diff --git a/libheif/codecs/decoder.cc b/libheif/codecs/decoder.cc index 3632e607b2..2b376992ee 100644 --- a/libheif/codecs/decoder.cc +++ b/libheif/codecs/decoder.cc @@ -98,37 +98,39 @@ Result> DataExtent::read_data(uint64_t offset, uint64_t siz } -std::shared_ptr Decoder::alloc_for_infe_type(const HeifContext* ctx, heif_item_id id, uint32_t format_4cc) +std::shared_ptr Decoder::alloc_for_infe_type(const ImageItem* item) { + uint32_t format_4cc = item->get_infe_type(); + switch (format_4cc) { case fourcc("hvc1"): { - auto hvcC = ctx->get_heif_file()->get_property(id); + auto hvcC = item->get_property(); return std::make_shared(hvcC); } case fourcc("av01"): { - auto av1C = ctx->get_heif_file()->get_property(id); + auto av1C = item->get_property(); return std::make_shared(av1C); } case fourcc("avc1"): { - auto avcC = ctx->get_heif_file()->get_property(id); + auto avcC = item->get_property(); return std::make_shared(avcC); } case fourcc("j2k1"): { - auto j2kH = ctx->get_heif_file()->get_property(id); + auto j2kH = item->get_property(); return std::make_shared(j2kH); } case fourcc("vvc1"): { - auto vvcC = ctx->get_heif_file()->get_property(id); + auto vvcC = item->get_property(); return std::make_shared(vvcC); } case fourcc("jpeg"): { - auto jpgC = ctx->get_heif_file()->get_property(id); + auto jpgC = item->get_property(); return std::make_shared(jpgC); } #if WITH_UNCOMPRESSED_CODEC case fourcc("unci"): { - auto uncC = ctx->get_heif_file()->get_property(id); - auto cmpd = ctx->get_heif_file()->get_property(id); + auto uncC = item->get_property(); + auto cmpd = item->get_property(); return std::make_shared(uncC,cmpd); } #endif diff --git a/libheif/codecs/decoder.h b/libheif/codecs/decoder.h index f6d82b4a4b..e00091ec71 100644 --- a/libheif/codecs/decoder.h +++ b/libheif/codecs/decoder.h @@ -61,7 +61,7 @@ struct DataExtent class Decoder { public: - static std::shared_ptr alloc_for_infe_type(const HeifContext* ctx, heif_item_id, uint32_t format_4cc); + static std::shared_ptr alloc_for_infe_type(const ImageItem* item); virtual ~Decoder() = default; diff --git a/libheif/codecs/uncompressed/decoder_abstract.cc b/libheif/codecs/uncompressed/decoder_abstract.cc index 4ff8e7a469..bbe469204e 100644 --- a/libheif/codecs/uncompressed/decoder_abstract.cc +++ b/libheif/codecs/uncompressed/decoder_abstract.cc @@ -166,10 +166,16 @@ const Error AbstractDecoder::get_compressed_image_data_uncompressed(const HeifCo uint32_t tile_idx, const Box_iloc::Item* item) const { + auto image = context->get_image(ID, false); + if (!image) { + return {heif_error_Invalid_input, + heif_suberror_Nonexisting_item_referenced}; + } + // --- get codec configuration - std::shared_ptr cmpC_box = context->get_heif_file()->get_property(ID); - std::shared_ptr icef_box = context->get_heif_file()->get_property(ID); + std::shared_ptr cmpC_box = image->get_property(); + std::shared_ptr icef_box = image->get_property(); if (!cmpC_box) { // assume no generic compression diff --git a/libheif/codecs/uncompressed/unc_codec.cc b/libheif/codecs/uncompressed/unc_codec.cc index 49adab1ee3..cfca1c2d73 100644 --- a/libheif/codecs/uncompressed/unc_codec.cc +++ b/libheif/codecs/uncompressed/unc_codec.cc @@ -483,9 +483,15 @@ Error UncompressedImageCodec::decode_uncompressed_image_tile(const HeifContext* uint32_t tile_x0, uint32_t tile_y0) { auto file = context->get_heif_file(); - std::shared_ptr ispe = file->get_property(ID); - std::shared_ptr cmpd = file->get_property(ID); - std::shared_ptr uncC = file->get_property(ID); + auto image = context->get_image(ID, false); + if (!image) { + return {heif_error_Invalid_input, + heif_suberror_Nonexisting_item_referenced}; + } + + std::shared_ptr ispe = image->get_property(); + std::shared_ptr cmpd = image->get_property(); + std::shared_ptr uncC = image->get_property(); Error error = check_header_validity(ispe, cmpd, uncC); if (error) { @@ -589,9 +595,15 @@ Error UncompressedImageCodec::decode_uncompressed_image(const HeifContext* conte return error; } - std::shared_ptr ispe = context->get_heif_file()->get_property(ID); - std::shared_ptr cmpd = context->get_heif_file()->get_property(ID); - std::shared_ptr uncC = context->get_heif_file()->get_property(ID); + auto image = context->get_image(ID, false); + if (!image) { + return {heif_error_Invalid_input, + heif_suberror_Nonexisting_item_referenced}; + } + + std::shared_ptr ispe = image->get_property(); + std::shared_ptr cmpd = image->get_property(); + std::shared_ptr uncC = image->get_property(); error = check_header_validity(ispe, cmpd, uncC); if (error) { diff --git a/libheif/context.cc b/libheif/context.cc index f3fa925f7f..cfae6e9bce 100644 --- a/libheif/context.cc +++ b/libheif/context.cc @@ -354,7 +354,15 @@ Error HeifContext::interpret_heif_file() m_top_level_images.push_back(image); } - Error err = image->on_load_file(); + std::vector> properties; + Error err = m_heif_file->get_properties(id, properties); + if (err) { + return err; + } + + image->set_properties(properties); + + err = image->on_load_file(); if (err) { return err; } @@ -555,7 +563,7 @@ Error HeifContext::interpret_heif_file() // --- this is an auxiliary image // check whether it is an alpha channel and attach to the main image if yes - std::shared_ptr auxC_property = m_heif_file->get_property(image->get_id()); + std::shared_ptr auxC_property = image->get_property(); if (!auxC_property) { std::stringstream sstr; sstr << "No auxC property for image " << image->get_id(); @@ -1208,6 +1216,12 @@ Result> HeifContext::encode_image(const std::shared_p } } + std::vector> properties; + err = m_heif_file->get_properties(output_image_item->get_id(), properties); + if (err) { + return err; + } + output_image_item->set_properties(properties); m_heif_file->set_brand(encoder->plugin->compression_format, output_image_item->is_miaf_compatible()); diff --git a/libheif/file.h b/libheif/file.h index ec48d33ff5..1a1585a403 100644 --- a/libheif/file.h +++ b/libheif/file.h @@ -139,7 +139,7 @@ class HeifFile std::vector>& properties) const; template - std::shared_ptr get_property(heif_item_id imageID) const + std::shared_ptr get_property_for_item(heif_item_id imageID) const { std::vector> properties; Error err = get_properties(imageID, properties); diff --git a/libheif/image-items/avc.cc b/libheif/image-items/avc.cc index 33f2f1d1ba..d10abb29ec 100644 --- a/libheif/image-items/avc.cc +++ b/libheif/image-items/avc.cc @@ -128,7 +128,7 @@ std::shared_ptr ImageItem_AVC::get_decoder() const Error ImageItem_AVC::on_load_file() { - auto avcC_box = get_file()->get_property(get_id()); + auto avcC_box = get_property(); if (!avcC_box) { return Error{heif_error_Invalid_input, heif_suberror_No_av1C_box}; diff --git a/libheif/image-items/avif.cc b/libheif/image-items/avif.cc index c6d343803f..0ad212c274 100644 --- a/libheif/image-items/avif.cc +++ b/libheif/image-items/avif.cc @@ -38,7 +38,7 @@ Error ImageItem_AVIF::on_load_file() { - auto av1C_box = get_file()->get_property(get_id()); + auto av1C_box = get_property(); if (!av1C_box) { return Error{heif_error_Invalid_input, heif_suberror_No_av1C_box}; @@ -102,7 +102,7 @@ Result ImageItem_AVIF::encode(const std::shared_ptr> ImageItem_AVIF::read_bitstream_configuration_data(heif_item_id itemId) const +Result> ImageItem_AVIF::read_bitstream_configuration_data() const { return m_decoder->read_bitstream_configuration_data(); } diff --git a/libheif/image-items/avif.h b/libheif/image-items/avif.h index 65b98581b1..182df6f148 100644 --- a/libheif/image-items/avif.h +++ b/libheif/image-items/avif.h @@ -57,7 +57,7 @@ class ImageItem_AVIF : public ImageItem enum heif_image_input_class input_class) override; protected: - Result> read_bitstream_configuration_data(heif_item_id itemId) const override; + Result> read_bitstream_configuration_data() const override; std::shared_ptr get_decoder() const override; diff --git a/libheif/image-items/grid.cc b/libheif/image-items/grid.cc index 883b9f4b7c..6d739e9566 100644 --- a/libheif/image-items/grid.cc +++ b/libheif/image-items/grid.cc @@ -684,7 +684,7 @@ Error ImageItem_Grid::add_image_tile(heif_item_id grid_id, uint32_t tile_x, uint set_grid_tile_id(tile_x, tile_y, encoded_image->get_id()); // Add PIXI property (copy from first tile) - auto pixi = file->get_property(encoded_image->get_id()); + auto pixi = encoded_image->get_property(); file->add_property(grid_id, pixi, true); return Error::Ok; @@ -715,6 +715,8 @@ Result> ImageItem_Grid::add_and_encode_full_grid std::vector tile_ids; + std::shared_ptr pixi_property; + for (int i=0; i out_tile; auto encodingResult = ctx->encode_image(tiles[i], @@ -728,6 +730,10 @@ Result> ImageItem_Grid::add_and_encode_full_grid heif_item_id tile_id = out_tile->get_id(); file->get_infe_box(tile_id)->set_hidden_item(true); // only show the full grid tile_ids.push_back(out_tile->get_id()); + + if (!pixi_property) { + pixi_property = out_tile->get_property(); + } } // Create Grid Item @@ -750,8 +756,7 @@ Result> ImageItem_Grid::add_and_encode_full_grid // Add PIXI property (copy from first tile) - auto pixi = file->get_property(tile_ids[0]); - file->add_property(grid_id, pixi, true); + file->add_property(grid_id, pixi_property, true); // Set Brands diff --git a/libheif/image-items/hevc.cc b/libheif/image-items/hevc.cc index bba8f71c5c..ac1a73e0fd 100644 --- a/libheif/image-items/hevc.cc +++ b/libheif/image-items/hevc.cc @@ -36,7 +36,7 @@ Error ImageItem_HEVC::on_load_file() { - auto hvcC_box = get_file()->get_property(get_id()); + auto hvcC_box = get_property(); if (!hvcC_box) { return Error{heif_error_Invalid_input, heif_suberror_No_hvcC_box}; @@ -139,7 +139,7 @@ Result ImageItem_HEVC::encode(const std::shared_ptr> ImageItem_HEVC::read_bitstream_configuration_data(heif_item_id itemId) const +Result> ImageItem_HEVC::read_bitstream_configuration_data() const { return m_decoder->read_bitstream_configuration_data(); } diff --git a/libheif/image-items/hevc.h b/libheif/image-items/hevc.h index 50bedfeea8..3f077eb478 100644 --- a/libheif/image-items/hevc.h +++ b/libheif/image-items/hevc.h @@ -58,7 +58,7 @@ class ImageItem_HEVC : public ImageItem void set_preencoded_hevc_image(const std::vector& data); protected: - Result> read_bitstream_configuration_data(heif_item_id itemId) const override; + Result> read_bitstream_configuration_data() const override; std::shared_ptr get_decoder() const override; diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc index db24c7e6bb..1e9a551970 100644 --- a/libheif/image-items/image_item.cc +++ b/libheif/image-items/image_item.cc @@ -407,12 +407,12 @@ Error ImageItem::encode_to_item(HeifContext* ctx, bool ImageItem::has_ispe_resolution() const { - return m_heif_context->get_heif_file()->get_property(m_id) != nullptr; + return get_property() != nullptr; } uint32_t ImageItem::get_ispe_width() const { - auto ispe = m_heif_context->get_heif_file()->get_property(m_id); + auto ispe = get_property(); if (!ispe) { return 0; } @@ -424,7 +424,7 @@ uint32_t ImageItem::get_ispe_width() const uint32_t ImageItem::get_ispe_height() const { - auto ispe = m_heif_context->get_heif_file()->get_property(m_id); + auto ispe = get_property(); if (!ispe) { return 0; } @@ -740,7 +740,7 @@ Result> ImageItem::decode_image(const struct hei // --- check whether image size (according to 'ispe') exceeds maximum if (!decode_tile_only) { - auto ispe = m_heif_context->get_heif_file()->get_property(m_id); + auto ispe = get_property(); if (ispe) { Error err = check_for_valid_image_size(get_context()->get_security_limits(), ispe->get_width(), ispe->get_height()); if (err) { @@ -921,21 +921,21 @@ Result> ImageItem::decode_image(const struct hei // CLLI - auto clli = get_file()->get_property(m_id); + auto clli = get_property(); if (clli) { img->set_clli(clli->clli); } // MDCV - auto mdcv = get_file()->get_property(m_id); + auto mdcv = get_property(); if (mdcv) { img->set_mdcv(mdcv->mdcv); } // PASP - auto pasp = get_file()->get_property(m_id); + auto pasp = get_property(); if (pasp) { img->set_pixel_ratio(pasp->hSpacing, pasp->vSpacing); } @@ -944,7 +944,7 @@ Result> ImageItem::decode_image(const struct hei return img; } - +#if 0 Result> ImageItem::read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const { auto item_codec = ImageItem::alloc_for_compression_format(const_cast(get_context()), format); @@ -957,7 +957,7 @@ Result> ImageItem::read_bitstream_configuration_data_overri return item_codec->read_bitstream_configuration_data(itemId); } - +#endif Result> ImageItem::get_compressed_image_data() const { @@ -967,7 +967,7 @@ Result> ImageItem::get_compressed_image_data() const // data from configuration blocks - Result> confData = read_bitstream_configuration_data(get_id()); + Result> confData = read_bitstream_configuration_data(); if (confData.error) { return confData.error; } diff --git a/libheif/image-items/image_item.h b/libheif/image-items/image_item.h index 2d6a94eceb..ffafdd0fd0 100644 --- a/libheif/image-items/image_item.h +++ b/libheif/image-items/image_item.h @@ -80,7 +80,7 @@ class ImageItem : public ErrorBuffer virtual heif_compression_format get_compression_format() const { return heif_compression_undefined; } - virtual Result> read_bitstream_configuration_data(heif_item_id itemId) const { return std::vector{}; } + virtual Result> read_bitstream_configuration_data() const { return std::vector{}; } void clear() { @@ -96,6 +96,22 @@ class ImageItem : public ErrorBuffer std::shared_ptr get_file() const; + void set_properties(std::vector> properties) { + m_properties = std::move(properties); + } + + template + std::shared_ptr get_property() const + { + for (auto& property : m_properties) { + if (auto box = std::dynamic_pointer_cast(property)) { + return box; + } + } + + return nullptr; + } + void set_resolution(uint32_t w, uint32_t h) { m_width = w; @@ -363,6 +379,7 @@ class ImageItem : public ErrorBuffer private: HeifContext* m_heif_context; + std::vector> m_properties; heif_item_id m_id = 0; uint32_t m_width = 0, m_height = 0; // after all transformations have been applied @@ -404,7 +421,7 @@ class ImageItem : public ErrorBuffer std::vector m_decoding_warnings; protected: - Result> read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const; + // Result> read_bitstream_configuration_data_override(heif_item_id itemId, heif_compression_format format) const; virtual Result encode(const std::shared_ptr& image, struct heif_encoder* encoder, diff --git a/libheif/image-items/jpeg.cc b/libheif/image-items/jpeg.cc index fe4b6d3607..d8ff590cc1 100644 --- a/libheif/image-items/jpeg.cc +++ b/libheif/image-items/jpeg.cc @@ -112,7 +112,7 @@ Result ImageItem_JPEG::encode(const std::shared_ptr> ImageItem_JPEG::read_bitstream_configuration_data(heif_item_id itemId) const +Result> ImageItem_JPEG::read_bitstream_configuration_data() const { return m_decoder->read_bitstream_configuration_data(); } @@ -126,7 +126,7 @@ std::shared_ptr ImageItem_JPEG::get_decoder() const Error ImageItem_JPEG::on_load_file() { // Note: jpgC box is optional. NULL is a valid value. - auto jpgC_box = get_file()->get_property(get_id()); + auto jpgC_box = get_property(); m_decoder = std::make_shared(jpgC_box); diff --git a/libheif/image-items/jpeg.h b/libheif/image-items/jpeg.h index ecc9bd7533..45abd574ef 100644 --- a/libheif/image-items/jpeg.h +++ b/libheif/image-items/jpeg.h @@ -54,7 +54,7 @@ class ImageItem_JPEG : public ImageItem protected: std::shared_ptr get_decoder() const override; - Result> read_bitstream_configuration_data(heif_item_id itemId) const override; + Result> read_bitstream_configuration_data() const override; private: std::shared_ptr m_decoder; diff --git a/libheif/image-items/jpeg2000.cc b/libheif/image-items/jpeg2000.cc index 30f2e17577..9d9a48719d 100644 --- a/libheif/image-items/jpeg2000.cc +++ b/libheif/image-items/jpeg2000.cc @@ -69,11 +69,11 @@ Result ImageItem_JPEG2000::encode(const std::shared_p } -Result> ImageItem_JPEG2000::read_bitstream_configuration_data(heif_item_id itemId) const +Result> ImageItem_JPEG2000::read_bitstream_configuration_data() const { // --- get codec configuration - std::shared_ptr j2kH_box = get_file()->get_property(itemId); + std::shared_ptr j2kH_box = get_property(); if (!j2kH_box) { // TODO - Correctly Find the j2kH box @@ -95,7 +95,7 @@ std::shared_ptr ImageItem_JPEG2000::get_decoder() const Error ImageItem_JPEG2000::on_load_file() { - auto j2kH = get_file()->get_property(get_id()); + auto j2kH = get_property(); if (!j2kH) { return Error{heif_error_Invalid_input, heif_suberror_Unspecified, diff --git a/libheif/image-items/jpeg2000.h b/libheif/image-items/jpeg2000.h index be6471dfc1..da1f834a58 100644 --- a/libheif/image-items/jpeg2000.h +++ b/libheif/image-items/jpeg2000.h @@ -47,7 +47,7 @@ class ImageItem_JPEG2000 : public ImageItem enum heif_image_input_class input_class) override; protected: - Result> read_bitstream_configuration_data(heif_item_id itemId) const override; + Result> read_bitstream_configuration_data() const override; std::shared_ptr get_decoder() const override; diff --git a/libheif/image-items/mask_image.cc b/libheif/image-items/mask_image.cc index 98ddb06501..c9adc67c3a 100644 --- a/libheif/image-items/mask_image.cc +++ b/libheif/image-items/mask_image.cc @@ -62,8 +62,14 @@ Error MaskImageCodec::decode_mask_image(const HeifContext* context, std::shared_ptr& img, const std::vector& data) { - std::shared_ptr ispe = context->get_heif_file()->get_property(ID); - std::shared_ptr mskC = context->get_heif_file()->get_property(ID); + auto image = context->get_image(ID, false); + if (!image) { + return {heif_error_Invalid_input, + heif_suberror_Nonexisting_item_referenced}; + } + + std::shared_ptr ispe = image->get_property(); + std::shared_ptr mskC = image->get_property(); uint32_t width = 0; uint32_t height = 0; @@ -193,7 +199,7 @@ Result ImageItem_mask::encode(const std::shared_ptrget_property(get_id()); + auto mskC = get_property(); if (!mskC) { return -1; } diff --git a/libheif/image-items/overlay.cc b/libheif/image-items/overlay.cc index eec4bd0f31..0b64af45a5 100644 --- a/libheif/image-items/overlay.cc +++ b/libheif/image-items/overlay.cc @@ -427,7 +427,7 @@ Result> ImageItem_Overlay::add_new_overlay_it file->add_ispe_property(iovl_id, overlayspec.get_canvas_width(), overlayspec.get_canvas_height(), false); // Add PIXI property (copy from first image) - According to MIAF, all images shall have the same color information. - auto pixi = file->get_property(ref_ids[0]); + auto pixi = file->get_property_for_item(ref_ids[0]); file->add_property(iovl_id, pixi, true); // Set Brands diff --git a/libheif/image-items/tiled.cc b/libheif/image-items/tiled.cc index e26a0792ee..0adf0d707c 100644 --- a/libheif/image-items/tiled.cc +++ b/libheif/image-items/tiled.cc @@ -157,6 +157,18 @@ Error Box_tilC::write(StreamWriter& writer) const writer.write32(m_parameters.extra_dimensions[i]); } + auto& tile_properties = m_children; + if (tile_properties.size() > 255) { + return {heif_error_Encoding_error, + heif_suberror_Unspecified, + "Cannot write more than 255 tile properties in tilC header"}; + } + + writer.write8(static_cast(tile_properties.size())); + for (const auto& property : tile_properties) { + property->write(writer); + } + prepend_header(writer, box_start); return Error::Ok; @@ -178,6 +190,9 @@ std::string Box_tilC::dump(Indent& indent) const << indent << "size field length: " << ((int) m_parameters.size_field_length) << " bits\n" << indent << "number of extra dimensions: " << ((int) m_parameters.number_of_extra_dimensions) << "\n"; + sstr << indent << "tile properties:\n" + << dump_children(indent, true); + return sstr.str(); } @@ -266,6 +281,18 @@ Error Box_tilC::parse(BitstreamRange& range, const heif_security_limits* limits) } } + // --- read tile properties + + // Check version for backwards compatibility with old format. + // TODO: remove when spec is final and old test images have been converted + if (get_version() == 0) { + uint8_t num_properties = range.read8(); + + Error error = read_children(range, num_properties, limits); + if (error) { + return error; + } + } return range.get_error(); } @@ -476,14 +503,14 @@ Error ImageItem_Tiled::on_load_file() { auto heif_file = get_context()->get_heif_file(); - auto tilC_box = heif_file->get_property(get_id()); + auto tilC_box = get_property(); if (!tilC_box) { return {heif_error_Invalid_input, heif_suberror_Unspecified, "Tiled image without 'tilC' property box."}; } - auto ispe_box = heif_file->get_property(get_id()); + auto ispe_box = get_property(); if (!ispe_box) { return {heif_error_Invalid_input, heif_suberror_Unspecified, @@ -504,7 +531,29 @@ Error ImageItem_Tiled::on_load_file() return err; } - m_tile_decoder = Decoder::alloc_for_infe_type(get_context(), get_id(), parameters.compression_format_fourcc); + + // --- create a dummy image item for decoding tiles + + heif_compression_format format = compression_format_from_fourcc_infe_type(m_tild_header.get_parameters().compression_format_fourcc); + m_tile_item = ImageItem::alloc_for_compression_format(get_context(), format); + + // For backwards compatibility: copy over properties from `tili` item. + // TODO: remove when spec is final and old test images have been converted + if (tilC_box->get_version() == 1) { + auto propertiesResult = get_properties(); + if (propertiesResult.error) { + return propertiesResult.error; + } + + m_tile_item->set_properties(*propertiesResult); + } + else { + // This is the new method + + m_tile_item->set_properties(tilC_box->get_all_child_boxes()); + } + + m_tile_decoder = Decoder::alloc_for_infe_type(m_tile_item.get()); if (!m_tile_decoder) { return {heif_error_Unsupported_feature, heif_suberror_Unsupported_codec, @@ -517,6 +566,7 @@ Error ImageItem_Tiled::on_load_file() } } + return Error::Ok; } @@ -639,27 +689,30 @@ Error ImageItem_Tiled::add_image_tile(uint32_t tile_x, uint32_t tile_y, header.set_tild_tile_range(tile_x, tile_y, offset, static_cast(dataSize)); set_next_tild_position(offset + encodeResult.value.bitstream.size()); - std::vector> existing_properties; - Error err = get_file()->get_properties(get_id(), existing_properties); - if (err) { - return err; - } + auto tilC = get_property(); + assert(tilC); - for (auto& propertyBox : encodeResult.value.properties) { - if (propertyBox->get_short_type() == fourcc("ispe")) { - continue; - } + std::vector>& tile_properties = tilC->get_tile_properties(); + for (auto& propertyBox : encodeResult.value.properties) { // skip properties that exist already - bool exists = std::any_of(existing_properties.begin(), - existing_properties.end(), + bool exists = std::any_of(tile_properties.begin(), + tile_properties.end(), [&propertyBox](const std::shared_ptr& p) { return p->get_short_type() == propertyBox->get_short_type();}); if (exists) { continue; } - get_file()->add_property(get_id(), propertyBox, propertyBox->is_essential()); + tile_properties.emplace_back(propertyBox); + + // some tile properties are also added to the tili image + + switch (propertyBox->get_short_type()) { + case fourcc("pixi"): + get_file()->add_property(get_id(), propertyBox, propertyBox->is_essential()); + break; + } } get_file()->set_brand(encoder->plugin->compression_format, @@ -717,21 +770,23 @@ Error ImageItem_Tiled::append_compressed_tile_data(std::vector& data, u } -Result> -ImageItem_Tiled::decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const +Result +ImageItem_Tiled::get_compressed_data_for_tile(uint32_t tx, uint32_t ty) const { - heif_compression_format format = compression_format_from_fourcc_infe_type( - m_tild_header.get_parameters().compression_format_fourcc); - // --- get compressed data - Result> dataResult = read_bitstream_configuration_data_override(get_id(), format); + Error err = m_tile_item->init_decoder_from_item(0); + if (err) { + return err; + } + + Result> dataResult = m_tile_item->read_bitstream_configuration_data(); if (dataResult.error) { return dataResult.error; } std::vector& data = dataResult.value; - Error err = append_compressed_tile_data(data, tx, ty); + err = append_compressed_tile_data(data, tx, ty); if (err) { return err; } @@ -741,7 +796,19 @@ ImageItem_Tiled::decode_grid_tile(const heif_decoding_options& options, uint32_t DataExtent extent; extent.m_raw = data; - m_tile_decoder->set_data_extent(std::move(extent)); + return extent; +} + + +Result> +ImageItem_Tiled::decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const +{ + Result extentResult = get_compressed_data_for_tile(tx, ty); + if (extentResult.error) { + return extentResult.error; + } + + m_tile_decoder->set_data_extent(std::move(*extentResult)); return m_tile_decoder->decode_single_frame_from_compressed_data(options); } @@ -786,6 +853,15 @@ void ImageItem_Tiled::get_tile_size(uint32_t& w, uint32_t& h) const Error ImageItem_Tiled::get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const { + uint32_t tx=0, ty=0; // TODO: find a tile that is defined. + + Result extentResult = get_compressed_data_for_tile(tx, ty); + if (extentResult.error) { + return extentResult.error; + } + + m_tile_decoder->set_data_extent(std::move(*extentResult)); + Error err = m_tile_decoder->get_coded_image_colorspace(out_colorspace, out_chroma); if (err) { return err; diff --git a/libheif/image-items/tiled.h b/libheif/image-items/tiled.h index 0909305e29..4ff32afa89 100644 --- a/libheif/image-items/tiled.h +++ b/libheif/image-items/tiled.h @@ -23,6 +23,7 @@ #include "image_item.h" +#include "codecs/decoder.h" #include "box.h" #include #include @@ -69,6 +70,10 @@ class Box_tilC : public FullBox std::string dump(Indent&) const override; + std::vector>& get_tile_properties() { return m_children; } + + const std::vector>& get_tile_properties() const { return m_children; } + protected: Error parse(BitstreamRange& range, const heif_security_limits* limits) override; @@ -198,8 +203,12 @@ class ImageItem_Tiled : public ImageItem uint32_t mReadChunkSize_bytes = 64*1024; // 64 kiB bool m_preload_offset_table = false; + std::shared_ptr m_tile_item; std::shared_ptr m_tile_decoder; + Result + get_compressed_data_for_tile(uint32_t tx, uint32_t ty) const; + Result> decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const; Error load_tile_offset_entry(uint32_t idx); diff --git a/libheif/image-items/unc_image.cc b/libheif/image-items/unc_image.cc index 2bba6342bc..10593f98a2 100644 --- a/libheif/image-items/unc_image.cc +++ b/libheif/image-items/unc_image.cc @@ -404,7 +404,7 @@ Result> ImageItem_uncompressed::add_unci Error ImageItem_uncompressed::add_image_tile(uint32_t tile_x, uint32_t tile_y, const std::shared_ptr& image) { - std::shared_ptr uncC = get_file()->get_property(get_id()); + std::shared_ptr uncC = get_property(); assert(uncC); uint32_t tile_width = image->get_width(); @@ -417,8 +417,8 @@ Error ImageItem_uncompressed::add_image_tile(uint32_t tile_x, uint32_t tile_y, c return codedBitstreamResult.error; } - std::shared_ptr cmpC = get_file()->get_property(get_id()); - std::shared_ptr icef = get_file()->get_property(get_id()); + std::shared_ptr cmpC = get_property(); + std::shared_ptr icef = get_property(); if (!icef || !cmpC) { assert(!icef); @@ -471,8 +471,8 @@ Error ImageItem_uncompressed::add_image_tile(uint32_t tile_x, uint32_t tile_y, c void ImageItem_uncompressed::get_tile_size(uint32_t& w, uint32_t& h) const { - auto ispe = get_file()->get_property(get_id()); - auto uncC = get_file()->get_property(get_id()); + auto ispe = get_property(); + auto uncC = get_property(); if (!ispe || !uncC) { w = h = 0; @@ -488,8 +488,8 @@ heif_image_tiling ImageItem_uncompressed::get_heif_image_tiling() const { heif_image_tiling tiling{}; - auto ispe = get_file()->get_property(get_id()); - auto uncC = get_file()->get_property(get_id()); + auto ispe = get_property(); + auto uncC = get_property(); assert(ispe && uncC); tiling.num_columns = uncC->get_number_of_tile_columns(); @@ -512,8 +512,8 @@ std::shared_ptr ImageItem_uncompressed::get_decoder() const Error ImageItem_uncompressed::on_load_file() { - std::shared_ptr cmpd = get_file()->get_property(get_id()); - std::shared_ptr uncC = get_file()->get_property(get_id()); + std::shared_ptr cmpd = get_property(); + std::shared_ptr uncC = get_property(); if (!uncC) { return Error{heif_error_Invalid_input, diff --git a/libheif/image-items/vvc.cc b/libheif/image-items/vvc.cc index 81be35d674..6377c26700 100644 --- a/libheif/image-items/vvc.cc +++ b/libheif/image-items/vvc.cc @@ -94,11 +94,11 @@ Result ImageItem_VVC::encode(const std::shared_ptr> ImageItem_VVC::read_bitstream_configuration_data(heif_item_id itemId) const +Result> ImageItem_VVC::read_bitstream_configuration_data() const { // --- get codec configuration - std::shared_ptr vvcC_box = get_file()->get_property(itemId); + std::shared_ptr vvcC_box = get_property(); if (!vvcC_box) { assert(false); @@ -124,7 +124,7 @@ std::shared_ptr ImageItem_VVC::get_decoder() const Error ImageItem_VVC::on_load_file() { - auto vvcC_box = get_file()->get_property(get_id()); + auto vvcC_box = get_property(); if (!vvcC_box) { return Error{heif_error_Invalid_input, heif_suberror_No_av1C_box}; diff --git a/libheif/image-items/vvc.h b/libheif/image-items/vvc.h index 384e7e9507..9a9a052021 100644 --- a/libheif/image-items/vvc.h +++ b/libheif/image-items/vvc.h @@ -53,7 +53,7 @@ class ImageItem_VVC : public ImageItem protected: std::shared_ptr get_decoder() const override; - Result> read_bitstream_configuration_data(heif_item_id itemId) const override; + Result> read_bitstream_configuration_data() const override; private: std::shared_ptr m_decoder; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index cbad04c730..0dbae17ea2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,7 +7,9 @@ set(TESTING_DATA_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data") set(LIBHEIFIO_TESTING_DATA_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/heifio") configure_file(test-config.cc.in ${CMAKE_BINARY_DIR}/generated/test-config.cc) -set_source_files_properties(catch_amalgamated.cpp PROPERTIES COMPILE_FLAGS -Wno-conversion) +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set_source_files_properties(catch_amalgamated.cpp PROPERTIES COMPILE_FLAGS -Wno-conversion) +endif() add_library(testframework STATIC ${CMAKE_BINARY_DIR}/generated/test-config.cc test_utils.cc catch_amalgamated.cpp)