diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index c8a884be..041bd0d3 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -21,12 +21,12 @@ jobs: sudo apt-get update sudo apt-get install ninja-build gcc-multilib g++-multilib sudo apt-get install python3-pip - sudo apt-get install libturbojpeg0-dev libpng-dev + sudo apt-get install libturbojpeg0-dev libpng-dev libwebp-dev sudo pip3 install meson - name: Build run: | - meson . build -Dlog=true -Dloaders="all" -Dsavers="all" -Dbindings="capi" -Dtools="all" + meson . build -Dlog=true -Dloaders="all, webp_beta" -Dsavers="all" -Dbindings="capi" -Dtools="all" sudo ninja -C build install static_loaders: @@ -45,7 +45,7 @@ jobs: - name: Build run: | - meson . build -Dlog=true -Dloaders="all" -Dsavers="all" -Dbindings="capi" -Dtools="all" -Dstatic=true + meson . build -Dlog=true -Dloaders="tvg, svg, png, jpg" -Dsavers="all" -Dbindings="capi" -Dtools="all" -Dstatic=true sudo ninja -C build install examples: @@ -61,12 +61,12 @@ jobs: sudo apt-get install ninja-build gcc-multilib g++-multilib sudo apt-get install libefl-all-dev sudo apt-get install python3-pip - sudo apt-get install libturbojpeg0-dev libpng-dev + sudo apt-get install libturbojpeg0-dev libpng-dev libwebp-dev sudo pip3 install meson - name: Build run: | - meson . build -Dexamples=true -Dloaders="all" -Dsavers="all" -Dbindings="capi" + meson . build -Dexamples=true -Dloaders="all, webp_beta" -Dsavers="all" -Dbindings="capi" sudo ninja -C build install unit_test: @@ -83,12 +83,12 @@ jobs: sudo apt-get install curl jq sudo apt-get install software-properties-common sudo apt-get install python3-pip - sudo apt-get install libturbojpeg0-dev libpng-dev + sudo apt-get install libturbojpeg0-dev libpng-dev libwebp-dev sudo pip3 install meson - name: Build run: | - meson . build -Dtests=true -Dloaders="all" -Dsavers="all" -Dbindings="capi" --errorlogs + meson . build -Dtests=true -Dloaders="all, webp_beta" -Dsavers="all" -Dbindings="capi" --errorlogs sudo ninja -C build install test - uses: actions/upload-artifact@v3 @@ -107,10 +107,10 @@ jobs: - name: Build & Run memcheck Script(ASAN) run: | sudo rm -rf ./build - meson . build -Db_sanitize="address,undefined" -Dloaders="all" -Dsavers="all" -Dtests="true" -Dbindings="capi" + meson . build -Db_sanitize="address,undefined" -Dloaders="all, webp_beta" -Dsavers="all" -Dtests="true" -Dbindings="capi" sudo ninja -C build install export PATH=$PATH:~/.local/bin/ chmod +x "${GITHUB_WORKSPACE}/.github/workflows/memcheck_asan.sh" "${GITHUB_WORKSPACE}/.github/workflows/memcheck_asan.sh" env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ce3f63a1..10b15e81 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -69,9 +69,9 @@ jobs: sudo apt-get install ninja-build gcc-multilib g++-multilib sudo apt-get install python3-pip sudo pip3 install meson - sudo apt-get install libturbojpeg0-dev libpng-dev + sudo apt-get install libturbojpeg0-dev libpng-dev libwebp-dev - meson . build -Dbindings="capi" -Dloaders="all" -Dsavers="all" -Dtools="all" + meson . build -Dbindings="capi" -Dloaders="all, webp_beta" -Dsavers="all" -Dtools="all" sudo ninja -C build install diff --git a/meson.build b/meson.build index 05ea2b96..9ce2e400 100644 --- a/meson.build +++ b/meson.build @@ -45,6 +45,10 @@ if all_loaders or get_option('loaders').contains('jpg') == true config_h.set10('THORVG_JPG_LOADER_SUPPORT', true) endif +if get_option('loaders').contains('webp_beta') == true + config_h.set10('THORVG_WEBP_LOADER_SUPPORT', true) +endif + #Savers all_savers = false @@ -114,13 +118,14 @@ Summary: Loader (SVG): @7@ Loader (PNG): @8@ Loader (JPG): @9@ - Saver (TVG): @10@ - CAPI Binding: @11@ - Log Message: @12@ - Tests: @13@ - Examples: @14@ - Tool (Svg2Tvg): @15@ - Tool (Svg2Png): @16@ + Loader (WEBP_BETA): @10@ + Saver (TVG): @11@ + CAPI Binding: @12@ + Log Message: @13@ + Tests: @14@ + Examples: @15@ + Tool (Svg2Tvg): @16@ + Tool (Svg2Png): @17@ '''.format( meson.project_version(), @@ -133,6 +138,7 @@ Summary: all_loaders or get_option('loaders').contains('svg'), all_loaders or get_option('loaders').contains('png'), all_loaders or get_option('loaders').contains('jpg'), + get_option('loaders').contains('webp_beta'), all_savers or get_option('savers').contains('tvg'), get_option('bindings').contains('capi'), get_option('log'), diff --git a/meson_options.txt b/meson_options.txt index e840b59e..399cd095 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,9 +6,9 @@ option('engines', option('loaders', type: 'array', - choices: ['', 'tvg', 'svg', 'png', 'jpg', 'all'], + choices: ['', 'tvg', 'svg', 'png', 'jpg', 'webp_beta','all'], value: ['svg', 'tvg'], - description: 'Enable File Loaders in thorvg') + description: 'Enable File Loaders in thorvg ("all" does not include "*_beta".)') option('savers', type: 'array', diff --git a/src/examples/PictureWebp.cpp b/src/examples/PictureWebp.cpp new file mode 100644 index 00000000..20bf41b8 --- /dev/null +++ b/src/examples/PictureWebp.cpp @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include "Common.h" + +/************************************************************************/ +/* Drawing Commands */ +/************************************************************************/ + +void tvgDrawCmds(tvg::Canvas* canvas) +{ + if (!canvas) return; + + //Background + auto bg = tvg::Shape::gen(); + bg->appendRect(0, 0, WIDTH, HEIGHT, 0, 0); //x, y, w, h, rx, ry + bg->fill(255, 255, 255); //r, g, b + canvas->push(move(bg)); + + //Load webp file from path + auto opacity = 31; + + for (int i = 0; i < 7; ++i) { + auto picture = tvg::Picture::gen(); + if (picture->load(EXAMPLE_DIR"/test.webp") != tvg::Result::Success) { + cout << "WEBP is not supported. Did you enable WEBP Loader?" << endl; + return; + } + picture->translate(i* 150, i * 150); + picture->rotate(30 * i); + picture->size(200, 200); + picture->opacity(opacity + opacity * i); + if (canvas->push(move(picture)) != tvg::Result::Success) return; + } + + //Open file manually + ifstream file(EXAMPLE_DIR"/test.webp"); + if (!file.is_open()) return; + auto begin = file.tellg(); + file.seekg(0, std::ios::end); + auto size = file.tellg() - begin; + auto data = (char*)malloc(size); + if (!data) return; + file.seekg(0, std::ios::beg); + file.read(data, size); + file.close(); + + auto picture = tvg::Picture::gen(); + if (picture->load(data, size, "webp", true) != tvg::Result::Success) { + cout << "Couldn't load WEBP file from data." << endl; + return; + } + + free(data); + picture->translate(400, 0); + picture->scale(0.8); + canvas->push(move(picture)); + +} + + +/************************************************************************/ +/* Sw Engine Test Code */ +/************************************************************************/ + +static unique_ptr swCanvas; + +void tvgSwTest(uint32_t* buffer) +{ + //Create a Canvas + swCanvas = tvg::SwCanvas::gen(); + swCanvas->target(buffer, WIDTH, WIDTH, HEIGHT, tvg::SwCanvas::ARGB8888); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(swCanvas.get()); +} + +void drawSwView(void* data, Eo* obj) +{ + if (swCanvas->draw() == tvg::Result::Success) { + swCanvas->sync(); + } +} + + +/************************************************************************/ +/* GL Engine Test Code */ +/************************************************************************/ + +static unique_ptr glCanvas; + +void initGLview(Evas_Object *obj) +{ + static constexpr auto BPP = 4; + + //Create a Canvas + glCanvas = tvg::GlCanvas::gen(); + glCanvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT); + + /* Push the shape into the Canvas drawing list + When this shape is into the canvas list, the shape could update & prepare + internal data asynchronously for coming rendering. + Canvas keeps this shape node unless user call canvas->clear() */ + tvgDrawCmds(glCanvas.get()); +} + +void drawGLview(Evas_Object *obj) +{ + auto gl = elm_glview_gl_api_get(obj); + gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + gl->glClear(GL_COLOR_BUFFER_BIT); + + if (glCanvas->draw() == tvg::Result::Success) { + glCanvas->sync(); + } +} + + +/************************************************************************/ +/* Main Code */ +/************************************************************************/ + +int main(int argc, char **argv) +{ + tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw; + + if (argc > 1) { + if (!strcmp(argv[1], "gl")) tvgEngine = tvg::CanvasEngine::Gl; + } + + //Initialize ThorVG Engine + if (tvgEngine == tvg::CanvasEngine::Sw) { + cout << "tvg engine: software" << endl; + } else { + cout << "tvg engine: opengl" << endl; + } + + //Threads Count + auto threads = std::thread::hardware_concurrency(); + + //Initialize ThorVG Engine + if (tvg::Initializer::init(tvgEngine, threads) == tvg::Result::Success) { + + elm_init(argc, argv); + + if (tvgEngine == tvg::CanvasEngine::Sw) { + createSwView(); + } else { + createGlView(); + } + + elm_run(); + elm_shutdown(); + + //Terminate ThorVG Engine + tvg::Initializer::term(tvgEngine); + + + } else { + cout << "engine is not supported" << endl; + } + return 0; +} diff --git a/src/examples/images/test.webp b/src/examples/images/test.webp new file mode 100644 index 00000000..eff7ada7 Binary files /dev/null and b/src/examples/images/test.webp differ diff --git a/src/examples/meson.build b/src/examples/meson.build index 105b4578..9678809f 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -36,6 +36,7 @@ source_file = [ 'PicturePng.cpp', 'PictureRaw.cpp', 'PictureTvg.cpp', + 'PictureWebp.cpp', 'RadialGradient.cpp', 'Scene.cpp', 'SceneClipper.cpp', diff --git a/src/lib/tvgCommon.h b/src/lib/tvgCommon.h index 1731647c..3800c055 100644 --- a/src/lib/tvgCommon.h +++ b/src/lib/tvgCommon.h @@ -62,7 +62,7 @@ using namespace tvg; #define TVG_CLASS_ID_LINEAR 4 #define TVG_CLASS_ID_RADIAL 5 -enum class FileType { Tvg = 0, Svg, Raw, Png, Jpg, Unknown }; +enum class FileType { Tvg = 0, Svg, Raw, Png, Jpg, Webp, Unknown }; #ifdef THORVG_LOG_ENABLED constexpr auto ErrorColor = "\033[31m"; //red diff --git a/src/lib/tvgLoader.cpp b/src/lib/tvgLoader.cpp index 2bbe1778..4e6f7c3e 100644 --- a/src/lib/tvgLoader.cpp +++ b/src/lib/tvgLoader.cpp @@ -38,6 +38,10 @@ #include "tvgJpgLoader.h" #endif +#ifdef THORVG_WEBP_LOADER_SUPPORT + #include "tvgWebpLoader.h" +#endif + #include "tvgRawLoader.h" /************************************************************************/ @@ -72,6 +76,12 @@ static LoadModule* _find(FileType type) case FileType::Jpg: { #ifdef THORVG_JPG_LOADER_SUPPORT return new JpgLoader; +#endif + break; + } + case FileType::Webp: { +#ifdef THORVG_WEBP_LOADER_SUPPORT + return new WebpLoader; #endif break; } @@ -103,6 +113,10 @@ static LoadModule* _find(FileType type) format = "JPG"; break; } + case FileType::Webp: { + format = "WEBP"; + break; + } default: { format = "???"; break; @@ -121,6 +135,7 @@ static LoadModule* _findByPath(const string& path) if (!ext.compare("svg")) return _find(FileType::Svg); if (!ext.compare("png")) return _find(FileType::Png); if (!ext.compare("jpg")) return _find(FileType::Jpg); + if (!ext.compare("webp")) return _find(FileType::Webp); return nullptr; } @@ -136,6 +151,7 @@ static LoadModule* _findByType(const string& mimeType) else if (mimeType == "raw") type = FileType::Raw; else if (mimeType == "png") type = FileType::Png; else if (mimeType == "jpg" || mimeType == "jpeg") type = FileType::Jpg; + else if (mimeType == "webp") type = FileType::Webp; else { TVGLOG("LOADER", "Given mimetype is unknown = \"%s\".", mimeType.c_str()); return nullptr; diff --git a/src/loaders/external_webp/meson.build b/src/loaders/external_webp/meson.build new file mode 100644 index 00000000..b92e6e97 --- /dev/null +++ b/src/loaders/external_webp/meson.build @@ -0,0 +1,14 @@ +source_file = [ + 'tvgWebpLoader.h', + 'tvgWebpLoader.cpp', +] + +webp_dep = dependency('libwebp', required: false) + +if webp_dep.found() + subloader_dep += [declare_dependency( + include_directories : include_directories('.'), + dependencies : webp_dep, + sources : source_file + )] +endif diff --git a/src/loaders/external_webp/tvgWebpLoader.cpp b/src/loaders/external_webp/tvgWebpLoader.cpp new file mode 100644 index 00000000..b8649c63 --- /dev/null +++ b/src/loaders/external_webp/tvgWebpLoader.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include + +#include "tvgLoader.h" +#include "tvgWebpLoader.h" + + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +void WebpLoader::clear() +{ + if (freeData) free(data); + data = nullptr; + size = 0; + freeData = false; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +WebpLoader::WebpLoader() +{ +} + + +WebpLoader::~WebpLoader() +{ + if (freeData) free(data); + WebPFree(image); +} + + +bool WebpLoader::open(const string& path) +{ + clear(); + + auto webpFile = fopen(path.c_str(), "rb"); + if (!webpFile) return false; + + auto ret = false; + + //determine size + if (fseek(webpFile, 0, SEEK_END) < 0) goto finalize; + if (((size = ftell(webpFile)) < 1)) goto finalize; + if (fseek(webpFile, 0, SEEK_SET)) goto finalize; + + data = (unsigned char *) malloc(size); + if (!data) goto finalize; + + freeData = true; + + if (fread(data, size, 1, webpFile) < 1) goto failure; + + int width, height; + if (!WebPGetInfo(data, size, &width, &height)) goto failure; + + w = static_cast(width); + h = static_cast(height); + cs = ColorSpace::ARGB8888; + + ret = true; + + goto finalize; + +failure: + clear(); + +finalize: + fclose(webpFile); + return ret; +} + + +bool WebpLoader::open(const char* data, uint32_t size, bool copy) +{ + clear(); + + if (copy) { + this->data = (unsigned char *) malloc(size); + if (!this->data) return false; + memcpy((unsigned char *)this->data, data, size); + freeData = true; + } else { + this->data = (unsigned char *) data; + freeData = false; + } + + int width, height; + if (!WebPGetInfo(this->data, size, &width, &height)) return false; + + w = static_cast(width); + h = static_cast(height); + cs = ColorSpace::ARGB8888; + this->size = size; + return true; +} + + +bool WebpLoader::read() +{ + if (!data || w <= 0 || h <= 0) return false; + + TaskScheduler::request(this); + return true; +} + + +bool WebpLoader::close() +{ + this->done(); + clear(); + return true; +} + + +unique_ptr WebpLoader::bitmap() +{ + this->done(); + + if (!image) return nullptr; + + //TODO: It's better to keep this surface instance in the loader side + auto surface = new Surface; + surface->buf8 = image; + surface->stride = static_cast(w); + surface->w = static_cast(w); + surface->h = static_cast(h); + surface->cs = cs; + surface->channelSize = sizeof(uint32_t); + surface->premultiplied = false; + surface->owner = true; + return unique_ptr(surface); +} + + +void WebpLoader::run(unsigned tid) +{ + if (image) { + WebPFree(image); + image = nullptr; + } + + image = WebPDecodeBGRA(data, size, nullptr, nullptr); +} diff --git a/src/loaders/external_webp/tvgWebpLoader.h b/src/loaders/external_webp/tvgWebpLoader.h new file mode 100644 index 00000000..38c6d82e --- /dev/null +++ b/src/loaders/external_webp/tvgWebpLoader.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2023 the ThorVG project. All rights reserved. + + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _TVG_WEBP_LOADER_H_ +#define _TVG_WEBP_LOADER_H_ + +#include "tvgTaskScheduler.h" + +class WebpLoader : public LoadModule, public Task +{ +public: + WebpLoader(); + ~WebpLoader(); + + using LoadModule::open; + bool open(const string& path) override; + bool open(const char* data, uint32_t size, bool copy) override; + bool read() override; + bool close() override; + + unique_ptr bitmap() override; + void run(unsigned tid) override; + +private: + void clear(); + + unsigned char* data = nullptr; + unsigned char *image = nullptr; + unsigned long size = 0; + bool freeData = false; +}; + +#endif //_TVG_WEBP_LOADER_H_ diff --git a/src/loaders/meson.build b/src/loaders/meson.build index a62a91ca..d4ce8adb 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -30,6 +30,14 @@ if all_loaders or get_option('loaders').contains('jpg') == true endif endif +if get_option('loaders').contains('webp_beta') == true + if get_option('static') == true + message('static webp is not available, disable webp_beta loader.') + else + subdir('external_webp') + endif +endif + subdir('raw') loader_dep = declare_dependency( diff --git a/test/capi/capiPicture.cpp b/test/capi/capiPicture.cpp index 5b84cf52..e1a3de26 100644 --- a/test/capi/capiPicture.cpp +++ b/test/capi/capiPicture.cpp @@ -204,4 +204,30 @@ TEST_CASE("Load Tvg file in Picture", "[capiPicture]") REQUIRE(tvg_paint_del(picture) == TVG_RESULT_SUCCESS); } -#endif \ No newline at end of file +#endif + +#ifdef THORVG_WEBP_LOADER_SUPPORT + +TEST_CASE("Load Webp file in Picture", "[capiPicture]") +{ + Tvg_Paint* picture = tvg_picture_new(); + REQUIRE(picture); + + //Invalid file + REQUIRE(tvg_picture_load(picture, "invalid.webp") == TVG_RESULT_INVALID_ARGUMENT); + + //Load Png file + REQUIRE(tvg_picture_load(picture, TEST_DIR"/test.webp") == TVG_RESULT_SUCCESS); + + //Verify Size + float wNew = 500.0f, hNew = 500.0f; + float w = 0.0f, h = 0.0f; + REQUIRE(tvg_picture_set_size(picture, wNew, hNew) == TVG_RESULT_SUCCESS); + REQUIRE(tvg_picture_get_size(picture, &w, &h) == TVG_RESULT_SUCCESS); + REQUIRE(w == Approx(wNew).epsilon(0.0000001)); + REQUIRE(h == Approx(hNew).epsilon(0.0000001)); + + REQUIRE(tvg_paint_del(picture) == TVG_RESULT_SUCCESS); +} + +#endif diff --git a/test/images/test.webp b/test/images/test.webp new file mode 100644 index 00000000..eff7ada7 Binary files /dev/null and b/test/images/test.webp differ diff --git a/test/testPicture.cpp b/test/testPicture.cpp index f0c4b73a..889d0d21 100644 --- a/test/testPicture.cpp +++ b/test/testPicture.cpp @@ -501,4 +501,71 @@ TEST_CASE("Load TVG file and render", "[tvgPicture]") delete[] buffer; } -#endif \ No newline at end of file +#endif + +#ifdef THORVG_WEBP_LOADER_SUPPORT + +TEST_CASE("Load WEBP file from path", "[tvgPicture]") +{ + auto picture = Picture::gen(); + REQUIRE(picture); + + //Invalid file + REQUIRE(picture->load("invalid.webp") == Result::InvalidArguments); + + REQUIRE(picture->load(TEST_DIR"/test.webp") == Result::Success); + + float w, h; + REQUIRE(picture->size(&w, &h) == Result::Success); + + REQUIRE(w == 512); + REQUIRE(h == 512); +} + +TEST_CASE("Load WEBP file from data", "[tvgPicture]") +{ + auto picture = Picture::gen(); + REQUIRE(picture); + + //Open file + ifstream file(TEST_DIR"/test.webp", ios::in | ios::binary); + REQUIRE(file.is_open()); + auto size = sizeof(uint32_t) * (1000*1000); + auto data = (char*)malloc(size); + file.read(data, size); + file.close(); + + REQUIRE(picture->load(data, size, "", false) == Result::Success); + REQUIRE(picture->load(data, size, "webp", true) == Result::Success); + + float w, h; + REQUIRE(picture->size(&w, &h) == Result::Success); + REQUIRE(w == 512); + REQUIRE(h == 512); + + free(data); +} + +TEST_CASE("Load WEBP file and render", "[tvgPicture]") +{ + REQUIRE(Initializer::init(CanvasEngine::Sw, 0) == Result::Success); + + auto canvas = SwCanvas::gen(); + REQUIRE(canvas); + + uint32_t buffer[100*100]; + REQUIRE(canvas->target(buffer, 100, 100, 100, SwCanvas::Colorspace::ABGR8888) == Result::Success); + + auto picture = Picture::gen(); + REQUIRE(picture); + + REQUIRE(picture->load(TEST_DIR"/test.webp") == Result::Success); + REQUIRE(picture->opacity(192) == Result::Success); + REQUIRE(picture->scale(5.0) == Result::Success); + + REQUIRE(canvas->push(std::move(picture)) == Result::Success); + + REQUIRE(Initializer::term(CanvasEngine::Sw) == Result::Success); +} + +#endif