diff --git a/libheif/image-items/grid.cc b/libheif/image-items/grid.cc index b6b1d3db12..e0c9e07079 100644 --- a/libheif/image-items/grid.cc +++ b/libheif/image-items/grid.cc @@ -290,6 +290,7 @@ Result> ImageItem_Grid::decode_full_grid_image(c int progress_counter = 0; bool cancelled = false; + std::shared_ptr > warnings(new std::vector()); for (uint32_t y = 0; y < grid.get_rows() && !cancelled; y++) { uint32_t x0 = 0; @@ -300,11 +301,30 @@ Result> ImageItem_Grid::decode_full_grid_image(c std::shared_ptr tileImg = get_context()->get_image(tileID, true); if (!tileImg) { + if (!options.strict_decoding && reference_idx != 0) { + // Skip missing tiles (unless it's the first one). + warnings->push_back(Error{ + heif_error_Invalid_input, + heif_suberror_Missing_grid_images, + }); + reference_idx++; + x0 += tile_width; + continue; + } + return Error{heif_error_Invalid_input, heif_suberror_Missing_grid_images, "Nonexistent grid image referenced"}; } if (auto error = tileImg->get_item_error()) { + if (!options.strict_decoding && reference_idx != 0) { + // Skip missing tiles (unless it's the first one). + warnings->push_back(error); + reference_idx++; + x0 += tile_width; + continue; + } + return error; } @@ -347,7 +367,7 @@ Result> ImageItem_Grid::decode_full_grid_image(c } } - err = decode_and_paste_tile_image(tileID, x0, y0, img, options, progress_counter); + err = decode_and_paste_tile_image(tileID, x0, y0, img, options, progress_counter, warnings); if (err) { return err; } @@ -395,7 +415,7 @@ Result> ImageItem_Grid::decode_full_grid_image(c errs.push_back(std::async(std::launch::async, &ImageItem_Grid::decode_and_paste_tile_image, this, data.tileID, data.x_origin, data.y_origin, std::ref(img), options, - std::ref(progress_counter))); + std::ref(progress_counter), warnings)); } // check for decoding errors in remaining tiles @@ -419,17 +439,49 @@ Result> ImageItem_Grid::decode_full_grid_image(c return Error{heif_error_Canceled, heif_suberror_Unspecified, "Decoding the image was canceled"}; } + if (img) { + img->add_warnings(*warnings.get()); + } + return img; } +static Error progress_and_return_ok(const heif_decoding_options& options, int& progress_counter) { + if (options.on_progress) { +#if ENABLE_PARALLEL_TILE_DECODING + static std::mutex progressMutex; + std::lock_guard lock(progressMutex); +#endif + + options.on_progress(heif_progress_step_total, ++progress_counter, options.progress_user_data); + } + return Error::Ok; +} + Error ImageItem_Grid::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, - int& progress_counter) const + int& progress_counter, + std::shared_ptr > warnings) const { std::shared_ptr tile_img; +#if ENABLE_PARALLEL_TILE_DECODING + static std::mutex warningsMutex; +#endif auto tileItem = get_context()->get_image(tileID, true); + if (!tileItem && !options.strict_decoding) { + // We ignore missing images. +#if ENABLE_PARALLEL_TILE_DECODING + std::lock_guard lock(warningsMutex); +#endif + warnings->push_back(Error{ + heif_error_Invalid_input, + heif_suberror_Missing_grid_images, + }); + return progress_and_return_ok(options, progress_counter); + } + assert(tileItem); if (auto error = tileItem->get_item_error()) { return error; @@ -437,6 +489,15 @@ Error ImageItem_Grid::decode_and_paste_tile_image(heif_item_id tileID, uint32_t auto decodeResult = tileItem->decode_image(options, false, 0, 0); if (!decodeResult) { + if (!options.strict_decoding) { + // We ignore broken tiles. +#if ENABLE_PARALLEL_TILE_DECODING + std::lock_guard lock(warningsMutex); +#endif + warnings->push_back(decodeResult.error()); + return progress_and_return_ok(options, progress_counter); + } + return decodeResult.error(); } @@ -489,16 +550,7 @@ Error ImageItem_Grid::decode_and_paste_tile_image(heif_item_id tileID, uint32_t inout_image->copy_image_to(tile_img, x0, y0); - if (options.on_progress) { -#if ENABLE_PARALLEL_TILE_DECODING - static std::mutex progressMutex; - std::lock_guard lock(progressMutex); -#endif - - options.on_progress(heif_progress_step_total, ++progress_counter, options.progress_user_data); - } - - return Error::Ok; + return progress_and_return_ok(options, progress_counter); } diff --git a/libheif/image-items/grid.h b/libheif/image-items/grid.h index b886ef8a12..e6bcaa4529 100644 --- a/libheif/image-items/grid.h +++ b/libheif/image-items/grid.h @@ -167,7 +167,8 @@ class ImageItem_Grid : public ImageItem 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, int& progress_counter) const; + const heif_decoding_options& options, int& progress_counter, + std::shared_ptr > warnings) const; }; diff --git a/libheif/image-items/image_item.cc b/libheif/image-items/image_item.cc index e2023e127a..8e76cc97ab 100644 --- a/libheif/image-items/image_item.cc +++ b/libheif/image-items/image_item.cc @@ -708,6 +708,10 @@ Result> ImageItem::decode_image(const heif_decod } auto img = *decodingResult; + if (!img) { + // Can happen if missing tiled image is decoded in non-strict mode. + return Error(heif_error_Decoder_plugin_error, heif_suberror_Unspecified); + } std::shared_ptr file = m_heif_context->get_heif_file();