File indexing completed on 2025-01-05 04:01:16
0001 /* 0002 * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include "app/log/log.hpp" 0010 0011 #include "model/shapes/group.hpp" 0012 #include "model/shapes/layer.hpp" 0013 #include "model/shapes/precomp_layer.hpp" 0014 #include "model/shapes/rect.hpp" 0015 #include "model/shapes/ellipse.hpp" 0016 #include "model/shapes/path.hpp" 0017 #include "model/shapes/polystar.hpp" 0018 #include "model/shapes/fill.hpp" 0019 #include "model/shapes/stroke.hpp" 0020 #include "model/shapes/image.hpp" 0021 #include "model/shapes/text.hpp" 0022 #include "model/shapes/repeater.hpp" 0023 0024 #include "lottie_format.hpp" 0025 0026 namespace glaxnimate::io::lottie::detail { 0027 0028 class ValueTransform 0029 { 0030 public: 0031 virtual ~ValueTransform() {} 0032 0033 virtual QVariant to_lottie(const QVariant& v, model::FrameTime) const = 0; 0034 virtual QVariant from_lottie(const QVariant& v, model::FrameTime) const = 0; 0035 }; 0036 0037 class FloatMult : public ValueTransform 0038 { 0039 public: 0040 explicit FloatMult(float factor) : factor(factor) {} 0041 0042 QVariant to_lottie(const QVariant& v, model::FrameTime) const override 0043 { 0044 return v.toFloat() * factor; 0045 } 0046 0047 QVariant from_lottie(const QVariant& v, model::FrameTime) const override 0048 { 0049 return v.toFloat() / factor; 0050 } 0051 private: 0052 float factor; 0053 }; 0054 0055 class EnumMap : public ValueTransform 0056 { 0057 public: 0058 EnumMap(QMap<int, int> values) : values(std::move(values)) {} 0059 0060 QVariant to_lottie(const QVariant& v, model::FrameTime) const override 0061 { 0062 return values[v.toInt()]; 0063 } 0064 0065 QVariant from_lottie(const QVariant& v, model::FrameTime) const override 0066 { 0067 return values.key(v.toInt()); 0068 } 0069 0070 QMap<int, int> values; 0071 }; 0072 0073 class IntBool : public ValueTransform 0074 { 0075 public: 0076 QVariant to_lottie(const QVariant& v, model::FrameTime) const override 0077 { 0078 return int(v.toBool()); 0079 } 0080 0081 QVariant from_lottie(const QVariant& v, model::FrameTime) const override 0082 { 0083 return bool(v.toInt()); 0084 } 0085 }; 0086 0087 class GradientLoad : public ValueTransform 0088 { 0089 public: 0090 GradientLoad(int count) : count(count) {} 0091 0092 QVariant to_lottie(const QVariant&, model::FrameTime) const override { return {}; } 0093 0094 QVariant from_lottie(const QVariant& v, model::FrameTime) const override 0095 { 0096 auto vlist = v.toList(); 0097 if ( vlist.size() < count * 4 ) 0098 return {}; 0099 0100 QGradientStops s; 0101 s.reserve(count); 0102 bool alpha = vlist.size() >= count * 6; 0103 0104 for ( int i = 0; i < count; i++ ) 0105 { 0106 s.push_back({ 0107 vlist[i*4].toDouble(), 0108 QColor::fromRgbF( 0109 vlist[i*4+1].toDouble(), 0110 vlist[i*4+2].toDouble(), 0111 vlist[i*4+3].toDouble(), 0112 alpha ? vlist[count*4+2*i+1].toDouble() : 1 0113 ) 0114 }); 0115 } 0116 0117 return QVariant::fromValue(s); 0118 } 0119 0120 int count = 0; 0121 }; 0122 0123 0124 class TransformFunc 0125 { 0126 public: 0127 template<class T, class = std::enable_if_t<std::is_base_of_v<ValueTransform, T>>> 0128 TransformFunc(const T& t) : trans(std::make_shared<T>(t)) {} 0129 0130 TransformFunc() {} 0131 TransformFunc(TransformFunc&&) = default; 0132 TransformFunc(const TransformFunc&) = default; 0133 0134 QVariant to_lottie(const QVariant& v, model::FrameTime t) const 0135 { 0136 if ( !trans ) 0137 return v; 0138 return trans->to_lottie(v, t); 0139 } 0140 0141 QVariant from_lottie(const QVariant& v, model::FrameTime t) const 0142 { 0143 if ( !trans ) 0144 return v; 0145 return trans->from_lottie(v, t); 0146 } 0147 0148 private: 0149 std::shared_ptr<ValueTransform> trans; 0150 }; 0151 0152 enum FieldMode 0153 { 0154 Auto, 0155 AnimatedToStatic, 0156 Ignored, 0157 Custom 0158 }; 0159 0160 struct FieldInfo 0161 { 0162 QString name; 0163 QString lottie; 0164 bool essential; 0165 FieldMode mode; 0166 TransformFunc transform; 0167 0168 FieldInfo(const char* lottie, const char* name, TransformFunc transform = {}, bool essential = true) 0169 : name(name), lottie(lottie), essential(essential), mode(Auto), transform(std::move(transform)) 0170 {} 0171 0172 FieldInfo(const char* lottie, FieldMode mode = Ignored) 0173 : lottie(lottie), essential(false), mode(mode) 0174 {} 0175 0176 FieldInfo(const char* lottie, const char* name, FieldMode mode, bool essential = true) 0177 : name(name), lottie(lottie), essential(essential), mode(mode) 0178 {} 0179 }; 0180 0181 // static mapping data 0182 const QMap<QString, QVector<FieldInfo>> fields = { 0183 {"DocumentNode", { 0184 FieldInfo{"nm", "name", {}, false}, 0185 FieldInfo{"mn", "uuid", {}, false}, 0186 }}, 0187 {"Composition", { 0188 FieldInfo("layers", Custom), 0189 FieldInfo("id", Custom), 0190 FieldInfo{"op", Custom}, 0191 FieldInfo{"ip", Custom}, 0192 FieldInfo("v", Custom), 0193 FieldInfo{"fr", "fps"}, 0194 FieldInfo{"w", "width"}, 0195 FieldInfo{"h", "height"}, 0196 FieldInfo("ddd"), 0197 FieldInfo("assets"), 0198 FieldInfo("comps"), 0199 FieldInfo("fonts"), 0200 FieldInfo("chars"), 0201 FieldInfo("markers"), 0202 FieldInfo("motion_blur"), 0203 FieldInfo("tgs"), 0204 FieldInfo("meta", Custom), 0205 FieldInfo("props"), 0206 FieldInfo("slots"), 0207 }}, 0208 // Layer is converted explicitly 0209 {"__Layer__", { 0210 FieldInfo{"op", Custom}, 0211 FieldInfo{"ip", Custom}, 0212 FieldInfo("ddd"), 0213 FieldInfo("hd", Custom), 0214 FieldInfo("ty", Custom), 0215 FieldInfo("parent", Custom), 0216 FieldInfo("sr"), 0217 FieldInfo("ks", Custom), 0218 FieldInfo("ao", "auto_orient", IntBool()), 0219 FieldInfo{"st", Custom}, 0220 FieldInfo("bm"), 0221 FieldInfo("tt"), 0222 FieldInfo("td"), 0223 FieldInfo("ind", Custom), 0224 FieldInfo("cl"), 0225 FieldInfo("ln"), 0226 FieldInfo("hasMasks", Custom), 0227 FieldInfo("masksProperties", Custom), 0228 FieldInfo("ef"), 0229 FieldInfo("bounds"), // old, no longer there 0230 FieldInfo("ct"), 0231 }}, 0232 {"Transform", { 0233 FieldInfo{"a", "anchor_point"}, 0234 FieldInfo("px", Custom), 0235 FieldInfo("py", Custom), 0236 FieldInfo("pz", Custom), 0237 FieldInfo{"p", "position"}, 0238 FieldInfo{"s", "scale"}, 0239 FieldInfo{"r", "rotation"}, 0240 FieldInfo("rx", Custom), 0241 FieldInfo("ry", Custom), 0242 FieldInfo("rz", Custom), 0243 FieldInfo("o"), 0244 FieldInfo("sk"), 0245 FieldInfo("sa"), 0246 FieldInfo("nm"), 0247 }}, 0248 {"ShapeElement", { 0249 FieldInfo{"ty", Custom}, 0250 FieldInfo{"ix"}, 0251 FieldInfo{"cix"}, 0252 FieldInfo{"bm"}, 0253 FieldInfo{"hd", Custom}, 0254 }}, 0255 {"Shape", { 0256 FieldInfo{"d", "reversed", EnumMap{{ 0257 {1, 3}, 0258 {0, 1}, 0259 }}}, 0260 FieldInfo{"closed", Custom}, // Old attribute 0261 }}, 0262 {"Rect", { 0263 FieldInfo{"p", "position"}, 0264 FieldInfo{"s", "size"}, 0265 FieldInfo{"r", "rounded"}, 0266 }}, 0267 {"Ellipse", { 0268 FieldInfo{"p", "position"}, 0269 FieldInfo{"s", "size"}, 0270 }}, 0271 {"Path", { 0272 FieldInfo{"ks", "shape"}, 0273 FieldInfo{"ind"}, 0274 }}, 0275 {"PolyStar", { 0276 FieldInfo{"p", "position"}, 0277 FieldInfo{"or", "outer_radius"}, 0278 FieldInfo{"ir", "inner_radius"}, 0279 FieldInfo{"is", "inner_roundness", FloatMult(100)}, 0280 FieldInfo{"os", "outer_roundness", FloatMult(100)}, 0281 FieldInfo{"r", "angle"}, 0282 FieldInfo{"pt", "points"}, 0283 FieldInfo{"sy", "type"}, 0284 }}, 0285 {"Group", { 0286 FieldInfo{"np"}, 0287 FieldInfo{"it", Custom}, 0288 }}, 0289 {"Styler", { 0290 FieldInfo{"o", "opacity", FloatMult(100)}, 0291 FieldInfo{"c", Custom}, 0292 FieldInfo{"fillEnabled", Custom}, 0293 }}, 0294 {"Fill", { 0295 FieldInfo{"r", "fill_rule", EnumMap{{ 0296 {model::Fill::NonZero, 1}, 0297 {model::Fill::EvenOdd, 2}, 0298 }}}, 0299 }}, 0300 {"Stroke", { 0301 FieldInfo{"lc", "cap", EnumMap{{ 0302 {model::Stroke::ButtCap, 1}, 0303 {model::Stroke::RoundCap, 2}, 0304 {model::Stroke::SquareCap, 3}, 0305 }}}, 0306 FieldInfo{"lj", "join", EnumMap{{ 0307 {model::Stroke::MiterJoin, 1}, 0308 {model::Stroke::RoundJoin, 2}, 0309 {model::Stroke::BevelJoin, 3}, 0310 }}}, 0311 FieldInfo{"ml", "miter_limit"}, 0312 FieldInfo{"w", "width"}, 0313 FieldInfo{"d"}, 0314 }}, 0315 {"Bitmap", { 0316 FieldInfo{"h", "height"}, 0317 FieldInfo{"w", "width"}, 0318 FieldInfo{"id", Custom}, 0319 FieldInfo{"p", Custom}, 0320 FieldInfo{"u", Custom}, 0321 FieldInfo{"e", Custom}, 0322 }}, 0323 {"Gradient", { 0324 FieldInfo{"s", "start_point"}, 0325 FieldInfo{"e", "end_point"}, 0326 FieldInfo{"t", "type"}, 0327 FieldInfo{"h", Custom}, /// \todo 0328 FieldInfo{"a", Custom}, /// \todo 0329 FieldInfo{"g", Custom}, 0330 }}, 0331 {"PreCompLayer", { 0332 FieldInfo{"refId", Custom}, 0333 FieldInfo{"w", Custom}, 0334 FieldInfo{"h", Custom}, 0335 FieldInfo{"tm"}, 0336 }}, 0337 {"Repeater", { 0338 FieldInfo{"c", "copies"}, 0339 FieldInfo{"o"}, 0340 FieldInfo{"m"}, 0341 FieldInfo{"tr", Custom}, 0342 }}, 0343 {"Trim", { 0344 FieldInfo{"s", "start", FloatMult(100)}, 0345 FieldInfo{"e", "end", FloatMult(100)}, 0346 FieldInfo{"o", "offset", FloatMult(360)}, 0347 FieldInfo{"m", "multiple"}, 0348 }}, 0349 {"InflateDeflate", { 0350 FieldInfo{"a", "amount", FloatMult(100)}, 0351 }}, 0352 {"RoundCorners", { 0353 FieldInfo{"r", "radius"}, 0354 }}, 0355 {"OffsetPath", { 0356 FieldInfo{"a", "amount"}, 0357 FieldInfo{"lj", "join", EnumMap{{ 0358 {model::Stroke::MiterJoin, 1}, 0359 {model::Stroke::RoundJoin, 2}, 0360 {model::Stroke::BevelJoin, 3}, 0361 }}}, 0362 FieldInfo{"ml", "miter_limit"}, 0363 }}, 0364 {"ZigZag", { 0365 FieldInfo{"s", "amplitude"}, 0366 FieldInfo{"r", "frequency"}, 0367 FieldInfo{"pt", "style", AnimatedToStatic}, 0368 }}, 0369 }; 0370 const QMap<QString, QString> shape_types = { 0371 {"Rect", "rc"}, 0372 {"PolyStar", "sr"}, 0373 {"Ellipse", "el"}, 0374 {"Path", "sh"}, 0375 {"Group", "gr"}, 0376 {"Layer", "gr"}, 0377 {"Fill", "fl"}, 0378 {"Stroke", "st"}, 0379 // "gf" (Gradient Fill) and "gs" (Gradient Stroke) are handled by fill/stroke 0380 // "tr" is not a shape but a property of groups 0381 // "mm" (Merge), "tw" (Twist), are not supported by lottie 0382 {"Trim", "tm"}, 0383 {"Repeater", "rp"}, 0384 {"RoundCorners", "rd"}, 0385 {"InflateDeflate", "pb"}, 0386 {"OffsetPath", "op"}, 0387 {"ZigZag", "zz"}, 0388 }; 0389 0390 const QMap<QString, QString> shape_types_repeat = { 0391 {"gf", "Fill"}, 0392 {"gs", "Stroke"}, 0393 }; 0394 0395 const QMap<int, QString> unsupported_layers = { 0396 {6, "Audio"}, 0397 {7, "Pholder Video"}, 0398 {8, "Image Sequence"}, 0399 {9, "Video"}, 0400 }; 0401 0402 } // namespace glaxnimate::io::lottie::detail