Krita Source Code Documentation
Loading...
Searching...
No Matches
ImageShape.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7#include <KoTosContainer_p.h>
8
9#include "ImageShape.h"
10#include "kis_debug.h"
11
12#include <QPainter>
13#include <SvgLoadingContext.h>
14#include <SvgSavingContext.h>
15#include <SvgUtil.h>
16#include <SvgStyleWriter.h>
17#include <QBuffer>
18#include <KisMimeDatabase.h>
19#include <KoXmlWriter.h>
20#include "kis_dom_utils.h"
21#include <QRegularExpression>
23
24
25struct Q_DECL_HIDDEN ImageShape::Private : public QSharedData
26{
28 Private(const Private &rhs)
29 : QSharedData(),
30 image(rhs.image),
31 ratioParser(rhs.ratioParser ? new SvgUtil::PreserveAspectRatioParser(*rhs.ratioParser) : 0),
32 viewBoxTransform(rhs.viewBoxTransform)
33 {
34 }
35
36 QImage image;
37 QScopedPointer<SvgUtil::PreserveAspectRatioParser> ratioParser;
38 QTransform viewBoxTransform;
39};
40
41
43 : m_d(new Private)
44{
45}
46
48 : KoTosContainer(rhs),
49 m_d(rhs.m_d)
50{
51}
52
56
58{
59 return new ImageShape(*this);
60}
61
62void ImageShape::paint(QPainter &painter) const
63{
64 KisQPainterStateSaver saver(&painter);
65
66 const QRectF myrect(QPointF(), size());
67
68 painter.setRenderHint(QPainter::SmoothPixmapTransform);
69 painter.setClipRect(QRectF(QPointF(), size()), Qt::IntersectClip);
70 painter.setTransform(m_d->viewBoxTransform, true);
71 painter.drawImage(QPoint(), m_d->image);
72}
73
74void ImageShape::setSize(const QSizeF &size)
75{
77}
78
80{
81 const QString uid = context.createUID("image");
82
83 context.shapeWriter().startElement("image");
84 context.shapeWriter().addAttribute("id", uid);
86 context.shapeWriter().addAttribute("width", QString("%1px").arg(KisDomUtils::toString(size().width())));
87 context.shapeWriter().addAttribute("height", QString("%1px").arg(KisDomUtils::toString(size().height())));
88
89 QString aspectString = m_d->ratioParser? m_d->ratioParser->toString(): QString();
90 if (!aspectString.isEmpty()) {
91 context.shapeWriter().addAttribute("preserveAspectRatio", aspectString);
92 }
93
94 QBuffer buffer;
95 buffer.open(QIODevice::WriteOnly);
96 if (m_d->image.save(&buffer, "PNG")) {
97 const QString mimeType = KisMimeDatabase::mimeTypeForSuffix("*.png");
98 context.shapeWriter().addAttribute("xlink:href", "data:"+ mimeType + ";base64," + buffer.data().toBase64());
99 }
100 SvgStyleWriter::saveMetadata(this, context);
101
102 context.shapeWriter().endElement(); // image
103
104 return true;
105}
106
107bool ImageShape::loadSvg(const QDomElement &element, SvgLoadingContext &context)
108{
109 const qreal x = SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), element.attribute("x"));
110 const qreal y = SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), element.attribute("y"));
111 const qreal w = SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), element.attribute("width"));
112 const qreal h = SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), element.attribute("height"));
113
114 setSize(QSizeF(w, h));
115 setPosition(QPointF(x, y));
116
117 if (w == 0.0 || h == 0.0) {
118 setVisible(false);
119 }
120
121 QString fileName = element.attribute("xlink:href");
122
123 QByteArray data;
124
125 if (fileName.startsWith("data:")) {
126
127 QRegularExpression re("data:(.+?);base64,(.+)");
128 QRegularExpressionMatch match = re.match(fileName);
129
130 data = match.captured(2).toLatin1();
131 data = QByteArray::fromBase64(data);
132 } else {
133 data = context.fetchExternalFile(fileName);
134 }
135
136 if (!data.isEmpty()) {
137 QBuffer buffer(&data);
138 m_d->image.load(&buffer, "");
139 }
140
141 const QString aspectString = element.attribute("preserveAspectRatio", "xMidYMid meet");
142 m_d->ratioParser.reset(new SvgUtil::PreserveAspectRatioParser(aspectString));
143
144 if (!m_d->image.isNull()) {
145
146 m_d->viewBoxTransform =
147 QTransform::fromScale(w / m_d->image.width(), h / m_d->image.height());
148
149 SvgUtil::parseAspectRatio(*m_d->ratioParser,
150 QRectF(QPointF(), size()),
151 QRect(QPoint(), m_d->image.size()),
152 &m_d->viewBoxTransform);
153 }
154
155 if (m_d->ratioParser->defer) {
156 // TODO:
157 }
158
159 return true;
160}
161
162void ImageShape::setImage(const QImage &img)
163{
164 if (m_d->image != img) {
165 m_d->image = img;
167 }
168}
169
170QImage ImageShape::image() const
171{
172 return m_d->image;
173}
174
175void ImageShape::setViewBoxTransform(const QTransform &tf)
176{
177 if (m_d->viewBoxTransform != tf) {
178 m_d->viewBoxTransform = tf;
180 }
181}
182
183QTransform ImageShape::viewBoxTransform() const
184{
185 return m_d->viewBoxTransform;
186}
static QString mimeTypeForSuffix(const QString &suffix)
Find the mimetype for a given extension. The extension may have the form "*.xxx" or "xxx".
virtual QSizeF size() const
Get the size of the shape in pt.
Definition KoShape.cpp:820
@ ContentChanged
the content of the shape changed e.g. a new image inside a pixmap/text change inside a textshape
Definition KoShape.h:110
@ GenericMatrixChange
used after the matrix was changed without knowing which property explicitly changed
Definition KoShape.h:101
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:424
virtual void setPosition(const QPointF &position)
Set the position of the shape in pt.
Definition KoShape.cpp:295
void setVisible(bool on)
Definition KoShape.cpp:972
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:276
void shapeChanged(ChangeType type, KoShape *shape=0) override
Contains data used for loading svg.
QByteArray fetchExternalFile(const QString &url)
SvgGraphicsContext * currentGC() const
Returns the current graphics context.
KoSvgTextProperties resolvedProperties() const
These are the text properties, completely resolved, ensuring that everything is inherited and the siz...
Context for saving svg files.
QString createUID(const QString &base)
Create a unique id from the specified base text.
QScopedPointer< KoXmlWriter > shapeWriter
static void saveMetadata(const KoShape *shape, SvgSavingContext &context)
static qreal parseUnitX(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in x-direction
Definition SvgUtil.cpp:304
static void parseAspectRatio(const PreserveAspectRatioParser &p, const QRectF &elementBounds, const QRectF &viewRect, QTransform *_viewTransform)
Definition SvgUtil.cpp:190
static void writeTransformAttributeLazy(const QString &name, const QTransform &transform, KoXmlWriter &shapeWriter)
Writes a transform as an attribute name iff the transform is not empty.
Definition SvgUtil.cpp:124
static qreal parseUnitY(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in y-direction
Definition SvgUtil.cpp:313
QString toString(const QString &value)
QTransform viewBoxTransform
void setImage(const QImage &img)
QImage image
void setViewBoxTransform(const QTransform &tf)
void setSize(const QSizeF &size) override
Resize the shape.
bool loadSvg(const QDomElement &element, SvgLoadingContext &context) override
Loads data from specified svg element.
bool saveSvg(SvgSavingContext &context) override
Saves data utilizing specified svg saving context.
void paint(QPainter &painter) const override
Paint the shape fill The class extending this one is responsible for painting itself....
~ImageShape() override
Private(const Private &rhs)
KoShape * cloneShape() const override
creates a deep copy of the shape or shape's subtree
QScopedPointer< SvgUtil::PreserveAspectRatioParser > ratioParser
QSharedDataPointer< Private > m_d
Definition ImageShape.h:44