LP-311 Remove basic/advanced stabilization tab auto-switch (autotune/txpid lock issues)
[librepilot.git] / ground / gcs / src / libs / utils / svgimageprovider.cpp
blob85e2fc318f01da4d5b96e9f60f82b2a6fd26b831
1 /**
2 ******************************************************************************
4 * @file svgimageprovider.cpp
5 * @author Dmytro Poplavskiy Copyright (C) 2012.
6 * @addtogroup GCSPlugins GCS Plugins
7 * @{
8 * @addtogroup OPMapPlugin QML Viewer Plugin
9 * @{
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
21 * for more details.
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"
30 #include <QDebug>
31 #include <QPainter>
32 #include <QUrl>
33 #include <QFileInfo>
34 #include <QSvgRenderer>
36 SvgImageProvider::SvgImageProvider(const QString &basePath) :
37 QQuickImageProvider(QQuickImageProvider::Image),
38 m_basePath(basePath)
41 SvgImageProvider::~SvgImageProvider()
43 qDeleteAll(m_renderers);
46 QSvgRenderer *SvgImageProvider::loadRenderer(const QString &svgFile)
48 QSvgRenderer *renderer = m_renderers.value(svgFile, NULL);
50 if (!renderer) {
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;
59 delete renderer;
60 return 0;
63 m_renderers.insert(svgFile, renderer);
66 return renderer;
69 /**
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.
77 usage:
79 Image {
80 source: "image://svg/pfd.svg!world"
83 QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
85 QString svgFile = id;
86 QString element;
87 QString parameters;
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;
103 int hSlice = 0;
104 int vSlicesCount = 0;
105 int vSlice = 0;
106 int border = 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();
124 if (size) {
125 *size = QSize();
128 QSvgRenderer *renderer = loadRenderer(svgFile);
129 if (!renderer) {
130 return QImage();
133 qreal xScale = 1.0;
134 qreal yScale = 1.0;
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;
156 return QImage();
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;
164 int x = 0;
165 int y = 0;
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);
178 img.fill(0);
179 QPainter p(&img);
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));
187 if (size) {
188 *size = QSize(w, h);
191 // img.save(element+parameters+".png");
192 return img;
193 } else {
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);
199 img.fill(0);
200 QPainter p(&img);
201 p.setRenderHints(QPainter::TextAntialiasing |
202 QPainter::Antialiasing |
203 QPainter::SmoothPixmapTransform);
205 p.scale(xScale, yScale);
206 renderer->render(&p, QRectF(QPointF(), QSizeF(docSize)));
208 if (size) {
209 *size = QSize(w, h);
211 return img;
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);
230 if (!renderer) {
231 return QRectF();
234 if (!renderer->elementExists(elementName)) {
235 qWarning() << "invalid element:" << elementName << "of" << svgFile;
236 return QRectF();
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());