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 #include "tgs_format.hpp" 0008 0009 #include <set> 0010 0011 #include <KCompressionDevice> 0012 0013 #include "cbor_write_json.hpp" 0014 #include "model/shapes/polystar.hpp" 0015 #include "model/shapes/image.hpp" 0016 #include "model/shapes/stroke.hpp" 0017 #include "model/shapes/repeater.hpp" 0018 #include "model/shapes/inflate_deflate.hpp" 0019 #include "model/shapes/offset_path.hpp" 0020 #include "model/shapes/zig_zag.hpp" 0021 #include "validation.hpp" 0022 0023 0024 using namespace glaxnimate; 0025 using namespace glaxnimate::io::lottie; 0026 0027 namespace { 0028 0029 class TgsVisitor : public ValidationVisitor 0030 { 0031 0032 public: 0033 explicit TgsVisitor(LottieFormat* fmt) 0034 : ValidationVisitor(fmt) 0035 { 0036 allowed_fps.push_back(30); 0037 allowed_fps.push_back(60); 0038 fixed_size = QSize(512, 512); 0039 max_frames = 180; 0040 } 0041 0042 private: 0043 void on_visit(model::DocumentNode * node) override 0044 { 0045 if ( qobject_cast<model::PolyStar*>(node) ) 0046 { 0047 show_error(node, i18n("Star Shapes are not officially supported"), app::log::Info); 0048 } 0049 else if ( qobject_cast<model::Image*>(node) || qobject_cast<model::Bitmap*>(node) ) 0050 { 0051 show_error(node, i18n("Images are not supported"), app::log::Error); 0052 } 0053 else if ( auto st = qobject_cast<model::Stroke*>(node) ) 0054 { 0055 if ( qobject_cast<model::Gradient*>(st->use.get()) ) 0056 show_error(node, i18n("Gradient strokes are not officially supported"), app::log::Info); 0057 } 0058 else if ( auto layer = qobject_cast<model::Layer*>(node) ) 0059 { 0060 if ( layer->mask->has_mask() ) 0061 show_error(node, i18n("Masks are not supported"), app::log::Error); 0062 } 0063 else if ( qobject_cast<model::Repeater*>(node) ) 0064 { 0065 show_error(node, i18n("Repeaters are not officially supported"), app::log::Info); 0066 } 0067 else if ( qobject_cast<model::InflateDeflate*>(node) ) 0068 { 0069 show_error(node, i18n("Inflate/Deflate is not supported"), app::log::Warning); 0070 } 0071 else if ( qobject_cast<model::OffsetPath*>(node) ) 0072 { 0073 show_error(node, i18n("Offset Path is not supported"), app::log::Warning); 0074 } 0075 else if ( qobject_cast<model::ZigZag*>(node) ) 0076 { 0077 show_error(node, i18n("ZigZag is not supported"), app::log::Warning); 0078 } 0079 } 0080 }; 0081 0082 } // namespace 0083 0084 bool glaxnimate::io::lottie::TgsFormat::on_open(QIODevice& file, const QString&, model::Document* document, const QVariantMap&) 0085 { 0086 KCompressionDevice compressed(&file, false, KCompressionDevice::GZip); 0087 compressed.open(QIODevice::ReadOnly); 0088 QByteArray json = compressed.readAll(); 0089 return load_json(json, document); 0090 } 0091 0092 bool glaxnimate::io::lottie::TgsFormat::on_save(QIODevice& file, const QString&, model::Composition* comp, const QVariantMap&) 0093 { 0094 validate(comp->document(), comp); 0095 0096 QCborMap json = LottieFormat::to_json(comp, true, true); 0097 json[QLatin1String("tgs")] = 1; 0098 QByteArray data = cbor_write_json(json, true); 0099 0100 { 0101 KCompressionDevice compressed(&file, false, KCompressionDevice::GZip); 0102 compressed.open(QIODevice::WriteOnly); 0103 compressed.write(data); 0104 } 0105 0106 quint32 compressed_size = file.pos(); 0107 0108 qreal size_k = compressed_size / 1024.0; 0109 if ( size_k > 64 ) 0110 error(i18n("File too large: %1k, should be under 64k", size_k)); 0111 0112 return true; 0113 } 0114 0115 0116 void glaxnimate::io::lottie::TgsFormat::validate(model::Document* document, model::Composition* comp) 0117 { 0118 TgsVisitor(this).visit(document, comp); 0119 } 0120 0121 0122 glaxnimate::io::Autoreg<glaxnimate::io::lottie::TgsFormat> glaxnimate::io::lottie::TgsFormat::autoreg = {};