2 ******************************************************************************
4 * @file svgimageprovider.cpp
5 * @author Dmytro Poplavskiy Copyright (C) 2012.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup OPMapPlugin QML Viewer Plugin
10 * @brief Svg declarative image provider
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "svgimageprovider.h"
34 #include <QSvgRenderer>
36 SvgImageProvider::SvgImageProvider(const QString
&basePath
) :
37 QQuickImageProvider(QQuickImageProvider::Image
),
41 SvgImageProvider::~SvgImageProvider()
43 qDeleteAll(m_renderers
);
46 QSvgRenderer
*SvgImageProvider::loadRenderer(const QString
&svgFile
)
48 QSvgRenderer
*renderer
= m_renderers
.value(svgFile
, NULL
);
51 QFileInfo
fi(svgFile
);
53 // if svgFile is relative, make it relative to base
54 QString fn
= fi
.isRelative() ? QUrl::fromLocalFile(m_basePath
).resolved(svgFile
).toLocalFile() : svgFile
;
56 renderer
= new QSvgRenderer(fn
);
57 if (!renderer
->isValid()) {
58 qWarning() << "Failed to load svg file:" << svgFile
<< fn
;
63 m_renderers
.insert(svgFile
, renderer
);
70 Supported id format: fileName[!elementName[?parameters]]
71 where parameters may be:
72 vslice=1:2;hslice=2:4 - use the 3rd horizontal slice of total 4 slices, slice numbering starts from 0
73 borders=1 - 1 pixel wide transparent border
75 requestedSize is related to the whole element size, even if slice is requested.
80 source: "image://svg/pfd.svg!world"
83 QImage
SvgImageProvider::requestImage(const QString
&id
, QSize
*size
, const QSize
&requestedSize
)
89 int separatorPos
= id
.indexOf('!');
91 if (separatorPos
!= -1) {
92 svgFile
= id
.left(separatorPos
);
93 element
= id
.mid(separatorPos
+ 1);
96 int parametersPos
= element
.indexOf('?');
97 if (parametersPos
!= -1) {
98 parameters
= element
.mid(parametersPos
+ 1);
99 element
= element
.left(parametersPos
);
102 int hSlicesCount
= 0;
104 int vSlicesCount
= 0;
107 if (!parameters
.isEmpty()) {
108 QRegExp
hSliceRx("hslice=(\\d+):(\\d+)");
109 if (hSliceRx
.indexIn(parameters
) != -1) {
110 hSlice
= hSliceRx
.cap(1).toInt();
111 hSlicesCount
= hSliceRx
.cap(2).toInt();
113 QRegExp
vSliceRx("vslice=(\\d+):(\\d+)");
114 if (vSliceRx
.indexIn(parameters
) != -1) {
115 vSlice
= vSliceRx
.cap(1).toInt();
116 vSlicesCount
= vSliceRx
.cap(2).toInt();
118 QRegExp
borderRx("border=(\\d+)");
119 if (borderRx
.indexIn(parameters
) != -1) {
120 border
= borderRx
.cap(1).toInt();
128 QSvgRenderer
*renderer
= loadRenderer(svgFile
);
136 QSize docSize
= renderer
->defaultSize();
138 if (!requestedSize
.isEmpty()) {
139 if (!element
.isEmpty()) {
140 QRectF elementBounds
= renderer
->boundsOnElement(element
);
141 xScale
= qreal(requestedSize
.width()) / elementBounds
.width();
142 yScale
= qreal(requestedSize
.height()) / elementBounds
.height();
143 } else if (!docSize
.isEmpty()) {
144 xScale
= qreal(requestedSize
.width()) / docSize
.width();
145 yScale
= qreal(requestedSize
.height()) / docSize
.height();
149 // keep the aspect ratio
150 // TODO: how to configure it? as a part of image path?
151 xScale
= yScale
= qMin(xScale
, yScale
);
153 if (!element
.isEmpty()) {
154 if (!renderer
->elementExists(element
)) {
155 qWarning() << "invalid element:" << element
<< "of" << svgFile
;
159 QRectF elementBounds
= renderer
->boundsOnElement(element
);
160 int elementWidth
= qRound(elementBounds
.width() * xScale
);
161 int elementHeigh
= qRound(elementBounds
.height() * yScale
);
162 int w
= elementWidth
;
163 int h
= elementHeigh
;
167 if (hSlicesCount
> 1) {
168 x
= (w
* hSlice
) / hSlicesCount
;
169 w
= (w
* (hSlice
+ 1)) / hSlicesCount
- x
;
172 if (vSlicesCount
> 1) {
173 y
= (h
* (vSlice
)) / vSlicesCount
;
174 h
= (h
* (vSlice
+ 1)) / vSlicesCount
- y
;
177 QImage
img(w
+ border
* 2, h
+ border
* 2, QImage::Format_ARGB32_Premultiplied
);
180 p
.setRenderHints(QPainter::TextAntialiasing
|
181 QPainter::Antialiasing
|
182 QPainter::SmoothPixmapTransform
);
184 p
.translate(-x
+ border
, -y
+ border
);
185 renderer
->render(&p
, element
, QRectF(0, 0, elementWidth
, elementHeigh
));
191 // img.save(element+parameters+".png");
194 // render the whole svg file
195 int w
= qRound(docSize
.width() * xScale
);
196 int h
= qRound(docSize
.height() * yScale
);
198 QImage
img(w
, h
, QImage::Format_ARGB32_Premultiplied
);
201 p
.setRenderHints(QPainter::TextAntialiasing
|
202 QPainter::Antialiasing
|
203 QPainter::SmoothPixmapTransform
);
205 p
.scale(xScale
, yScale
);
206 renderer
->render(&p
, QRectF(QPointF(), QSizeF(docSize
)));
215 QPixmap
SvgImageProvider::requestPixmap(const QString
&id
, QSize
*size
, const QSize
&requestedSize
)
217 return QPixmap::fromImage(requestImage(id
, size
, requestedSize
));
221 \fn SvgImageProvider::scaledElementBounds(const QString &svgFile, const QString &element)
223 Returns the bound of \a element in logical coordinates,
224 scalled to the default size of svg document (so the bounds of whole doc would be (0,0,1,1) ).
226 QRectF
SvgImageProvider::scaledElementBounds(const QString
&svgFile
, const QString
&elementName
)
228 QSvgRenderer
*renderer
= loadRenderer(svgFile
);
234 if (!renderer
->elementExists(elementName
)) {
235 qWarning() << "invalid element:" << elementName
<< "of" << svgFile
;
239 QRectF elementBounds
= renderer
->boundsOnElement(elementName
);
240 QMatrix matrix
= renderer
->matrixForElement(elementName
);
241 elementBounds
= matrix
.mapRect(elementBounds
);
243 QSize docSize
= renderer
->defaultSize();
244 return QRectF(elementBounds
.x() / docSize
.width(),
245 elementBounds
.y() / docSize
.height(),
246 elementBounds
.width() / docSize
.width(),
247 elementBounds
.height() / docSize
.height());