From cff8815404aceebf16a55d9326b18c3ddd107050 Mon Sep 17 00:00:00 2001 From: Michal Maciola <71131832+mmaciola@users.noreply.github.com> Date: Thu, 5 Aug 2021 04:02:26 +0200 Subject: [PATCH] loaders: Pass mimetype to picture::load * loaders: Pass mimetype to picture::load Added mimetype attribute to enfaster loading using a proper loader. @Changed api: Picture::load(const char* data, uint32_t size, const std::string& mimeType, bool copy = false) @issue: #571 --- inc/thorvg.h | 22 ++++++++++++++++++++-- src/bindings/capi/thorvg_capi.h | 3 ++- src/bindings/capi/tvgCapi.cpp | 4 ++-- src/examples/PictureJpg.cpp | 4 ++-- src/examples/PicturePng.cpp | 4 ++-- src/examples/Svg2.cpp | 2 +- src/lib/tvgLoader.cpp | 26 +++++++++++++++++++++++++- src/lib/tvgLoader.h | 2 +- src/lib/tvgPicture.cpp | 9 +++++++-- src/lib/tvgPictureImpl.h | 4 ++-- src/loaders/svg/tvgSvgSceneBuilder.cpp | 10 ++++++---- test/capi/capiPicture.cpp | 8 ++++---- test/testPicture.cpp | 14 +++++++------- 13 files changed, 81 insertions(+), 31 deletions(-) diff --git a/inc/thorvg.h b/inc/thorvg.h index 12199634..a8c3bf76 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -1012,11 +1012,29 @@ public: * @retval Result::NonSupport When trying to load a file with an unknown extension. * @retval Result::Unknown If an error occurs at a later stage. * - * @note: This api supports only SVG format + * @warning: you have responsibility to release the @p data memory if the @p copy is true + * + * @deprecated This method will go away next release. + * @see load(data, size, mimeType, copy) + */ + Result load(const char* data, uint32_t size, bool copy = false) noexcept; + + /** + * @brief Loads a picture data from a memory block of a given size. + * + * @param[in] data A pointer to a memory location where the content of the picture file is stored. + * @param[in] size The size in bytes of the memory occupied by the @p data. + * @param[in] mimetype Mimetype or extension of data such as "jpg", "jpeg", "svg", "svg+xml", "png", etc. If empty string or unknown, loaders will be tried one by one. + * @param[in] copy Decides whether the data should be copied into the engine local buffer. + * + * @retval Result::Success When succeed. + * @retval Result::InvalidArguments In case no data are provided or the @p size is zero or less. + * @retval Result::NonSupport When trying to load a file with an unknown extension. + * @retval Result::Unknown If an error occurs at a later stage. * * @warning: you have responsibility to release the @p data memory if the @p copy is true */ - Result load(const char* data, uint32_t size, bool copy = false) noexcept; + Result load(const char* data, uint32_t size, const std::string& mimeType, bool copy = false) noexcept; /** * @brief Resize the picture content with the given width and height. diff --git a/src/bindings/capi/thorvg_capi.h b/src/bindings/capi/thorvg_capi.h index cc37c8c9..d58249da 100644 --- a/src/bindings/capi/thorvg_capi.h +++ b/src/bindings/capi/thorvg_capi.h @@ -1676,6 +1676,7 @@ TVG_EXPORT Tvg_Result tvg_picture_load_raw(Tvg_Paint* paint, uint32_t *data, uin * \param[in] paint Tvg_Paint pointer * \param[in] data raw data pointer * \param[in] size of data +* \param[in] mimetype mimetype of data * \param[in] copy Decides whether the data should be copied into the local buffer * * \return Tvg_Result return value @@ -1684,7 +1685,7 @@ TVG_EXPORT Tvg_Result tvg_picture_load_raw(Tvg_Paint* paint, uint32_t *data, uin * * \warning Please do not use it, this API is not official one. It can be modified in the next version. */ -TVG_EXPORT Tvg_Result tvg_picture_load_data(Tvg_Paint* paint, const char *data, uint32_t size, bool copy); +TVG_EXPORT Tvg_Result tvg_picture_load_data(Tvg_Paint* paint, const char *data, uint32_t size, const char *mimetype, bool copy); /*! diff --git a/src/bindings/capi/tvgCapi.cpp b/src/bindings/capi/tvgCapi.cpp index d9a50f66..19c52c70 100644 --- a/src/bindings/capi/tvgCapi.cpp +++ b/src/bindings/capi/tvgCapi.cpp @@ -463,10 +463,10 @@ TVG_EXPORT Tvg_Result tvg_picture_load_raw(Tvg_Paint* paint, uint32_t *data, uin } -TVG_EXPORT Tvg_Result tvg_picture_load_data(Tvg_Paint* paint, const char *data, uint32_t size, bool copy) +TVG_EXPORT Tvg_Result tvg_picture_load_data(Tvg_Paint* paint, const char *data, uint32_t size, const char *mimetype, bool copy) { if (!paint) return TVG_RESULT_INVALID_ARGUMENT; - return (Tvg_Result) reinterpret_cast(paint)->load(data, size, copy); + return (Tvg_Result) reinterpret_cast(paint)->load(data, size, mimetype ? mimetype : "", copy); } diff --git a/src/examples/PictureJpg.cpp b/src/examples/PictureJpg.cpp index 11d4ae94..7f4e6c5d 100644 --- a/src/examples/PictureJpg.cpp +++ b/src/examples/PictureJpg.cpp @@ -57,8 +57,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) file.close(); auto picture = tvg::Picture::gen(); - if (picture->load(data, size, true) != tvg::Result::Success) { - cout << "Couldnt load JPG file from data." << endl; + if (picture->load(data, size, "jpg", true) != tvg::Result::Success) { + cout << "Couldn't load JPG file from data." << endl; return; } diff --git a/src/examples/PicturePng.cpp b/src/examples/PicturePng.cpp index 52f40fde..d7ad2081 100644 --- a/src/examples/PicturePng.cpp +++ b/src/examples/PicturePng.cpp @@ -57,8 +57,8 @@ void tvgDrawCmds(tvg::Canvas* canvas) file.close(); auto picture = tvg::Picture::gen(); - if (picture->load(data, size, true) != tvg::Result::Success) { - cout << "Couldnt load PNG file from data." << endl; + if (picture->load(data, size, "png", true) != tvg::Result::Success) { + cout << "Couldn't load PNG file from data." << endl; return; } diff --git a/src/examples/Svg2.cpp b/src/examples/Svg2.cpp index db823697..87d3960d 100644 --- a/src/examples/Svg2.cpp +++ b/src/examples/Svg2.cpp @@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas) if (canvas->push(move(shape)) != tvg::Result::Success) return; auto picture = tvg::Picture::gen(); - if (picture->load(svg, strlen(svg)) != tvg::Result::Success) return; + if (picture->load(svg, strlen(svg), "svg") != tvg::Result::Success) return; picture->size(WIDTH, HEIGHT); diff --git a/src/lib/tvgLoader.cpp b/src/lib/tvgLoader.cpp index 825017bb..2ee710eb 100644 --- a/src/lib/tvgLoader.cpp +++ b/src/lib/tvgLoader.cpp @@ -158,9 +158,33 @@ shared_ptr LoaderMgr::loader(const string& path, bool* invalid) } -shared_ptr LoaderMgr::loader(const char* data, uint32_t size, bool copy) +shared_ptr LoaderMgr::loader(const char* data, uint32_t size, const string& mimeType, bool copy) { + FileType filetype = FileType::Unknown; + if (!mimeType.empty()) { + if (mimeType == "tvg") filetype = FileType::Tvg; + else if (mimeType == "svg") filetype = FileType::Svg; + else if (mimeType == "svg+xml") filetype = FileType::Svg; + else if (mimeType == "raw") filetype = FileType::Raw; + else if (mimeType == "png") filetype = FileType::Png; + else if (mimeType == "jpg") filetype = FileType::Jpg; + else if (mimeType == "jpeg") filetype = FileType::Jpg; + else TVGLOG("LOADER", "Provided unknown mimetype \"%s\".", mimeType.c_str()); + + if (filetype != FileType::Unknown) { + auto loader = _find(static_cast(filetype)); + if (loader) { + if (loader->open(data, size, copy)) return shared_ptr(loader); + else { + TVGLOG("LOADER", "Provided mimetype \"%s\" (filetype=%d) seems incorrect. Will try other types.", mimeType.c_str(), static_cast(filetype)); + delete(loader); + } + } + } + } + for (int i = 0; i < static_cast(FileType::Unknown); i++) { + if (static_cast(i) == filetype) continue; auto loader = _find(static_cast(i)); if (loader) { if (loader->open(data, size, copy)) return shared_ptr(loader); diff --git a/src/lib/tvgLoader.h b/src/lib/tvgLoader.h index 9072769a..8ba3c139 100644 --- a/src/lib/tvgLoader.h +++ b/src/lib/tvgLoader.h @@ -29,7 +29,7 @@ struct LoaderMgr static bool init(); static bool term(); static shared_ptr loader(const string& path, bool* invalid); - static shared_ptr loader(const char* data, uint32_t size, bool copy); + static shared_ptr loader(const char* data, uint32_t size, const string& mimeType, bool copy); static shared_ptr loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); }; diff --git a/src/lib/tvgPicture.cpp b/src/lib/tvgPicture.cpp index db0ee6ed..26df9f0d 100644 --- a/src/lib/tvgPicture.cpp +++ b/src/lib/tvgPicture.cpp @@ -53,11 +53,16 @@ Result Picture::load(const std::string& path) noexcept } -Result Picture::load(const char* data, uint32_t size, bool copy) noexcept +Result Picture::load(const char* data, uint32_t size, const string& mimeType, bool copy) noexcept { if (!data || size <= 0) return Result::InvalidArguments; - return pImpl->load(data, size, copy); + return pImpl->load(data, size, mimeType, copy); +} + +Result Picture::load(const char* data, uint32_t size, bool copy) noexcept +{ + return load(data, size, "", copy); } diff --git a/src/lib/tvgPictureImpl.h b/src/lib/tvgPictureImpl.h index ff9d1e9a..eb0edd9e 100644 --- a/src/lib/tvgPictureImpl.h +++ b/src/lib/tvgPictureImpl.h @@ -173,10 +173,10 @@ struct Picture::Impl return Result::Success; } - Result load(const char* data, uint32_t size, bool copy) + Result load(const char* data, uint32_t size, const string& mimeType, bool copy) { if (loader) loader->close(); - loader = LoaderMgr::loader(data, size, copy); + loader = LoaderMgr::loader(data, size, mimeType, copy); if (!loader) return Result::NonSupport; if (!loader->read()) return Result::Unknown; w = loader->w; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index bdfbaffe..f41b6486 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -396,7 +396,7 @@ static constexpr struct }; -static bool _isValidImageMimeTypeAndEncoding(const char** href, imageMimeTypeEncoding* encoding) { +static bool _isValidImageMimeTypeAndEncoding(const char** href, const char** mimetype, imageMimeTypeEncoding* encoding) { if (strncmp(*href, "image/", sizeof("image/") - 1)) return false; //not allowed mime type *href += sizeof("image/") - 1; @@ -406,6 +406,7 @@ static bool _isValidImageMimeTypeAndEncoding(const char** href, imageMimeTypeEnc for (unsigned int i = 0; i < sizeof(imageMimeTypes) / sizeof(imageMimeTypes[0]); i++) { if (!strncmp(*href, imageMimeTypes[i].name, imageMimeTypes[i].sz - 1)) { *href += imageMimeTypes[i].sz - 1; + *mimetype = imageMimeTypes[i].name; while (**href && **href != ',') { while (**href && **href != ';') ++(*href); @@ -448,14 +449,15 @@ static unique_ptr _imageBuildHelper(SvgNode* node, float vx, float vy, const char* href = (*node->node.image.href).c_str(); if (!strncmp(href, "data:", sizeof("data:") - 1)) { href += sizeof("data:") - 1; + const char* mimetype; imageMimeTypeEncoding encoding; - if (!_isValidImageMimeTypeAndEncoding(&href, &encoding)) return nullptr; //not allowed mime type or encoding + if (!_isValidImageMimeTypeAndEncoding(&href, &mimetype, &encoding)) return nullptr; //not allowed mime type or encoding if (encoding == imageMimeTypeEncoding::base64) { string decoded = svgUtilBase64Decode(href); - if (picture->load(decoded.c_str(), decoded.size(), true) != Result::Success) return nullptr; + if (picture->load(decoded.c_str(), decoded.size(), mimetype, true) != Result::Success) return nullptr; } else { string decoded = svgUtilURLDecode(href); - if (picture->load(decoded.c_str(), decoded.size(), true) != Result::Success) return nullptr; + if (picture->load(decoded.c_str(), decoded.size(), mimetype, true) != Result::Success) return nullptr; } } else { if (!strncmp(href, "file://", sizeof("file://") - 1)) href += sizeof("file://") - 1; diff --git a/test/capi/capiPicture.cpp b/test/capi/capiPicture.cpp index f9c7ae87..e59c54ed 100644 --- a/test/capi/capiPicture.cpp +++ b/test/capi/capiPicture.cpp @@ -53,12 +53,12 @@ TEST_CASE("Load Svg Data in Picture", "[capiPicture]") REQUIRE(picture); //Negative - REQUIRE(tvg_picture_load_data(nullptr, svg, strlen(svg), true) == TVG_RESULT_INVALID_ARGUMENT); - REQUIRE(tvg_picture_load_data(picture, nullptr, strlen(svg), true) == TVG_RESULT_INVALID_ARGUMENT); - REQUIRE(tvg_picture_load_data(picture, svg, 0, true) == TVG_RESULT_INVALID_ARGUMENT); + REQUIRE(tvg_picture_load_data(nullptr, svg, strlen(svg), nullptr, true) == TVG_RESULT_INVALID_ARGUMENT); + REQUIRE(tvg_picture_load_data(picture, nullptr, strlen(svg), "", true) == TVG_RESULT_INVALID_ARGUMENT); + REQUIRE(tvg_picture_load_data(picture, svg, 0, "", true) == TVG_RESULT_INVALID_ARGUMENT); //Positive - REQUIRE(tvg_picture_load_data(picture, svg, strlen(svg), false) == TVG_RESULT_SUCCESS); + REQUIRE(tvg_picture_load_data(picture, svg, strlen(svg), "svg", false) == TVG_RESULT_SUCCESS); //Verify Size float w, h; diff --git a/test/testPicture.cpp b/test/testPicture.cpp index a468463d..53b48f4b 100644 --- a/test/testPicture.cpp +++ b/test/testPicture.cpp @@ -51,11 +51,11 @@ TEST_CASE("Load SVG Data", "[tvgPicture]") REQUIRE(picture); //Negative cases - REQUIRE(picture->load(nullptr, 100) == Result::InvalidArguments); - REQUIRE(picture->load(svg, 0) == Result::InvalidArguments); + REQUIRE(picture->load(nullptr, 100, "") == Result::InvalidArguments); + REQUIRE(picture->load(svg, 0, "") == Result::InvalidArguments); //Positive cases - REQUIRE(picture->load(svg, strlen(svg)) == Result::Success); + REQUIRE(picture->load(svg, strlen(svg), "svg") == Result::Success); float w, h; REQUIRE(picture->size(&w, &h) == Result::Success); @@ -125,8 +125,8 @@ TEST_CASE("Load PNG file from data", "[tvgPicture]") file.read(data, size); file.close(); - REQUIRE(picture->load(data, size, false) == Result::Success); - REQUIRE(picture->load(data, size, true) == Result::Success); + REQUIRE(picture->load(data, size, "", false) == Result::Success); + REQUIRE(picture->load(data, size, "png", true) == Result::Success); float w, h; REQUIRE(picture->size(&w, &h) == Result::Success); @@ -169,8 +169,8 @@ TEST_CASE("Load JPG file from data", "[tvgPicture]") file.read(data, size); file.close(); - REQUIRE(picture->load(data, size, false) == Result::Success); - REQUIRE(picture->load(data, size, true) == Result::Success); + REQUIRE(picture->load(data, size, "", false) == Result::Success); + REQUIRE(picture->load(data, size, "jpg", true) == Result::Success); float w, h; REQUIRE(picture->size(&w, &h) == Result::Success);