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 = {};