From 02ebde0504ba18f46bdf24c25f3384860a82e294 Mon Sep 17 00:00:00 2001 From: Dirk Farin Date: Sun, 18 Aug 2024 18:37:21 +0200 Subject: [PATCH] move 'grid' image tile access to codecs --- libheif/api/libheif/heif.cc | 148 +++++++++++++++--------------------- libheif/codecs/grid.cc | 18 ++++- libheif/codecs/grid.h | 2 + libheif/context.cc | 5 +- libheif/context.h | 3 +- 5 files changed, 86 insertions(+), 90 deletions(-) diff --git a/libheif/api/libheif/heif.cc b/libheif/api/libheif/heif.cc index 4a0b14739e..7adbd03eaa 100644 --- a/libheif/api/libheif/heif.cc +++ b/libheif/api/libheif/heif.cc @@ -938,65 +938,6 @@ struct heif_error heif_image_handle_get_tile_size(const struct heif_image_handle } -// TODO: move this into the Context. But first, we also have to move heif_decode_image() into Context. -struct heif_error heif_image_handle_decode_image_tile(const struct heif_image_handle* handle, - struct heif_image** out_img, - enum heif_colorspace colorspace, - enum heif_chroma chroma, - const struct heif_decoding_options* options, - uint64_t x0, uint64_t y0, uint64_t z0) -{ - if (!handle) { - return error_null_parameter; - } - - std::shared_ptr gridItem = std::dynamic_pointer_cast(handle->image); - if (gridItem) { - if (z0 != 0) { - return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "z0 must be 0 for 2D images"}; - } - - if (x0 > 0xFFFFFFFF || y0 > 0xFFFFFFFF) { - return {heif_error_Usage_error, heif_suberror_Invalid_parameter_value, "x0/y0 currently must be 32 bit"}; - } - - heif_item_id first_tile_id = gridItem->get_grid_tiles()[0]; - auto tile = handle->context->get_image(first_tile_id); - - const ImageGrid& gridspec = gridItem->get_grid_spec(); - uint32_t tile_x = static_cast(x0) / tile->get_width(); - uint32_t tile_y = static_cast(y0) / tile->get_height(); - - heif_item_id tile_id = gridItem->get_grid_tiles()[tile_y * gridspec.get_columns() + tile_x]; - heif_image_handle* tile_handle; - heif_context* ctx = heif_image_handle_get_context(handle); - heif_error err = heif_context_get_image_handle(ctx, tile_id, &tile_handle); - if (err.code) { - heif_image_handle_release(tile_handle); - heif_context_free(ctx); - err.message = nullptr; // have to delete the text pointer because the text may be deleted with the context (TODO) - return err; - } - - heif_context_free(ctx); - err = heif_decode_image(tile_handle, out_img, colorspace, chroma, options); - if (err.code) { - heif_image_handle_release(tile_handle); - err.message = nullptr; // have to delete the text pointer because the text may be deleted with the context (TODO) - return err; - } - - heif_image_handle_release(tile_handle); - - return heif_error_success; - } - - // --- fallback: decode the whole image - - return heif_decode_image(handle, out_img, colorspace, chroma, options); -} - - struct heif_error heif_context_add_pyramid_entity_group(struct heif_context* ctx, uint16_t tile_width, uint16_t tile_height, @@ -1198,29 +1139,37 @@ void fill_default_decoding_options(heif_decoding_options& options) } -static void copy_options(heif_decoding_options& options, const heif_decoding_options& input_options) +// overwrite the (possibly lower version) input options over the default options +static heif_decoding_options normalize_options(const heif_decoding_options* input_options) { - switch (input_options.version) { - case 5: - options.color_conversion_options = input_options.color_conversion_options; - // fallthrough - case 4: - options.decoder_id = input_options.decoder_id; - // fallthrough - case 3: - options.strict_decoding = input_options.strict_decoding; - // fallthrough - case 2: - options.convert_hdr_to_8bit = input_options.convert_hdr_to_8bit; - // fallthrough - case 1: - options.ignore_transformations = input_options.ignore_transformations; + heif_decoding_options options{}; + fill_default_decoding_options(options); - options.start_progress = input_options.start_progress; - options.on_progress = input_options.on_progress; - options.end_progress = input_options.end_progress; - options.progress_user_data = input_options.progress_user_data; + if (input_options) { + switch (input_options->version) { + case 5: + options.color_conversion_options = input_options->color_conversion_options; + // fallthrough + case 4: + options.decoder_id = input_options->decoder_id; + // fallthrough + case 3: + options.strict_decoding = input_options->strict_decoding; + // fallthrough + case 2: + options.convert_hdr_to_8bit = input_options->convert_hdr_to_8bit; + // fallthrough + case 1: + options.ignore_transformations = input_options->ignore_transformations; + + options.start_progress = input_options->start_progress; + options.on_progress = input_options->on_progress; + options.end_progress = input_options->end_progress; + options.progress_user_data = input_options->progress_user_data; + } } + + return options; } @@ -1248,18 +1197,47 @@ struct heif_error heif_decode_image(const struct heif_image_handle* in_handle, { heif_item_id id = in_handle->image->get_id(); - heif_decoding_options dec_options; - fill_default_decoding_options(dec_options); + heif_decoding_options dec_options = normalize_options(input_options); - if (input_options != nullptr) { - // overwrite the (possibly lower version) input options over the default options - copy_options(dec_options, *input_options); + Result> decodingResult = in_handle->context->decode_image(id, + colorspace, + chroma, + dec_options, + false, 0,0); + if (decodingResult.error.error_code != heif_error_Ok) { + return decodingResult.error.error_struct(in_handle->image.get()); + } + + std::shared_ptr img = decodingResult.value; + + *out_img = new heif_image(); + (*out_img)->image = std::move(img); + + return Error::Ok.error_struct(in_handle->image.get()); +} + + +// TODO: move this into the Context. But first, we also have to move heif_decode_image() into Context. +struct heif_error heif_image_handle_decode_image_tile(const struct heif_image_handle* in_handle, + struct heif_image** out_img, + enum heif_colorspace colorspace, + enum heif_chroma chroma, + const struct heif_decoding_options* input_options, + uint64_t x0, uint64_t y0, uint64_t z0) +{ + if (!in_handle) { + return error_null_parameter; } + heif_item_id id = in_handle->image->get_id(); + + heif_decoding_options dec_options = normalize_options(input_options); + Result> decodingResult = in_handle->context->decode_image(id, colorspace, chroma, - dec_options); + dec_options, + true, x0,y0); if (decodingResult.error.error_code != heif_error_Ok) { return decodingResult.error.error_struct(in_handle->image.get()); } diff --git a/libheif/codecs/grid.cc b/libheif/codecs/grid.cc index dde2a3f28d..449778ee1d 100644 --- a/libheif/codecs/grid.cc +++ b/libheif/codecs/grid.cc @@ -51,6 +51,8 @@ Error ImageGrid::parse(const std::vector& data) m_rows = static_cast(data[2] + 1); m_columns = static_cast(data[3] + 1); + printf("rows:%d columns:%d\n", m_rows, m_columns); + if (field_size == 32) { if (data.size() < 12) { return Error(heif_error_Invalid_input, @@ -214,8 +216,7 @@ Result> ImageItem_Grid::decode_compressed_image( bool decode_tile_only, uint32_t tile_x0, uint32_t tile_y0) const { if (decode_tile_only) { - // TODO - return Error{heif_error_Unsupported_feature, heif_suberror_Unspecified, "Tile access to grid images not implemented"}; + return decode_grid_tile(options, tile_x0, tile_y0); } else { return decode_full_grid_image(options); @@ -558,6 +559,19 @@ Error ImageItem_Grid::decode_and_paste_tile_image(heif_item_id tileID, uint32_t } +Result> ImageItem_Grid::decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const +{ + uint32_t idx = ty * m_grid_spec.get_columns() + tx; + + assert(idx < m_grid_tile_ids.size()); + + heif_item_id tile_id = m_grid_tile_ids[idx]; + std::shared_ptr tile_item = get_context()->get_image(tile_id); + + return tile_item->decode_compressed_image(options, true, tx, ty); +} + + heif_image_tiling ImageItem_Grid::get_heif_image_tiling() const { heif_image_tiling tiling{}; diff --git a/libheif/codecs/grid.h b/libheif/codecs/grid.h index 191f6c16c5..380bfefc31 100644 --- a/libheif/codecs/grid.h +++ b/libheif/codecs/grid.h @@ -117,6 +117,8 @@ class ImageItem_Grid : public ImageItem Result> decode_full_grid_image(const heif_decoding_options& options) const; + Result> decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const; + Error decode_and_paste_tile_image(heif_item_id tileID, uint32_t x0, uint32_t y0, std::shared_ptr inout_image, const heif_decoding_options& options) const; diff --git a/libheif/context.cc b/libheif/context.cc index a3afac446f..086b015005 100644 --- a/libheif/context.cc +++ b/libheif/context.cc @@ -957,7 +957,8 @@ Error HeifContext::get_id_of_non_virtual_child_image(heif_item_id id, heif_item_ Result> HeifContext::decode_image(heif_item_id ID, heif_colorspace out_colorspace, heif_chroma out_chroma, - const struct heif_decoding_options& options) const + const struct heif_decoding_options& options, + bool decode_only_tile, uint32_t tx, uint32_t ty) const { std::string image_type = m_heif_file->get_item_type(ID); @@ -972,7 +973,7 @@ Result> HeifContext::decode_image(heif_item_id I } - auto decodingResult = imginfo->decode_image(out_colorspace, options, false,0,0); + auto decodingResult = imginfo->decode_image(out_colorspace, options, decode_only_tile, tx, ty); if (decodingResult.error) { return decodingResult.error; } diff --git a/libheif/context.h b/libheif/context.h index abd9e0b4bb..9a01a6c30a 100644 --- a/libheif/context.h +++ b/libheif/context.h @@ -127,7 +127,8 @@ class HeifContext : public ErrorBuffer Result> decode_image(heif_item_id ID, heif_colorspace out_colorspace, heif_chroma out_chroma, - const struct heif_decoding_options& options) const; + const struct heif_decoding_options& options, + bool decode_only_tile, uint32_t tx, uint32_t ty) const; std::string debug_dump_boxes() const;