File indexing completed on 2024-05-26 04:33:12

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include <KoTosContainer_p.h>
0008 
0009 #include "ImageShape.h"
0010 #include "kis_debug.h"
0011 
0012 #include <QPainter>
0013 #include <SvgLoadingContext.h>
0014 #include <SvgSavingContext.h>
0015 #include <SvgUtil.h>
0016 #include <QFileInfo>
0017 #include <QBuffer>
0018 #include <KisMimeDatabase.h>
0019 #include <KoXmlWriter.h>
0020 #include "kis_dom_utils.h"
0021 #include <QRegularExpression>
0022 #include "KisQPainterStateSaver.h"
0023 
0024 
0025 struct Q_DECL_HIDDEN ImageShape::Private : public QSharedData
0026 {
0027     Private() {}
0028     Private(const Private &rhs)
0029         : QSharedData(),
0030           image(rhs.image),
0031           ratioParser(rhs.ratioParser ? new SvgUtil::PreserveAspectRatioParser(*rhs.ratioParser) : 0),
0032           viewBoxTransform(rhs.viewBoxTransform)
0033     {
0034     }
0035 
0036     QImage image;
0037     QScopedPointer<SvgUtil::PreserveAspectRatioParser> ratioParser;
0038     QTransform viewBoxTransform;
0039 };
0040 
0041 
0042 ImageShape::ImageShape()
0043     : m_d(new Private)
0044 {
0045 }
0046 
0047 ImageShape::ImageShape(const ImageShape &rhs)
0048     : KoTosContainer(rhs),
0049       m_d(rhs.m_d)
0050 {
0051 }
0052 
0053 ImageShape::~ImageShape()
0054 {
0055 }
0056 
0057 KoShape *ImageShape::cloneShape() const
0058 {
0059     return new ImageShape(*this);
0060 }
0061 
0062 void ImageShape::paint(QPainter &painter) const
0063 {
0064     KisQPainterStateSaver saver(&painter);
0065 
0066     const QRectF myrect(QPointF(), size());
0067 
0068     painter.setRenderHint(QPainter::SmoothPixmapTransform);
0069     painter.setClipRect(QRectF(QPointF(), size()), Qt::IntersectClip);
0070     painter.setTransform(m_d->viewBoxTransform, true);
0071     painter.drawImage(QPoint(), m_d->image);
0072 }
0073 
0074 void ImageShape::setSize(const QSizeF &size)
0075 {
0076     KoTosContainer::setSize(size);
0077 }
0078 
0079 bool ImageShape::saveSvg(SvgSavingContext &context)
0080 {
0081     const QString uid = context.createUID("image");
0082 
0083     context.shapeWriter().startElement("image");
0084     context.shapeWriter().addAttribute("id", uid);
0085     SvgUtil::writeTransformAttributeLazy("transform", transformation(), context.shapeWriter());
0086     context.shapeWriter().addAttribute("width", QString("%1px").arg(KisDomUtils::toString(size().width())));
0087     context.shapeWriter().addAttribute("height", QString("%1px").arg(KisDomUtils::toString(size().height())));
0088 
0089     QString aspectString = m_d->ratioParser->toString();
0090     if (!aspectString.isEmpty()) {
0091         context.shapeWriter().addAttribute("preserveAspectRatio", aspectString);
0092     }
0093 
0094     QBuffer buffer;
0095     buffer.open(QIODevice::WriteOnly);
0096     if (m_d->image.save(&buffer, "PNG")) {
0097         const QString mimeType = KisMimeDatabase::mimeTypeForSuffix("*.png");
0098         context.shapeWriter().addAttribute("xlink:href", "data:"+ mimeType + ";base64," + buffer.data().toBase64());
0099     }
0100 
0101     context.shapeWriter().endElement(); // image
0102 
0103     return true;
0104 }
0105 
0106 bool ImageShape::loadSvg(const QDomElement &element, SvgLoadingContext &context)
0107 {
0108     const qreal x = SvgUtil::parseUnitX(context.currentGC(), element.attribute("x"));
0109     const qreal y = SvgUtil::parseUnitY(context.currentGC(), element.attribute("y"));
0110     const qreal w = SvgUtil::parseUnitX(context.currentGC(), element.attribute("width"));
0111     const qreal h = SvgUtil::parseUnitY(context.currentGC(), element.attribute("height"));
0112 
0113     setSize(QSizeF(w, h));
0114     setPosition(QPointF(x, y));
0115 
0116     if (w == 0.0 || h == 0.0) {
0117         setVisible(false);
0118     }
0119 
0120     QString fileName = element.attribute("xlink:href");
0121 
0122     QByteArray data;
0123 
0124     if (fileName.startsWith("data:")) {
0125 
0126         QRegularExpression re("data:(.+?);base64,(.+)");
0127         QRegularExpressionMatch match = re.match(fileName);
0128 
0129         data = match.captured(2).toLatin1();
0130         data = QByteArray::fromBase64(data);
0131     } else {
0132         data = context.fetchExternalFile(fileName);
0133     }
0134 
0135     if (!data.isEmpty()) {
0136         QBuffer buffer(&data);
0137         m_d->image.load(&buffer, "");
0138     }
0139 
0140     const QString aspectString = element.attribute("preserveAspectRatio", "xMidYMid meet");
0141     m_d->ratioParser.reset(new SvgUtil::PreserveAspectRatioParser(aspectString));
0142 
0143     if (!m_d->image.isNull()) {
0144 
0145         m_d->viewBoxTransform =
0146              QTransform::fromScale(w / m_d->image.width(), h / m_d->image.height());
0147 
0148         SvgUtil::parseAspectRatio(*m_d->ratioParser,
0149                                   QRectF(QPointF(), size()),
0150                                   QRect(QPoint(), m_d->image.size()),
0151                                   &m_d->viewBoxTransform);
0152     }
0153 
0154     if (m_d->ratioParser->defer) {
0155         // TODO:
0156     }
0157 
0158     return true;
0159 }