From 269e35ee0a1080010051876850fc311be8961801 Mon Sep 17 00:00:00 2001 From: Kleis Auke Wolthuizen Date: Thu, 25 Jul 2024 10:18:29 +0200 Subject: [PATCH] Enable true streaming with a buffer-based fallback When using libvips version 8.13 or higher. --- src/api/CMakeLists.txt | 16 +- src/api/api_manager_impl.cpp | 5 +- src/api/io/blob.h | 81 ++++++++++ src/api/io/source.cpp | 9 +- src/api/io/target.cpp | 9 +- src/api/processors/mask.cpp | 17 +- src/api/processors/stream.cpp | 191 ++++++++++++----------- src/api/processors/stream.h | 27 ++-- src/api/processors/thumbnail.cpp | 59 +++---- src/api/utils/utility.h | 21 +-- test/api/base.cpp | 10 +- test/api/base.h | 1 - test/api/exceptions/unit-invalid.cpp | 26 +++ test/api/exceptions/unit-large.cpp | 31 +--- test/api/exceptions/unit-unreadable.cpp | 30 +--- test/api/processors/unit-alignment.cpp | 4 +- test/api/processors/unit-crop.cpp | 24 +-- test/api/processors/unit-embed.cpp | 20 +-- test/api/processors/unit-filter.cpp | 16 +- test/api/processors/unit-mask.cpp | 4 +- test/api/processors/unit-orientation.cpp | 4 +- test/api/processors/unit-stream.cpp | 111 ++++--------- test/api/processors/unit-thumbnail.cpp | 72 +++------ test/api/processors/unit-trim.cpp | 4 +- 24 files changed, 356 insertions(+), 436 deletions(-) create mode 100644 src/api/io/blob.h diff --git a/src/api/CMakeLists.txt b/src/api/CMakeLists.txt index 25e5efdd..41474bc2 100644 --- a/src/api/CMakeLists.txt +++ b/src/api/CMakeLists.txt @@ -3,6 +3,7 @@ set(HEADERS exceptions/large.h exceptions/unreadable.h exceptions/unsupported.h + io/blob.h io/source.h io/target.h parsers/color.h @@ -77,18 +78,17 @@ target_link_libraries(${PROJECT_NAME} ${VIPS_LDFLAGS} ) -# TODO(kleisauke): Enable once magickload_source is supported in libvips -#if (VIPS_VERSION VERSION_GREATER_EQUAL 8.13) -# target_compile_definitions(${PROJECT_NAME} -# PUBLIC -# WESERV_ENABLE_TRUE_STREAMING -# ) -#endif() +if (VIPS_VERSION VERSION_GREATER_EQUAL 8.13) + target_compile_definitions(${PROJECT_NAME} + PUBLIC + WESERV_ENABLE_TRUE_STREAMING + ) +endif() set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${PROJECT_VERSION} - SOVERSION 5 + SOVERSION ${PROJECT_VERSION_MAJOR} ) install(TARGETS ${PROJECT_NAME} diff --git a/src/api/api_manager_impl.cpp b/src/api/api_manager_impl.cpp index eb1c4ed1..865156fb 100644 --- a/src/api/api_manager_impl.cpp +++ b/src/api/api_manager_impl.cpp @@ -78,7 +78,8 @@ ApiManagerImpl::ApiManagerImpl(std::unique_ptr env) vips_error_clear(); env_->log_error("error: Unable to start up libvips: " + error); - } // LCOV_EXCL_STOP + // LCOV_EXCL_STOP + } } ApiManagerImpl::~ApiManagerImpl() { @@ -142,8 +143,8 @@ Status ApiManagerImpl::exception_handler(const std::string &query) { return {Status::Code::Unknown, error_str, Status::ErrorCause::Application}; + // LCOV_EXCL_STOP } - // LCOV_EXCL_STOP } utils::Status ApiManagerImpl::process(const std::string &query, diff --git a/src/api/io/blob.h b/src/api/io/blob.h new file mode 100644 index 00000000..65eb5b3b --- /dev/null +++ b/src/api/io/blob.h @@ -0,0 +1,81 @@ +#pragma once + +#include + +namespace weserv::api::io { + +class Blob { + public: + explicit Blob(VipsBlob *blob = nullptr) : blob_(blob) {} + + // copy constructor + Blob(const Blob &a) : blob_(a.blob_) { + reference(); + } + + // this mustn't be virtual: we want this class to only be a pointer, + // no vtable allowed + ~Blob() { + unreference(); + } + + // assignment ... we must delete the old ref + Blob &operator=(const Blob &a) { + // check whether we are already referencing this object - + // if so make this a null op. This will also deal with + // self-assignment. + if (blob_ != a.blob_) { + unreference(); + + blob_ = a.blob_; + + reference(); + } + + return *this; + } + + /** + * Get the underlying VipsBlob pointer. + * @return The underlying VipsBlob pointer. + */ + VipsBlob *get_blob() const { + return blob_; + } + + /** + * Get the data from a Blob. + * @param length Return number of bytes of data. + * @return The data. + */ + const void *get_blob(size_t *length) const { + return vips_blob_get(blob_, length); + } + + /** + * @return true if this Blob is a nullptr. + */ + bool is_null() const { + return blob_ == nullptr; + } + + private: + /** + * The underlying VipsBlob pointer, can be nullptr. + */ + VipsBlob *blob_; + + inline void unreference() { + if (blob_ != nullptr) { + vips_area_unref(reinterpret_cast(blob_)); + } + } + + inline void reference() { + if (blob_ != nullptr) { + vips_area_copy(reinterpret_cast(blob_)); + } + } +}; + +} // namespace weserv::api::io diff --git a/src/api/io/source.cpp b/src/api/io/source.cpp index 06ab197f..a8a5c402 100644 --- a/src/api/io/source.cpp +++ b/src/api/io/source.cpp @@ -59,8 +59,9 @@ Source Source::new_from_pointer(std::unique_ptr source) { g_object_new(WESERV_TYPE_SOURCE, "source", source.get(), nullptr)); if (vips_object_build(VIPS_OBJECT(weserv_source)) != 0) { - VIPS_UNREF(weserv_source); + VIPS_UNREF(weserv_source); // LCOV_EXCL_START throw vips::VError(); + // LCOV_EXCL_STOP } return Source(weserv_source); @@ -70,7 +71,7 @@ Source Source::new_from_file(const std::string &filename) { VipsSource *source = vips_source_new_from_file(filename.c_str()); if (source == nullptr) { - throw vips::VError(); + throw vips::VError(); // LCOV_EXCL_LINE } return Source(source); @@ -78,10 +79,10 @@ Source Source::new_from_file(const std::string &filename) { Source Source::new_from_buffer(const std::string &buffer) { VipsSource *source = - vips_source_new_from_memory(buffer.c_str(), buffer.size()); + vips_source_new_from_memory(buffer.data(), buffer.size()); if (source == nullptr) { - throw vips::VError(); + throw vips::VError(); // LCOV_EXCL_LINE } return Source(source); diff --git a/src/api/io/target.cpp b/src/api/io/target.cpp index d4ef9d5a..ccf3cb35 100644 --- a/src/api/io/target.cpp +++ b/src/api/io/target.cpp @@ -17,6 +17,7 @@ static gint64 weserv_target_write_wrapper(VipsTarget *target, const void *data, return weserv_target->write(data, length); } +// LCOV_EXCL_START static gint64 weserv_target_read_wrapper(VipsTarget *target, void *data, size_t length) { auto weserv_target = WESERV_TARGET(target)->target; @@ -30,6 +31,7 @@ static gint64 weserv_target_seek_wrapper(VipsTarget *target, gint64 offset, return weserv_target->seek(offset, whence); } +// LCOV_EXCL_STOP static int weserv_target_end_wrapper(VipsTarget *target) { auto weserv_target = WESERV_TARGET(target)->target; @@ -71,8 +73,9 @@ Target Target::new_to_pointer(std::unique_ptr target) { g_object_new(WESERV_TYPE_TARGET, "target", target.get(), nullptr)); if (vips_object_build(VIPS_OBJECT(weserv_target)) != 0) { - VIPS_UNREF(weserv_target); + VIPS_UNREF(weserv_target); // LCOV_EXCL_START throw vips::VError(); + // LCOV_EXCL_STOP } return Target(weserv_target); @@ -82,7 +85,7 @@ Target Target::new_to_file(const std::string &filename) { VipsTarget *target = vips_target_new_to_file(filename.c_str()); if (target == nullptr) { - throw vips::VError(); + throw vips::VError(); // LCOV_EXCL_LINE } return Target(target); @@ -92,7 +95,7 @@ Target Target::new_to_memory() { VipsTarget *target = vips_target_new_to_memory(); if (target == nullptr) { - throw vips::VError(); + throw vips::VError(); // LCOV_EXCL_LINE } return Target(target); diff --git a/src/api/processors/mask.cpp b/src/api/processors/mask.cpp index 4e44914f..e3671151 100644 --- a/src/api/processors/mask.cpp +++ b/src/api/processors/mask.cpp @@ -1,5 +1,6 @@ #include "mask.h" +#include "../io/blob.h" #include "../utils/utility.h" #include @@ -15,6 +16,8 @@ namespace weserv::api::processors { using enums::MaskType; using parsers::Color; +using io::Blob; + std::string Mask::svg_path_by_type(const int width, const int height, const MaskType &mask, int *out_x_min, int *out_y_min, @@ -323,10 +326,11 @@ VImage Mask::process(const VImage &image) const { auto svg_mask = svg.str(); // We don't take a copy of the data or free it - auto *blob = vips_blob_new(nullptr, svg_mask.data(), svg_mask.size()); + auto blob = + Blob(vips_blob_new(nullptr, svg_mask.data(), svg_mask.size())); auto mask = VImage::svgload_buffer( - blob, VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); - vips_area_unref(reinterpret_cast(blob)); + blob.get_blob(), + VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); // Cutout via dest-in output_image = output_image.composite2(mask, VIPS_BLEND_MODE_DEST_IN); @@ -353,10 +357,11 @@ VImage Mask::process(const VImage &image) const { auto svg_frame = svg.str(); // We don't take a copy of the data or free it - auto *blob = vips_blob_new(nullptr, svg_frame.data(), svg_frame.size()); + auto blob = + Blob(vips_blob_new(nullptr, svg_frame.data(), svg_frame.size())); auto frame = VImage::svgload_buffer( - blob, VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); - vips_area_unref(reinterpret_cast(blob)); + blob.get_blob(), + VImage::option()->set("access", VIPS_ACCESS_SEQUENTIAL)); // Ensure image to composite is premultiplied sRGB frame = frame.premultiply(); diff --git a/src/api/processors/stream.cpp b/src/api/processors/stream.cpp index 3774dd53..5bcd5ff1 100644 --- a/src/api/processors/stream.cpp +++ b/src/api/processors/stream.cpp @@ -20,37 +20,21 @@ using enums::Output; using parsers::Coordinate; using vips::VError; +using io::Blob; using io::Source; using io::Target; template -int Stream::resolve_page(const Source &source, const std::string &loader, +int Stream::resolve_page(const VImage &image, int n_pages, const Source &source, + const Blob &blob, const std::string &loader, Comparator comp) const { - auto image = new_from_source(source, loader, - VImage::option() - ->set("access", VIPS_ACCESS_SEQUENTIAL) - ->set("fail", config_.fail_on_error == 1) - ->set("page", 0)); - - int n_pages = image.get_typeof(VIPS_META_N_PAGES) != 0 - ? image.get_int(VIPS_META_N_PAGES) - : 1; - - // Limit the number of pages - if (config_.max_pages > 0 && n_pages > config_.max_pages) { - throw exceptions::TooLargeImageException( - "Input image exceeds the maximum number of pages. " - "Number of pages should be less than " + - std::to_string(config_.max_pages)); - } - uint64_t size = static_cast(image.height()) * image.width(); int target_page = 0; for (int i = 1; i < n_pages; ++i) { auto image_page = - new_from_source(source, loader, + new_from_source(source, blob, loader, VImage::option() ->set("access", VIPS_ACCESS_SEQUENTIAL) ->set("fail", config_.fail_on_error == 1) @@ -68,65 +52,63 @@ int Stream::resolve_page(const Source &source, const std::string &loader, return target_page; } -std::pair -Stream::get_page_load_options(const Source &source, - const std::string &loader) const { - auto n = query_->get_if( - "n", - [](int p) { - // Number of pages needs to be higher than 0 - // or -1 for all pages (animated GIF/WebP) - // Note: This is checked against config_.max_pages below. - return p == -1 || p > 0; - }, - 1); +std::pair Stream::get_page_load_options(int n_pages) const { + // Skip for single-page images + if (n_pages == 1) { + return std::pair{1, 0}; + } auto page = query_->get_if( "page", - [](int p) { - // Page needs to be in the range of - // 0 (numbered from zero) - 100000 + [&n_pages](int p) { + // Limit page to [0, n_pages] // Or: // -1 = largest page // -2 = smallest page - return p == -1 || p == -2 || (p >= 0 && p <= 100000); + return p == -1 || p == -2 || (p >= 0 && p <= n_pages); }, 0); - if (page != -1 && page != -2) { - return std::pair{n, page}; + // Selecting the largest/smallest page implies n=1 + if (page == -1 || page == -2) { + return std::pair{1, page}; } - if (page == -1) { - page = resolve_page(source, loader, std::greater<>()); - } else { // page == -2 - page = resolve_page(source, loader, std::less<>()); - } + auto n = query_->get_if( + "n", + [&n_pages](int n) { + // Limit number of pages to [1, n_pages] + // or -1 for all pages (animated GIF/WebP) + // Note: This is checked against config_.max_pages below. + return n == -1 || (n >= 1 && n <= n_pages); + }, + 1); - // Update page according to new value - query_->update("page", page); + if (n == -1) { + // Resolve the number of pages if we need to render until + // the end of the document. + n = n_pages - page; + } return std::pair{n, page}; } -VImage Stream::new_from_source(const Source &source, const std::string &loader, - vips::VOption *options) const { +VImage Stream::new_from_source(const Source &source, const Blob &blob, + const std::string &loader, + vips::VOption *options) { VImage out_image; #ifdef WESERV_ENABLE_TRUE_STREAMING - try { - VImage::call(loader.c_str(), - options->set("source", source)->set("out", &out_image)); -#else - // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - options = options->set("buffer", blob)->set("out", &out_image); - vips_area_unref(reinterpret_cast(blob)); + if (blob.is_null()) { + options->set("source", source)->set("out", &out_image); + } else +#endif + // We don't take a copy of the data or free it + options = + options->set("buffer", blob.get_blob())->set("out", &out_image); try { VImage::call(loader.c_str(), options); -#endif } catch (const VError &err) { throw exceptions::UnreadableImageException(err.what()); } @@ -222,17 +204,36 @@ void Stream::resolve_query(const VImage &image) const { } VImage Stream::new_from_source(const Source &source) const { + Blob blob; + #ifdef WESERV_ENABLE_TRUE_STREAMING const char *loader = vips_foreign_find_load_source(source.get_source()); + if (loader == nullptr) { + // Try with the old buffer-based loaders + blob = Blob(vips_source_map_blob(source.get_source())); + if (blob.is_null()) { + throw exceptions::InvalidImageException(vips_error_buffer()); + } + + size_t len; + const void *buf = blob.get_blob(&len); + + loader = vips_foreign_find_load_buffer(buf, len); + if (loader == nullptr) { + throw exceptions::InvalidImageException(vips_error_buffer()); + } + } #else const char *loader = vips_foreign_find_load_buffer(source.buffer().data(), source.buffer().size()); -#endif - if (loader == nullptr) { throw exceptions::InvalidImageException(vips_error_buffer()); } + blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); +#endif + ImageType image_type = utils::determine_image_type(loader); // Save the image type so that we can work out @@ -245,24 +246,43 @@ VImage Stream::new_from_source(const Source &source) const { ? VIPS_ACCESS_RANDOM : VIPS_ACCESS_SEQUENTIAL; - vips::VOption *options; - int n = 1; - int page = 0; - if (utils::support_multi_pages(image_type)) { - std::tie(n, page) = get_page_load_options(source, loader); - - options = VImage::option() - ->set("access", access_method) - ->set("fail", config_.fail_on_error == 1) - ->set("n", n) - ->set("page", page); - } else { - options = VImage::option() - ->set("access", access_method) - ->set("fail", config_.fail_on_error == 1); - } + auto image = new_from_source(source, blob, loader, + VImage::option() + ->set("access", access_method) + ->set("fail", config_.fail_on_error == 1)); + + auto n_pages = image.get_typeof(VIPS_META_N_PAGES) != 0 + ? image.get_int(VIPS_META_N_PAGES) + : 1; + + auto n = 1; + auto page = 0; + std::tie(n, page) = get_page_load_options(n_pages); + + if (n != 1 || page != 0) { + // Limit the number of pages + if (config_.max_pages > 0 && n > config_.max_pages) { + throw exceptions::TooLargeImageException( + "Input image exceeds the maximum number of pages. " + "Number of pages should be less than " + + std::to_string(config_.max_pages)); + } - auto image = new_from_source(source, loader, options); + if (page == -1) { + page = resolve_page(image, n_pages, source, blob, loader, + std::greater<>()); + } else if (page == -2) { + page = resolve_page(image, n_pages, source, blob, loader, + std::less<>()); + } + + image = new_from_source(source, blob, loader, + VImage::option() + ->set("access", access_method) + ->set("fail", config_.fail_on_error == 1) + ->set("n", n) + ->set("page", page)); + } // Limit input images to a given number of pixels, where // pixels = width * height @@ -275,24 +295,9 @@ VImage Stream::new_from_source(const Source &source) const { std::to_string(config_.limit_input_pixels)); } - if (n == -1) { - // Resolve the number of pages if we need to render until - // the end of the document. - n = image.get_typeof(VIPS_META_N_PAGES) != 0 - ? image.get_int(VIPS_META_N_PAGES) - page - : 1; - } - - // Limit the number of pages - if (config_.max_pages > 0 && n > config_.max_pages) { - throw exceptions::TooLargeImageException( - "Input image exceeds the maximum number of pages. " - "Number of pages should be less than " + - std::to_string(config_.max_pages)); - } - - // Always store the number of pages to load + // Always store the page load options query_->update("n", n); + query_->update("page", page); // Resolve query resolve_query(image); diff --git a/src/api/processors/stream.h b/src/api/processors/stream.h index eec341bf..eb8fa980 100644 --- a/src/api/processors/stream.h +++ b/src/api/processors/stream.h @@ -1,5 +1,6 @@ #pragma once +#include "../io/blob.h" #include "../io/source.h" #include "../io/target.h" #include "base.h" @@ -32,28 +33,29 @@ class Stream { const Config &config_; /** - * Finds the largest/smallest page in the range [0, VIPS_META_N_PAGES]. + * Finds the largest/smallest page in the range [0, n_pages]. * Pages are compared using the given comparison function. * See: https://github.com/weserv/images/issues/170. * @tparam T Comparison type. + * @param image The source image. + * @param n_pages Number of pages in the image. * @param source Source to read from. + * @param blob (Fallback-)blob to read from. * @param loader Image loader. * @param comp Comparison function object. - * @return The largest/smallest page in the range [0, VIPS_META_N_PAGES]. + * @return The largest/smallest page in the range [0, n_pages]. */ template - int resolve_page(const io::Source &source, const std::string &loader, + int resolve_page(const VImage &image, int n_pages, const io::Source &source, + const io::Blob &blob, const std::string &loader, Comparator comp) const; /** - * Get the page options for a specified loader to pass on - * to the load operation. - * @param source Source to read from. - * @param loader Image loader. + * Get the page options to pass on to the load operation. + * @param n_pages Number of pages in the image. * @return Any options to pass on to the load operation */ - std::pair get_page_load_options(const io::Source &souce, - const std::string &loader) const; + std::pair get_page_load_options(int n_pages) const; /** * Load a formatted image from a source. @@ -62,12 +64,15 @@ class Stream { * It will throw a `UnreadableImageException` if an error occurs * during loading. * @param source Source to read from. + * @param blob (Fallback-)blob to read from. * @param loader Image loader. * @param options Any options to pass on to the load operation. * @return A new `VImage`. */ - VImage new_from_source(const io::Source &source, const std::string &loader, - vips::VOption *options) const; + static VImage new_from_source(const io::Source &source, + const io::Blob &blob, + const std::string &loader, + vips::VOption *options); /** * Resolve/validate the query parameters based on the given image. diff --git a/src/api/processors/thumbnail.cpp b/src/api/processors/thumbnail.cpp index 9202a973..768f17e8 100644 --- a/src/api/processors/thumbnail.cpp +++ b/src/api/processors/thumbnail.cpp @@ -1,6 +1,7 @@ #include "thumbnail.h" #include "../exceptions/large.h" +#include "../io/blob.h" #include #include @@ -18,6 +19,7 @@ using enums::ImageType; // NOTE: Can be overridden with `&fsol=0`. const bool FAST_SHRINK_ON_LOAD = true; +using io::Blob; using io::Source; template <> @@ -28,11 +30,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::jpegload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::jpegload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::jpegload_buffer(blob.get_blob(), options); #endif } @@ -44,11 +44,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::pdfload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::pdfload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::pdfload_buffer(blob.get_blob(), options); #endif } @@ -60,11 +58,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::webpload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::webpload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::webpload_buffer(blob.get_blob(), options); #endif } @@ -76,11 +72,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::tiffload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::tiffload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::tiffload_buffer(blob.get_blob(), options); #endif } @@ -105,11 +99,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::svgload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::svgload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::svgload_buffer(blob.get_blob(), options); #endif } @@ -121,11 +113,9 @@ Thumbnail::new_from_source(const Source &source, return VImage::heifload_source(source, options); #else // We don't take a copy of the data or free it - auto *blob = - vips_blob_new(nullptr, source.buffer().data(), source.buffer().size()); - auto image = VImage::heifload_buffer(blob, options); - vips_area_unref(reinterpret_cast(blob)); - return image; + auto blob = Blob( + vips_blob_new(nullptr, source.buffer().data(), source.buffer().size())); + return VImage::heifload_buffer(blob.get_blob(), options); #endif } @@ -311,14 +301,7 @@ int Thumbnail::resolve_tiff_pyramid(const VImage &image, const Source &source, void Thumbnail::append_page_options(vips::VOption *options) const { auto n = query_->get("n"); - auto page = query_->get_if( - "page", - [](int p) { - // Page needs to be in the range of - // 0 (numbered from zero) - 100000 - return p >= 0 && p <= 100000; - }, - 0); + auto page = query_->get("page"); options->set("n", n); options->set("page", page); diff --git a/src/api/utils/utility.h b/src/api/utils/utility.h index fefa1f81..ae464096 100644 --- a/src/api/utils/utility.h +++ b/src/api/utils/utility.h @@ -179,7 +179,8 @@ static void image_eval_cb(VipsImage *image, VipsProgress *progress, // We've killed the image and issued an error, it's now our caller's // responsibility to pass the message up the chain. *timeout = 0; - } // LCOV_EXCL_STOP + // LCOV_EXCL_STOP + } } /** @@ -323,19 +324,8 @@ inline std::string image_type_id(const ImageType &image_type) { case ImageType::Unknown: // LCOV_EXCL_START default: return "unknown"; + // LCOV_EXCL_STOP } - // LCOV_EXCL_STOP -} - -/** - * Does this image type support multiple pages? - * @param image_type Image type to check. - * @return A bool indicating if this image type support multiple pages. - */ -inline bool support_multi_pages(const ImageType &image_type) { - return image_type == ImageType::Webp || image_type == ImageType::Tiff || - image_type == ImageType::Gif || image_type == ImageType::Pdf || - image_type == ImageType::Heif || image_type == ImageType::Magick; } /** @@ -539,8 +529,9 @@ inline std::string image_to_json(const VImage &image, * @param s The string to escape. * @return The escaped string. */ -inline std::string escape_string(const std::string &s) { // LCOV_EXCL_START +inline std::string escape_string(const std::string &s) { std::ostringstream o; + // LCOV_EXCL_START for (char c : s) { switch (c) { case '\x00': @@ -565,9 +556,9 @@ inline std::string escape_string(const std::string &s) { // LCOV_EXCL_START o << c; } } + // LCOV_EXCL_STOP return o.str(); } -// LCOV_EXCL_STOP } // namespace weserv::api::utils diff --git a/test/api/base.cpp b/test/api/base.cpp index af12befd..f5efa568 100644 --- a/test/api/base.cpp +++ b/test/api/base.cpp @@ -9,15 +9,13 @@ std::shared_ptr fixtures; std::shared_ptr api_manager; +// libvips prior to 8.12 uses *magick for saving to gif bool pre_8_12 = vips_version(0) < 8 || (vips_version(0) == 8 && vips_version(1) < 12); -// TODO(kleisauke): Enable once magickload_source is supported in libvips -bool true_streaming = false; - VImage buffer_to_image(const std::string &buf) { const char *operation_name = - vips_foreign_find_load_buffer(buf.c_str(), buf.size()); + vips_foreign_find_load_buffer(buf.data(), buf.size()); if (operation_name == nullptr) { throw std::runtime_error("invalid or unsupported image format"); @@ -26,12 +24,12 @@ VImage buffer_to_image(const std::string &buf) { VImage out; // We must take a copy of the data. - VipsBlob *blob = vips_blob_copy(buf.c_str(), buf.size()); + VipsBlob *blob = vips_blob_copy(buf.data(), buf.size()); vips::VOption *options = VImage::option() ->set("access", VIPS_ACCESS_SEQUENTIAL) ->set("buffer", blob) ->set("out", &out); - vips_area_unref(VIPS_AREA(blob)); + vips_area_unref(reinterpret_cast(blob)); VImage::call(operation_name, options); diff --git a/test/api/base.h b/test/api/base.h index 6aa2a34e..60248707 100644 --- a/test/api/base.h +++ b/test/api/base.h @@ -17,7 +17,6 @@ extern std::shared_ptr fixtures; extern std::shared_ptr api_manager; extern bool pre_8_12; -extern bool true_streaming; extern Status process(std::unique_ptr source, std::unique_ptr target, diff --git a/test/api/exceptions/unit-invalid.cpp b/test/api/exceptions/unit-invalid.cpp index f677358b..7d0dbe18 100644 --- a/test/api/exceptions/unit-invalid.cpp +++ b/test/api/exceptions/unit-invalid.cpp @@ -57,4 +57,30 @@ TEST_CASE("invalid image", "[invalid]") { CHECK_THAT(status.message(), Contains("Invalid or unsupported image format")); } + SECTION("empty source") { + if (vips_version(0) < 8 || + (vips_version(0) == 8 && vips_version(1) < 13)) { + SUCCEED("requires libvips 8.13+, skipping test"); + return; + } + + class UnreadableSource : public SourceInterface { + int64_t read(void * /* unsused */, size_t /* unsused */) override { + return -1; + } + + int64_t seek(int64_t /* unsused */, int /* unsused */) override { + return -1; + } + }; + + Status status = process( + std::unique_ptr(new UnreadableSource()), nullptr); + + CHECK(!status.ok()); + CHECK(status.code() == static_cast(Status::Code::InvalidImage)); + CHECK(status.error_cause() == Status::ErrorCause::Application); + CHECK_THAT(status.message(), + Contains("Invalid or unsupported image format")); + } } diff --git a/test/api/exceptions/unit-large.cpp b/test/api/exceptions/unit-large.cpp index ccc92b71..168388b2 100644 --- a/test/api/exceptions/unit-large.cpp +++ b/test/api/exceptions/unit-large.cpp @@ -6,9 +6,7 @@ using Catch::Matchers::Contains; TEST_CASE("too large image", "[large]") { SECTION("input") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -41,9 +39,7 @@ TEST_CASE("too large image", "[large]") { TEST_CASE("too many pages", "[large]") { SECTION("input") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "gifload_buffer") == 0) { SUCCEED("no gif support, skipping test"); return; } @@ -62,27 +58,4 @@ TEST_CASE("too many pages", "[large]") { Contains("Input image exceeds the maximum number of pages.")); CHECK(out_buf.empty()); } - - SECTION("input and special page") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { - SUCCEED("no gif support, skipping test"); - return; - } - - auto test_image = fixtures->input_gif_animated_max_pages; - auto params = "page=-1"; - - std::string out_buf; - Status status = process_file(test_image, &out_buf, params); - - CHECK(!status.ok()); - CHECK(status.code() == static_cast(Status::Code::ImageTooLarge)); - CHECK(status.error_cause() == Status::ErrorCause::Application); - CHECK_THAT( - status.message(), - Contains("Input image exceeds the maximum number of pages.")); - CHECK(out_buf.empty()); - } } diff --git a/test/api/exceptions/unit-unreadable.cpp b/test/api/exceptions/unit-unreadable.cpp index 7e906351..e1c0af2e 100644 --- a/test/api/exceptions/unit-unreadable.cpp +++ b/test/api/exceptions/unit-unreadable.cpp @@ -6,9 +6,7 @@ using Catch::Matchers::Contains; TEST_CASE("unreadable image", "[unreadable]") { SECTION("buffer") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "gifload_buffer") == 0) { SUCCEED("no gif support, skipping test"); return; } @@ -22,30 +20,4 @@ TEST_CASE("unreadable image", "[unreadable]") { CHECK(status.error_cause() == Status::ErrorCause::Application); CHECK_THAT(status.message(), Contains("Image not readable")); } - SECTION("source") { - // TODO: This test can be moved to unit-invalid when libvips >= 8.12 - class UnreadableSource : public SourceInterface { - int64_t read(void * /* unsused */, size_t /* unsused */) override { - return -1; - } - - int64_t seek(int64_t /* unsused */, int /* unsused */) override { - return -1; - } - }; - - Status status = process( - std::unique_ptr(new UnreadableSource()), nullptr); - - CHECK(!status.ok()); - CHECK(status.code() == - static_cast(true_streaming - ? Status::Code::InvalidImage - : Status::Code::ImageNotReadable)); - CHECK(status.error_cause() == Status::ErrorCause::Application); - CHECK_THAT(status.message(), - Contains(true_streaming - ? "Invalid or unsupported image format" - : "Image not readable")); - } } diff --git a/test/api/processors/unit-alignment.cpp b/test/api/processors/unit-alignment.cpp index 2b249159..a1cf85d1 100644 --- a/test/api/processors/unit-alignment.cpp +++ b/test/api/processors/unit-alignment.cpp @@ -222,9 +222,7 @@ TEST_CASE("attention crop", "[alignment]") { } TEST_CASE("animated image", "[alignment]") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { diff --git a/test/api/processors/unit-crop.cpp b/test/api/processors/unit-crop.cpp index fbedf168..15db4912 100644 --- a/test/api/processors/unit-crop.cpp +++ b/test/api/processors/unit-crop.cpp @@ -40,12 +40,8 @@ TEST_CASE("partial image extract", "[crop]") { } SECTION("webp") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -65,12 +61,8 @@ TEST_CASE("partial image extract", "[crop]") { } SECTION("tiff") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -119,9 +111,7 @@ TEST_CASE("image extract before resize", "[crop]") { } TEST_CASE("image resize and extract svg 72 dpi", "[crop]") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -249,9 +239,7 @@ TEST_CASE("bad extract area", "[crop]") { } TEST_CASE("animated image", "[crop]") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { diff --git a/test/api/processors/unit-embed.cpp b/test/api/processors/unit-embed.cpp index d057a4ff..570905cb 100644 --- a/test/api/processors/unit-embed.cpp +++ b/test/api/processors/unit-embed.cpp @@ -11,12 +11,8 @@ using vips::VImage; TEST_CASE("embed", "[embed]") { // TIFF letterbox known to cause rounding errors SECTION("tiff") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -35,9 +31,7 @@ TEST_CASE("embed", "[embed]") { // Letterbox TIFF in LAB colourspace onto RGBA background SECTION("tiff on rgba") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -183,9 +177,7 @@ TEST_CASE("skip", "[embed]") { TEST_CASE("animated image", "[embed]") { SECTION("width only") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { @@ -203,9 +195,7 @@ TEST_CASE("animated image", "[embed]") { } SECTION("height only") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { diff --git a/test/api/processors/unit-filter.cpp b/test/api/processors/unit-filter.cpp index 8691e449..19295a3f 100644 --- a/test/api/processors/unit-filter.cpp +++ b/test/api/processors/unit-filter.cpp @@ -135,12 +135,8 @@ TEST_CASE("negate filter", "[filter]") { } SECTION("webp") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -158,12 +154,8 @@ TEST_CASE("negate filter", "[filter]") { } SECTION("webp transparent") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } diff --git a/test/api/processors/unit-mask.cpp b/test/api/processors/unit-mask.cpp index 45460d94..62cfd509 100644 --- a/test/api/processors/unit-mask.cpp +++ b/test/api/processors/unit-mask.cpp @@ -192,9 +192,7 @@ TEST_CASE("mask", "[mask]") { } SECTION("animated image") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { diff --git a/test/api/processors/unit-orientation.cpp b/test/api/processors/unit-orientation.cpp index a1a3ff9c..bebb6a59 100644 --- a/test/api/processors/unit-orientation.cpp +++ b/test/api/processors/unit-orientation.cpp @@ -124,9 +124,7 @@ TEST_CASE("rectangular output ignoring aspect ratio, rotate by 270 degrees", TEST_CASE("rotate a multi-page image with a non-straight angle", "[orientation]") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { diff --git a/test/api/processors/unit-stream.cpp b/test/api/processors/unit-stream.cpp index 30fb3f3e..bca356c1 100644 --- a/test/api/processors/unit-stream.cpp +++ b/test/api/processors/unit-stream.cpp @@ -25,12 +25,8 @@ TEST_CASE("output", "[stream]") { } SECTION("webp") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -47,12 +43,8 @@ TEST_CASE("output", "[stream]") { } SECTION("avif") { - if (vips_type_find("VipsOperation", true_streaming - ? "heifload_source" - : "heifload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "heifsave_target" - : "heifsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "heifload_buffer") == 0 || + vips_type_find("VipsOperation", "heifsave_buffer") == 0) { SUCCEED("no avif support, skipping test"); return; } @@ -75,12 +67,8 @@ TEST_CASE("output", "[stream]") { } SECTION("tiff") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -97,9 +85,7 @@ TEST_CASE("output", "[stream]") { } SECTION("gif") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) { @@ -169,9 +155,7 @@ TEST_CASE("output", "[stream]") { TEST_CASE("special page", "[stream]") { SECTION("largest") { - if (vips_type_find("VipsOperation", true_streaming - ? "magickload_source" - : "magickload_buffer") == 0) { + if (vips_type_find("VipsOperation", "magickload_buffer") == 0) { SUCCEED("no magick support, skipping test"); return; } @@ -188,22 +172,21 @@ TEST_CASE("special page", "[stream]") { } SECTION("smallest") { - if (vips_type_find("VipsOperation", true_streaming - ? "magickload_source" - : "magickload_buffer") == 0) { - SUCCEED("no magick support, skipping test"); + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { + SUCCEED("no tiff support, skipping test"); return; } - auto test_image = fixtures->input_ico; + auto test_image = fixtures->input_tiff_pyramid; auto params = "page=-2"; VImage image = process_file(test_image, params); - CHECK_THAT(image.get_string("vips-loader"), Equals("pngload_buffer")); + CHECK_THAT(image.get_string("vips-loader"), Equals("tiffload_buffer")); - CHECK(image.width() == 16); - CHECK(image.height() == 16); + CHECK(image.width() == 125); + CHECK(image.height() == 25); } } @@ -245,12 +228,8 @@ TEST_CASE("quality and compression", "[stream]") { } SECTION("webp quality") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -274,12 +253,8 @@ TEST_CASE("quality and compression", "[stream]") { } SECTION("avif quality") { - if (vips_type_find("VipsOperation", true_streaming - ? "heifload_source" - : "heifload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "heifsave_target" - : "heifsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "heifload_buffer") == 0 || + vips_type_find("VipsOperation", "heifsave_buffer") == 0) { SUCCEED("no avif support, skipping test"); return; } @@ -298,12 +273,8 @@ TEST_CASE("quality and compression", "[stream]") { } SECTION("tiff quality") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -342,9 +313,7 @@ TEST_CASE("without adaptive filtering generates smaller file", "[stream]") { TEST_CASE("gif options", "[stream]") { SECTION("loop count") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "gifload_buffer") == 0) { SUCCEED("no gif support, skipping test"); return; } @@ -361,9 +330,7 @@ TEST_CASE("gif options", "[stream]") { } SECTION("frame delay") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "gifload_buffer") == 0) { SUCCEED("no gif support, skipping test"); return; } @@ -380,9 +347,7 @@ TEST_CASE("gif options", "[stream]") { } SECTION("page height") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "gifload_buffer") == 0) { SUCCEED("no gif support, skipping test"); return; } @@ -423,9 +388,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("webp") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -439,9 +402,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("avif") { - if (vips_type_find("VipsOperation", true_streaming - ? "heifload_source" - : "heifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "heifload_buffer") == 0) { SUCCEED("no avif support, skipping test"); return; } @@ -455,9 +416,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("tiff") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -471,9 +430,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("svg") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -487,9 +444,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("pdf") { - if (vips_type_find("VipsOperation", true_streaming - ? "pdfload_source" - : "pdfload_buffer") == 0) { + if (vips_type_find("VipsOperation", "pdfload_buffer") == 0) { SUCCEED("no pdf support, skipping test"); return; } @@ -503,9 +458,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("heic") { - if (vips_type_find("VipsOperation", true_streaming - ? "heifload_source" - : "heifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "heifload_buffer") == 0) { SUCCEED("no heif support, skipping test"); return; } @@ -520,9 +473,7 @@ TEST_CASE("metadata", "[stream]") { } SECTION("magick") { - if (vips_type_find("VipsOperation", true_streaming - ? "magickload_source" - : "magickload_buffer") == 0) { + if (vips_type_find("VipsOperation", "magickload_buffer") == 0) { SUCCEED("no magick support, skipping test"); return; } diff --git a/test/api/processors/unit-thumbnail.cpp b/test/api/processors/unit-thumbnail.cpp index 66f432d2..7f4005d3 100644 --- a/test/api/processors/unit-thumbnail.cpp +++ b/test/api/processors/unit-thumbnail.cpp @@ -207,12 +207,8 @@ TEST_CASE("cover", "[thumbnail]") { TEST_CASE("tiff", "[thumbnail]") { SECTION("cover") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -229,12 +225,8 @@ TEST_CASE("tiff", "[thumbnail]") { // Width or height considering ratio (portrait) SECTION("smaller axis") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -250,12 +242,8 @@ TEST_CASE("tiff", "[thumbnail]") { } SECTION("pyramid") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -273,12 +261,8 @@ TEST_CASE("tiff", "[thumbnail]") { } SECTION("pyramid skip shrink-on-load") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -293,12 +277,8 @@ TEST_CASE("tiff", "[thumbnail]") { } SECTION("multi-page skip shrink-on-load") { - if (vips_type_find("VipsOperation", true_streaming - ? "tiffload_source" - : "tiffload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "tiffsave_target" - : "tiffsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "tiffload_buffer") == 0 || + vips_type_find("VipsOperation", "tiffsave_buffer") == 0) { SUCCEED("no tiff support, skipping test"); return; } @@ -475,9 +455,7 @@ TEST_CASE("from", "[thumbnail]") { TEST_CASE("shortest edge is at least 1 pixel", "[thumbnail]") { SECTION("height") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -492,9 +470,7 @@ TEST_CASE("shortest edge is at least 1 pixel", "[thumbnail]") { } SECTION("width") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -509,9 +485,7 @@ TEST_CASE("shortest edge is at least 1 pixel", "[thumbnail]") { } SECTION("shrink-on-load") { - if (vips_type_find("VipsOperation", true_streaming - ? "svgload_source" - : "svgload_buffer") == 0) { + if (vips_type_find("VipsOperation", "svgload_buffer") == 0) { SUCCEED("no svg support, skipping test"); return; } @@ -527,9 +501,7 @@ TEST_CASE("shortest edge is at least 1 pixel", "[thumbnail]") { } TEST_CASE("pdf", "[thumbnail]") { - if (vips_type_find("VipsOperation", true_streaming - ? "pdfload_source" - : "pdfload_buffer") == 0) { + if (vips_type_find("VipsOperation", "pdfload_buffer") == 0) { SUCCEED("no pdf support, skipping test"); return; } @@ -547,9 +519,7 @@ TEST_CASE("pdf", "[thumbnail]") { } TEST_CASE("heif", "[thumbnail]") { - if (vips_type_find("VipsOperation", true_streaming - ? "heifload_source" - : "heifload_buffer") == 0) { + if (vips_type_find("VipsOperation", "heifload_buffer") == 0) { SUCCEED("no heic support, skipping test"); return; } @@ -567,12 +537,8 @@ TEST_CASE("heif", "[thumbnail]") { } TEST_CASE("animated webp page", "[thumbnail]") { - if (vips_type_find("VipsOperation", true_streaming - ? "webpload_source" - : "webpload_buffer") == 0 || - vips_type_find("VipsOperation", true_streaming - ? "webpsave_target" - : "webpsave_buffer") == 0) { + if (vips_type_find("VipsOperation", "webpload_buffer") == 0 || + vips_type_find("VipsOperation", "webpsave_buffer") == 0) { SUCCEED("no webp support, skipping test"); return; } @@ -590,9 +556,7 @@ TEST_CASE("animated webp page", "[thumbnail]") { } TEST_CASE("radiance", "[thumbnail]") { - if (vips_type_find("VipsOperation", true_streaming - ? "radload_source" - : "radload_buffer") == 0) { + if (vips_type_find("VipsOperation", "radload_buffer") == 0) { SUCCEED("no radiance support, skipping test"); return; } diff --git a/test/api/processors/unit-trim.cpp b/test/api/processors/unit-trim.cpp index cf2abf78..3f978471 100644 --- a/test/api/processors/unit-trim.cpp +++ b/test/api/processors/unit-trim.cpp @@ -79,9 +79,7 @@ TEST_CASE("trim", "[trim]") { } SECTION("skip height in toilet-roll mode") { - if (vips_type_find("VipsOperation", true_streaming - ? "gifload_source" - : "gifload_buffer") == 0 || + if (vips_type_find("VipsOperation", "gifload_buffer") == 0 || vips_type_find("VipsOperation", pre_8_12 ? "magicksave_buffer" : "gifsave_target") == 0) {