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
This commit is contained in:
Michal Maciola 2021-08-05 04:02:26 +02:00 committed by GitHub
parent 0e98809f15
commit cff8815404
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 81 additions and 31 deletions

View file

@ -1012,11 +1012,29 @@ public:
* @retval Result::NonSupport When trying to load a file with an unknown extension. * @retval Result::NonSupport When trying to load a file with an unknown extension.
* @retval Result::Unknown If an error occurs at a later stage. * @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 * @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. * @brief Resize the picture content with the given width and height.

View file

@ -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] paint Tvg_Paint pointer
* \param[in] data raw data pointer * \param[in] data raw data pointer
* \param[in] size of data * \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 * \param[in] copy Decides whether the data should be copied into the local buffer
* *
* \return Tvg_Result return value * \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. * \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);
/*! /*!

View file

@ -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; if (!paint) return TVG_RESULT_INVALID_ARGUMENT;
return (Tvg_Result) reinterpret_cast<Picture*>(paint)->load(data, size, copy); return (Tvg_Result) reinterpret_cast<Picture*>(paint)->load(data, size, mimetype ? mimetype : "", copy);
} }

View file

@ -57,8 +57,8 @@ void tvgDrawCmds(tvg::Canvas* canvas)
file.close(); file.close();
auto picture = tvg::Picture::gen(); auto picture = tvg::Picture::gen();
if (picture->load(data, size, true) != tvg::Result::Success) { if (picture->load(data, size, "jpg", true) != tvg::Result::Success) {
cout << "Couldnt load JPG file from data." << endl; cout << "Couldn't load JPG file from data." << endl;
return; return;
} }

View file

@ -57,8 +57,8 @@ void tvgDrawCmds(tvg::Canvas* canvas)
file.close(); file.close();
auto picture = tvg::Picture::gen(); auto picture = tvg::Picture::gen();
if (picture->load(data, size, true) != tvg::Result::Success) { if (picture->load(data, size, "png", true) != tvg::Result::Success) {
cout << "Couldnt load PNG file from data." << endl; cout << "Couldn't load PNG file from data." << endl;
return; return;
} }

View file

@ -41,7 +41,7 @@ void tvgDrawCmds(tvg::Canvas* canvas)
if (canvas->push(move(shape)) != tvg::Result::Success) return; if (canvas->push(move(shape)) != tvg::Result::Success) return;
auto picture = tvg::Picture::gen(); 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); picture->size(WIDTH, HEIGHT);

View file

@ -158,9 +158,33 @@ shared_ptr<LoadModule> LoaderMgr::loader(const string& path, bool* invalid)
} }
shared_ptr<LoadModule> LoaderMgr::loader(const char* data, uint32_t size, bool copy) shared_ptr<LoadModule> 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>(filetype));
if (loader) {
if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader);
else {
TVGLOG("LOADER", "Provided mimetype \"%s\" (filetype=%d) seems incorrect. Will try other types.", mimeType.c_str(), static_cast<int>(filetype));
delete(loader);
}
}
}
}
for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) { for (int i = 0; i < static_cast<int>(FileType::Unknown); i++) {
if (static_cast<FileType>(i) == filetype) continue;
auto loader = _find(static_cast<FileType>(i)); auto loader = _find(static_cast<FileType>(i));
if (loader) { if (loader) {
if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader); if (loader->open(data, size, copy)) return shared_ptr<LoadModule>(loader);

View file

@ -29,7 +29,7 @@ struct LoaderMgr
static bool init(); static bool init();
static bool term(); static bool term();
static shared_ptr<LoadModule> loader(const string& path, bool* invalid); static shared_ptr<LoadModule> loader(const string& path, bool* invalid);
static shared_ptr<LoadModule> loader(const char* data, uint32_t size, bool copy); static shared_ptr<LoadModule> loader(const char* data, uint32_t size, const string& mimeType, bool copy);
static shared_ptr<LoadModule> loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy); static shared_ptr<LoadModule> loader(const uint32_t* data, uint32_t w, uint32_t h, bool copy);
}; };

View file

@ -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; 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);
} }

View file

@ -173,10 +173,10 @@ struct Picture::Impl
return Result::Success; 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(); if (loader) loader->close();
loader = LoaderMgr::loader(data, size, copy); loader = LoaderMgr::loader(data, size, mimeType, copy);
if (!loader) return Result::NonSupport; if (!loader) return Result::NonSupport;
if (!loader->read()) return Result::Unknown; if (!loader->read()) return Result::Unknown;
w = loader->w; w = loader->w;

View file

@ -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 if (strncmp(*href, "image/", sizeof("image/") - 1)) return false; //not allowed mime type
*href += sizeof("image/") - 1; *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++) { for (unsigned int i = 0; i < sizeof(imageMimeTypes) / sizeof(imageMimeTypes[0]); i++) {
if (!strncmp(*href, imageMimeTypes[i].name, imageMimeTypes[i].sz - 1)) { if (!strncmp(*href, imageMimeTypes[i].name, imageMimeTypes[i].sz - 1)) {
*href += imageMimeTypes[i].sz - 1; *href += imageMimeTypes[i].sz - 1;
*mimetype = imageMimeTypes[i].name;
while (**href && **href != ',') { while (**href && **href != ',') {
while (**href && **href != ';') ++(*href); while (**href && **href != ';') ++(*href);
@ -448,14 +449,15 @@ static unique_ptr<Picture> _imageBuildHelper(SvgNode* node, float vx, float vy,
const char* href = (*node->node.image.href).c_str(); const char* href = (*node->node.image.href).c_str();
if (!strncmp(href, "data:", sizeof("data:") - 1)) { if (!strncmp(href, "data:", sizeof("data:") - 1)) {
href += sizeof("data:") - 1; href += sizeof("data:") - 1;
const char* mimetype;
imageMimeTypeEncoding encoding; 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) { if (encoding == imageMimeTypeEncoding::base64) {
string decoded = svgUtilBase64Decode(href); 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 { } else {
string decoded = svgUtilURLDecode(href); 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 { } else {
if (!strncmp(href, "file://", sizeof("file://") - 1)) href += sizeof("file://") - 1; if (!strncmp(href, "file://", sizeof("file://") - 1)) href += sizeof("file://") - 1;

View file

@ -53,12 +53,12 @@ TEST_CASE("Load Svg Data in Picture", "[capiPicture]")
REQUIRE(picture); REQUIRE(picture);
//Negative //Negative
REQUIRE(tvg_picture_load_data(nullptr, svg, strlen(svg), 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, 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(picture, svg, 0, "", true) == TVG_RESULT_INVALID_ARGUMENT);
//Positive //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 //Verify Size
float w, h; float w, h;

View file

@ -51,11 +51,11 @@ TEST_CASE("Load SVG Data", "[tvgPicture]")
REQUIRE(picture); REQUIRE(picture);
//Negative cases //Negative cases
REQUIRE(picture->load(nullptr, 100) == Result::InvalidArguments); REQUIRE(picture->load(nullptr, 100, "") == Result::InvalidArguments);
REQUIRE(picture->load(svg, 0) == Result::InvalidArguments); REQUIRE(picture->load(svg, 0, "") == Result::InvalidArguments);
//Positive cases //Positive cases
REQUIRE(picture->load(svg, strlen(svg)) == Result::Success); REQUIRE(picture->load(svg, strlen(svg), "svg") == Result::Success);
float w, h; float w, h;
REQUIRE(picture->size(&w, &h) == Result::Success); REQUIRE(picture->size(&w, &h) == Result::Success);
@ -125,8 +125,8 @@ TEST_CASE("Load PNG file from data", "[tvgPicture]")
file.read(data, size); file.read(data, size);
file.close(); file.close();
REQUIRE(picture->load(data, size, false) == Result::Success); REQUIRE(picture->load(data, size, "", false) == Result::Success);
REQUIRE(picture->load(data, size, true) == Result::Success); REQUIRE(picture->load(data, size, "png", true) == Result::Success);
float w, h; float w, h;
REQUIRE(picture->size(&w, &h) == Result::Success); REQUIRE(picture->size(&w, &h) == Result::Success);
@ -169,8 +169,8 @@ TEST_CASE("Load JPG file from data", "[tvgPicture]")
file.read(data, size); file.read(data, size);
file.close(); file.close();
REQUIRE(picture->load(data, size, false) == Result::Success); REQUIRE(picture->load(data, size, "", false) == Result::Success);
REQUIRE(picture->load(data, size, true) == Result::Success); REQUIRE(picture->load(data, size, "jpg", true) == Result::Success);
float w, h; float w, h;
REQUIRE(picture->size(&w, &h) == Result::Success); REQUIRE(picture->size(&w, &h) == Result::Success);