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 <QBuffer>
0010 #include <QImage>
0011 #include <QPainter>
0012 
0013 #include "io/mime/mime_serializer.hpp"
0014 #include "io/io_registry.hpp"
0015 #include "model/document.hpp"
0016 #include "model/shapes/image.hpp"
0017 #include "model/assets/assets.hpp"
0018 
0019 namespace glaxnimate::io::raster {
0020 
0021 class RasterMime : public io::mime::MimeSerializer
0022 {
0023 public:
0024     QString slug() const override { return "raster"; }
0025     QString name() const override { return i18n("Raster Image"); }
0026     QStringList mime_types() const override { return {"image/png"}; }
0027 
0028     QByteArray serialize(const std::vector<model::DocumentNode*>& selection) const override
0029     {
0030         QByteArray data;
0031         QBuffer buffer(&data);
0032         to_image(selection).save(&buffer, "PNG");
0033         return data;
0034     }
0035 
0036     bool can_deserialize() const override { return true; }
0037 
0038     void to_mime_data(QMimeData& mime, const std::vector<model::DocumentNode*>& objects) const override
0039     {
0040         mime.setImageData(to_image(objects));
0041     }
0042 
0043     static QImage to_image(const std::vector<model::DocumentNode*>& selection)
0044     {
0045         if ( selection.empty() )
0046             return {};
0047 
0048         std::vector<model::VisualNode*> visual_nodes;
0049         visual_nodes.reserve(selection.size());
0050         QRectF box;
0051 
0052         for ( auto node : selection )
0053         {
0054             if ( auto visual = node->cast<model::VisualNode>() )
0055             {
0056                 visual_nodes.push_back(visual);
0057                 box |= visual->local_bounding_rect(visual->time());
0058             }
0059         }
0060 
0061         QImage image(box.size().toSize(), QImage::Format_ARGB32);
0062         image.fill(Qt::transparent);
0063         QPainter painter(&image);
0064         painter.setRenderHint(QPainter::Antialiasing);
0065         painter.translate(-box.topLeft());
0066         for ( auto visual : visual_nodes )
0067         {
0068             visual->paint(&painter, visual->time(), model::VisualNode::Render);
0069         }
0070         return image;
0071     }
0072 
0073     static QImage frame_to_image(const model::VisualNode* node, model::FrameTime time)
0074     {
0075         if ( !node )
0076             return {};
0077 
0078         QImage image(node->local_bounding_rect(time).size().toSize(), QImage::Format_ARGB32);
0079         image.fill(Qt::transparent);
0080         QPainter painter(&image);
0081         painter.setRenderHint(QPainter::Antialiasing);
0082         node->paint(&painter, time, model::VisualNode::Render);
0083         return image;
0084     }
0085 
0086     io::mime::DeserializedData deserialize(const QByteArray& data) const override
0087     {
0088         io::mime::DeserializedData out;
0089         out.initialize_data();
0090         auto bmp = out.document->assets()->images->values.insert(std::make_unique<model::Bitmap>(out.document.get()));
0091         bmp->data.set(data);
0092         auto img = std::make_unique<model::Image>(out.document.get());
0093         img->image.set(bmp);
0094         QPointF p(bmp->pixmap().width() / 2.0, bmp->pixmap().height() / 2.0);
0095         img->transform->anchor_point.set(p);
0096         img->transform->position.set(p);
0097         out.main->shapes.insert(std::move(img));
0098         return out;
0099     }
0100 
0101 private:
0102     static Autoreg<RasterMime> autoreg;
0103 };
0104 
0105 } // namespace glaxnimate::io::mime
0106