1 /*
2  * Copyright (c) 2021 - 2024 the ThorVG project. All rights reserved.
3 
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10 
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13 
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
23 #include "../../lv_conf_internal.h"
24 #if LV_USE_THORVG_INTERNAL
25 
26 #include "tvgCommon.h"
27 #include "tvgSaveModule.h"
28 #include "tvgPaint.h"
29 
30 #ifdef THORVG_TVG_SAVER_SUPPORT
31     #include "tvgTvgSaver.h"
32 #endif
33 #ifdef THORVG_GIF_SAVER_SUPPORT
34     #include "tvgGifSaver.h"
35 #endif
36 
37 /************************************************************************/
38 /* Internal Class Implementation                                        */
39 /************************************************************************/
40 
41 struct Saver::Impl
42 {
43     SaveModule* saveModule = nullptr;
44     Paint* bg = nullptr;
45 
~ImplSaver::Impl46     ~Impl()
47     {
48         delete(saveModule);
49         delete(bg);
50     }
51 };
52 
53 
_find(FileType type)54 static SaveModule* _find(FileType type)
55 {
56     switch(type) {
57         case FileType::Tvg: {
58 #ifdef THORVG_TVG_SAVER_SUPPORT
59             return new TvgSaver;
60 #endif
61             break;
62         }
63         case FileType::Gif: {
64 #ifdef THORVG_GIF_SAVER_SUPPORT
65             return new GifSaver;
66 #endif
67             break;
68         }
69         default: {
70             break;
71         }
72     }
73 
74 #ifdef THORVG_LOG_ENABLED
75     const char *format;
76     switch(type) {
77         case FileType::Tvg: {
78             format = "TVG";
79             break;
80         }
81         case FileType::Gif: {
82             format = "GIF";
83             break;
84         }
85         default: {
86             format = "???";
87             break;
88         }
89     }
90     TVGLOG("RENDERER", "%s format is not supported", format);
91 #endif
92     return nullptr;
93 }
94 
95 
_find(const string & path)96 static SaveModule* _find(const string& path)
97 {
98     auto ext = path.substr(path.find_last_of(".") + 1);
99     if (!ext.compare("tvg")) {
100         return _find(FileType::Tvg);
101     } else if (!ext.compare("gif")) {
102         return _find(FileType::Gif);
103     }
104     return nullptr;
105 }
106 
107 
108 /************************************************************************/
109 /* External Class Implementation                                        */
110 /************************************************************************/
111 
Saver()112 Saver::Saver() : pImpl(new Impl())
113 {
114 }
115 
116 
~Saver()117 Saver::~Saver()
118 {
119     delete(pImpl);
120 }
121 
122 
save(std::unique_ptr<Paint> paint,const string & path,bool compress)123 Result Saver::save(std::unique_ptr<Paint> paint, const string& path, bool compress) noexcept
124 {
125     auto p = paint.release();
126     if (!p) return Result::MemoryCorruption;
127 
128     //Already on saving another resource.
129     if (pImpl->saveModule) {
130         if (P(p)->refCnt == 0) delete(p);
131         return Result::InsufficientCondition;
132     }
133 
134     if (auto saveModule = _find(path)) {
135         if (saveModule->save(p, path, compress)) {
136             pImpl->saveModule = saveModule;
137             return Result::Success;
138         } else {
139             if (P(p)->refCnt == 0) delete(p);
140             delete(saveModule);
141             return Result::Unknown;
142         }
143     }
144     if (P(p)->refCnt == 0) delete(p);
145     return Result::NonSupport;
146 }
147 
148 
background(unique_ptr<Paint> paint)149 Result Saver::background(unique_ptr<Paint> paint) noexcept
150 {
151     delete(pImpl->bg);
152     pImpl->bg = paint.release();
153 
154     return Result::Success;
155 }
156 
157 
save(unique_ptr<Animation> animation,const string & path,uint32_t quality,uint32_t fps)158 Result Saver::save(unique_ptr<Animation> animation, const string& path, uint32_t quality, uint32_t fps) noexcept
159 {
160     auto a = animation.release();
161     if (!a) return Result::MemoryCorruption;
162 
163     //animation holds the picture, it must be 1 at the bottom.
164     auto remove = PP(a->picture())->refCnt <= 1 ? true : false;
165 
166     if (tvg::zero(a->totalFrame())) {
167         if (remove) delete(a);
168         return Result::InsufficientCondition;
169     }
170 
171     //Already on saving another resource.
172     if (pImpl->saveModule) {
173         if (remove) delete(a);
174         return Result::InsufficientCondition;
175     }
176 
177     if (auto saveModule = _find(path)) {
178         if (saveModule->save(a, pImpl->bg, path, quality, fps)) {
179             pImpl->saveModule = saveModule;
180             return Result::Success;
181         } else {
182             if (remove) delete(a);
183             delete(saveModule);
184             return Result::Unknown;
185         }
186     }
187     if (remove) delete(a);
188     return Result::NonSupport;
189 }
190 
191 
sync()192 Result Saver::sync() noexcept
193 {
194     if (!pImpl->saveModule) return Result::InsufficientCondition;
195     pImpl->saveModule->close();
196     delete(pImpl->saveModule);
197     pImpl->saveModule = nullptr;
198 
199     return Result::Success;
200 }
201 
202 
gen()203 unique_ptr<Saver> Saver::gen() noexcept
204 {
205     return unique_ptr<Saver>(new Saver);
206 }
207 
208 #endif /* LV_USE_THORVG_INTERNAL */
209 
210