From 60f81b7da71a13161cffde6e2ff82944748a8d31 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 20 Jun 2023 17:13:02 +0900 Subject: [PATCH] loader lottie: added empty interface body This marks the first step towards implementing the Lottie feature. --- meson.build | 21 +- meson_options.txt | 2 +- src/loaders/lottie/meson.build | 9 + src/loaders/lottie/tvgLottieLoader.cpp | 294 +++++++++++++++++++++++++ src/loaders/lottie/tvgLottieLoader.h | 9 +- src/loaders/meson.build | 4 + src/loaders/svg/tvgSvgLoader.cpp | 3 +- src/loaders/tvg/tvgTvgLoader.cpp | 3 +- 8 files changed, 328 insertions(+), 17 deletions(-) create mode 100644 src/loaders/lottie/meson.build create mode 100644 src/loaders/lottie/tvgLottieLoader.cpp diff --git a/meson.build b/meson.build index 9ce2e400..edf4d729 100644 --- a/meson.build +++ b/meson.build @@ -49,6 +49,11 @@ if get_option('loaders').contains('webp_beta') == true config_h.set10('THORVG_WEBP_LOADER_SUPPORT', true) endif +if get_option('loaders').contains('lottie_beta') == true + config_h.set10('THORVG_LOTTIE_LOADER_SUPPORT', true) +endif + + #Savers all_savers = false @@ -119,13 +124,14 @@ Summary: Loader (PNG): @8@ Loader (JPG): @9@ Loader (WEBP_BETA): @10@ - Saver (TVG): @11@ - CAPI Binding: @12@ - Log Message: @13@ - Tests: @14@ - Examples: @15@ - Tool (Svg2Tvg): @16@ - Tool (Svg2Png): @17@ + Loader (LOTTIE_BETA): @11@ + Saver (TVG): @12@ + CAPI Binding: @13@ + Log Message: @14@ + Tests: @15@ + Examples: @16@ + Tool (Svg2Tvg): @17@ + Tool (Svg2Png): @18@ '''.format( meson.project_version(), @@ -139,6 +145,7 @@ Summary: all_loaders or get_option('loaders').contains('png'), all_loaders or get_option('loaders').contains('jpg'), get_option('loaders').contains('webp_beta'), + get_option('loaders').contains('lottie_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 399cd095..c6acdc7b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,7 +6,7 @@ option('engines', option('loaders', type: 'array', - choices: ['', 'tvg', 'svg', 'png', 'jpg', 'webp_beta','all'], + choices: ['', 'tvg', 'svg', 'png', 'jpg', 'webp_beta', 'lottie_beta', 'all'], value: ['svg', 'tvg'], description: 'Enable File Loaders in thorvg ("all" does not include "*_beta".)') diff --git a/src/loaders/lottie/meson.build b/src/loaders/lottie/meson.build new file mode 100644 index 00000000..b87a694c --- /dev/null +++ b/src/loaders/lottie/meson.build @@ -0,0 +1,9 @@ +source_file = [ + 'tvgLottieLoader.h', + 'tvgLottieLoader.cpp', +] + +subloader_dep += [declare_dependency( + include_directories : include_directories('.'), + sources : source_file +)] diff --git a/src/loaders/lottie/tvgLottieLoader.cpp b/src/loaders/lottie/tvgLottieLoader.cpp new file mode 100644 index 00000000..bfe1494b --- /dev/null +++ b/src/loaders/lottie/tvgLottieLoader.cpp @@ -0,0 +1,294 @@ +/* + * 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 "tvgLoader.h" +#include "tvgLottieLoader.h" + +/************************************************************************/ +/* Internal Class Implementation */ +/************************************************************************/ + +static bool _checkDotLottie(const char *str) +{ + //check the .Lottie signature. + if (str[0] == 0x50 && str[1] == 0x4B && str[2] == 0x03 && str[3] == 0x04) return true; + else return false; +} + + +static int _str2int(const char* str, int len) +{ + int ret = 0; + for(int i = 0; i < len; ++i) { + ret = ret * 10 + (str[i] - '0'); + } + return ret; +} + + +static int _str2float(const char* str, int len) +{ + //strndup() + auto tmp = (char*)malloc(len + 1); + if (!tmp) return 0; + tmp[len] = '\0'; + memcpy(tmp, str, len); + + auto ret = strtof(tmp, nullptr); + free(tmp); + return lround(ret); +} + + +void LottieLoader::clear() +{ + //TODO: Clear all used resources + if (copy) free((char*)content); + size = 0; + content = nullptr; + copy = false; +} + + +/************************************************************************/ +/* External Class Implementation */ +/************************************************************************/ + +LottieLoader::LottieLoader() +{ +} + + +LottieLoader::~LottieLoader() +{ + close(); +} + + +void LottieLoader::run(unsigned tid) +{ + /* TODO: Compose current frame of Lottie Scene tree + The result should be assigned to "this->root" */ +} + + +bool LottieLoader::header() +{ + //Quickly validate the given Lottie file without parsing in order to get the animation info. + auto p = content; + + uint32_t depth = 0; + + while (*p != '\0') { + if (*p == '{') { + ++depth; + ++p; + continue; + } + if (*p == '}') { + --depth; + ++p; + continue; + } + if (depth != 1) { + ++p; + continue; + } + //version. + if (!strncmp(p, "\"v\":", 4)) { + p += 4; + continue; + } + //framerate + if (!strncmp(p, "\"fr\":", 5)) { + p += 5; + auto e = strstr(p, ","); + if (!e) e = strstr(p, "}"); + frameRate = _str2float(p, e - p); + p = e; + continue; + } + //width + if (!strncmp(p, "\"w\":", 4)) { + p += 4; + auto e = strstr(p, ","); + if (!e) e = strstr(p, "}"); + w = static_cast(_str2int(p, e - p)); + p = e; + continue; + } + //height + if (!strncmp(p, "\"h\":", 4)) { + p += 4; + auto e = strstr(p, ","); + if (!e) e = strstr(p, "}"); + h = static_cast(_str2int(p, e - p)); + p = e; + continue; + } + ++p; + } + TVGLOG("LOTTIE", "info: fr = %d, size = %d x %d", frameRate, (int)w, (int)h); + + return true; +} + + +bool LottieLoader::open(const char* data, uint32_t size, bool copy) +{ + clear(); + + //If the format is dotLottie + auto dotLottie = _checkDotLottie(data); + if (dotLottie) { + TVGLOG("LOTTIE", "Requested .Lottie Format, Not Supported yet."); + return false; + } + + if (copy) { + content = (char*)malloc(size); + if (!content) return false; + memcpy((char*)content, data, size); + } else content = data; + + this->size = size; + this->copy = copy; + + return header(); +} + + +bool LottieLoader::open(const string& path) +{ + clear(); + + auto f = fopen(path.c_str(), "r"); + if (!f) return false; + + fseek(f, 0, SEEK_END); + + size = ftell(f); + if (size == 0) { + fclose(f); + return false; + } + + auto content = (char*)(malloc(sizeof(char) * size + 1)); + fseek(f, 0, SEEK_SET); + auto ret = fread(content, sizeof(char), size, f); + if (ret < size) { + fclose(f); + return false; + } + content[size] = '\0'; + + fclose(f); + + //If the format is dotLottie + auto dotLottie = _checkDotLottie(content); + if (dotLottie) { + TVGLOG("LOTTIE", "Requested .Lottie Format, Not Supported yet."); + return false; + } + + this->content = content; + this->copy = true; + + return header(); +} + + +bool LottieLoader::resize(Paint* paint, float w, float h) +{ + if (!paint) return false; + + auto sx = w / this->w; + auto sy = h / this->h; + Matrix m = {sx, 0, 0, 0, sy, 0, 0, 0, 1}; + paint->transform(m); + + return true; +} + + +bool LottieLoader::read() +{ + if (!content || size == 0) return false; + + //the loading has been already completed in header() + if (root) return true; + + TaskScheduler::request(this); + + return true; +} + + +bool LottieLoader::close() +{ + this->done(); + + clear(); + + return true; +} + + +unique_ptr LottieLoader::paint() +{ + this->done(); + + return std::move(root); +} + + +bool LottieLoader::frame(uint32_t frameNo) +{ + this->done(); + + return true; +} + + +uint32_t LottieLoader::totalFrame() +{ + this->done(); + + return 0; +} + + +uint32_t LottieLoader::curFrame() +{ + this->done(); + + return frameNo; +} + + +float LottieLoader::duration() +{ + this->done(); + + return 0; +} \ No newline at end of file diff --git a/src/loaders/lottie/tvgLottieLoader.h b/src/loaders/lottie/tvgLottieLoader.h index 21d06317..e5e22d18 100644 --- a/src/loaders/lottie/tvgLottieLoader.h +++ b/src/loaders/lottie/tvgLottieLoader.h @@ -27,12 +27,13 @@ #include "tvgFrameModule.h" #include "tvgTaskScheduler.h" -class LottieLoader : public LoadModule, public FrameModule, public Task +class LottieLoader : public FrameModule, public Task { public: - string filePath; //lottie file path const char* content = nullptr; //lottie file data uint32_t size = 0; //lottie data size + uint32_t frameRate; + uint32_t frameNo = 0; //current frame number unique_ptr root; //current motion frame @@ -50,13 +51,11 @@ public: bool close() override; unique_ptr paint() override; - bool animatable() override { return true; } - //Frame Controls bool frame(uint32_t frameNo) override; uint32_t totalFrame() override; uint32_t curFrame() override; - double duration() override; + float duration() override; private: bool header(); diff --git a/src/loaders/meson.build b/src/loaders/meson.build index d4ce8adb..deebd369 100644 --- a/src/loaders/meson.build +++ b/src/loaders/meson.build @@ -8,6 +8,10 @@ if all_loaders or get_option('loaders').contains('svg') == true subdir('svg') endif +if get_option('loaders').contains('lottie_beta') == true + subdir('lottie') +endif + if all_loaders or get_option('loaders').contains('png') == true if get_option('static') == true subdir('png') diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index b6bfdf73..6fe94c19 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -3682,6 +3682,5 @@ bool SvgLoader::close() unique_ptr SvgLoader::paint() { this->done(); - if (root) return std::move(root); - else return nullptr; + return std::move(root); } diff --git a/src/loaders/tvg/tvgTvgLoader.cpp b/src/loaders/tvg/tvgTvgLoader.cpp index 123ce4ff..8db452d5 100644 --- a/src/loaders/tvg/tvgTvgLoader.cpp +++ b/src/loaders/tvg/tvgTvgLoader.cpp @@ -228,6 +228,5 @@ void TvgLoader::run(unsigned tid) unique_ptr TvgLoader::paint() { this->done(); - if (root) return std::move(root); - return nullptr; + return std::move(root); }