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 }