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 "ImageShape.h"
8#include "kis_debug.h"
9
10#include <QPainter>
11#include <SvgLoadingContext.h>
12#include <SvgSavingContext.h>
13#include <SvgUtil.h>
14#include <SvgStyleWriter.h>
15#include <QBuffer>
16#include <KisMimeDatabase.h>
17#include <KoXmlWriter.h>
18#include "kis_dom_utils.h"
19#include <QRegularExpression>
21
22
23struct Q_DECL_HIDDEN ImageShape::Private : public QSharedData
24{
26 Private(const Private &rhs)
27 : QSharedData(),
28 image(rhs.image),
29 ratioParser(rhs.ratioParser ? new SvgUtil::PreserveAspectRatioParser(*rhs.ratioParser) : 0),
30 viewBoxTransform(rhs.viewBoxTransform)
31 {
32 }
33
34 QImage image;
35 QScopedPointer<SvgUtil::PreserveAspectRatioParser> ratioParser;
36 QTransform viewBoxTransform;
37};
38
39
41 : m_d(new Private)
42{
43}
44
46 : KoShape(rhs),
47 m_d(rhs.m_d)
48{
49}
50
54
56{
57 return new ImageShape(*this);
58}
59
60void ImageShape::paint(QPainter &painter) const
61{
62 KisQPainterStateSaver saver(&painter);
63
64 const QRectF myrect(QPointF(), size());
65
66 painter.setRenderHint(QPainter::SmoothPixmapTransform);
67 painter.setClipRect(QRectF(QPointF(), size()), Qt::IntersectClip);
68 painter.setTransform(m_d->viewBoxTransform, true);
69 painter.drawImage(QPoint(), m_d->image);
70}
71
72void ImageShape::setSize(const QSizeF &size)
73{
75}
76
78{
79 const QString uid = context.createUID("image");
80
81 context.shapeWriter().startElement("image");
82 context.shapeWriter().addAttribute("id", uid);
84 context.shapeWriter().addAttribute("width", QString("%1px").arg(KisDomUtils::toString(size().width())));
85 context.shapeWriter().addAttribute("height", QString("%1px").arg(KisDomUtils::toString(size().height())));
86
87 QString aspectString = m_d->ratioParser? m_d->ratioParser->toString(): QString();
88 if (!aspectString.isEmpty()) {
89 context.shapeWriter().addAttribute("preserveAspectRatio", aspectString);
90 }
91
92 QBuffer buffer;
93 buffer.open(QIODevice::WriteOnly);
94 if (m_d->image.save(&buffer, "PNG")) {
95 const QString mimeType = KisMimeDatabase::mimeTypeForSuffix("*.png");
96 context.shapeWriter().addAttribute("xlink:href", "data:"+ mimeType + ";base64," + buffer.data().toBase64());
97 }
98 SvgStyleWriter::saveMetadata(this, context);
99
100 context.shapeWriter().endElement(); // image
101
102 return true;
103}
104
105bool ImageShape::loadSvg(const QDomElement &element, SvgLoadingContext &context)
106{
107 const qreal x = SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), element.attribute("x"));
108 const qreal y = SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), element.attribute("y"));
109 const qreal w = SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), element.attribute("width"));
110 const qreal h = SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), element.attribute("height"));
111
112 setSize(QSizeF(w, h));
113 setPosition(QPointF(x, y));
114
115 if (w == 0.0 || h == 0.0) {
116 setVisible(false);
117 }
118
119 QString fileName = element.attribute("xlink:href");
120
121 QByteArray data;
122
123 if (fileName.startsWith("data:")) {
124
125 QRegularExpression re("data:(.+?);base64,(.+)");
126 QRegularExpressionMatch match = re.match(fileName);
127
128 data = match.captured(2).toLatin1();
129 data = QByteArray::fromBase64(data);
130 } else {
131 data = context.fetchExternalFile(fileName);
132 }
133
134 if (!data.isEmpty()) {
135 QBuffer buffer(&data);
136 m_d->image.load(&buffer, "");
137 }
138
139 const QString aspectString = element.attribute("preserveAspectRatio", "xMidYMid meet");
140 m_d->ratioParser.reset(new SvgUtil::PreserveAspectRatioParser(aspectString));
141
142 if (!m_d->image.isNull()) {
143
144 m_d->viewBoxTransform =
145 QTransform::fromScale(w / m_d->image.width(), h / m_d->image.height());
146
147 SvgUtil::parseAspectRatio(*m_d->ratioParser,
148 QRectF(QPointF(), size()),
149 QRect(QPoint(), m_d->image.size()),
150 &m_d->viewBoxTransform);
151 }
152
153 if (m_d->ratioParser->defer) {
154 // TODO:
155 }
156
157 return true;
158}
159
160void ImageShape::setImage(const QImage &img)
161{
162 if (m_d->image != img) {
163 m_d->image = img;
165 }
166}
167
168QImage ImageShape::image() const
169{
170 return m_d->image;
171}
172
173void ImageShape::setViewBoxTransform(const QTransform &tf)
174{
175 if (m_d->viewBoxTransform != tf) {
176 m_d->viewBoxTransform = tf;
178 }
179}
180
181QTransform ImageShape::viewBoxTransform() const
182{
183 return m_d->viewBoxTransform;
184}
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:735
virtual void shapeChanged(ChangeType type, KoShape *shape=0)
Definition KoShape.cpp:1054
@ ContentChanged
the content of the shape changed e.g. a new image inside a pixmap/text change inside a textshape
Definition KoShape.h:106
@ GenericMatrixChange
used after the matrix was changed without knowing which property explicitly changed
Definition KoShape.h:98
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:378
virtual void setPosition(const QPointF &position)
Set the position of the shape in pt.
Definition KoShape.cpp:268
void setVisible(bool on)
Definition KoShape.cpp:790
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:249
Contains data used for loading svg.
QByteArray fetchExternalFile(const QString &url)
KoSvgTextProperties resolvedProperties(bool onlyFontAndLineHeight=false) const
SvgGraphicsContext * currentGC() const
Returns the current graphics context.
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