dRonin  adbada4
dRonin GCS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
svgimageprovider.cpp
Go to the documentation of this file.
1 
12 /*
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.
17  *
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.
22  *
23  * You should have received a copy of the GNU General Public License along
24  * with this program; if not, see <http://www.gnu.org/licenses/>
25  */
26 
27 #include "svgimageprovider.h"
28 #include <QDebug>
29 #include <QPainter>
30 #include <QUrl>
31 #include <QFileInfo>
32 
33 SvgImageProvider::SvgImageProvider(const QString &basePath):
34  QObject(),
35  QQuickImageProvider(QQuickImageProvider::Image),
36  m_basePath(basePath)
37 {
38 }
39 
41 {
42  qDeleteAll(m_renderers);
43 }
44 
45 QSvgRenderer *SvgImageProvider::loadRenderer(const QString &svgFile)
46 {
47  QSvgRenderer *renderer = m_renderers.value(svgFile, NULL);
48  if (!renderer) {
49  QString fn = svgFile;
50 
51  if(!QFileInfo::exists(fn)) {
52  //convert path to be relative to base
53  fn = QUrl::fromLocalFile(m_basePath).resolved(svgFile).toLocalFile();
54  }
55 
56  if(!QFileInfo::exists(fn)) {
57  //it's really missing this time
58  qWarning() << "[SvgImageProvider::loadRenderer]SVG file not found:" << svgFile;
59  return nullptr;
60  }
61 
62  renderer = new QSvgRenderer(fn);
63 
64  if (!renderer->isValid()) {
65  qWarning() << "[SvgImageProvider::loadRenderer]Failed to load svg file:" << svgFile;
66  delete renderer;
67  return nullptr;
68  }
69 
70  m_renderers.insert(svgFile, renderer);
71  }
72 
73  return renderer;
74 }
75 
90 QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
91 {
92  QString svgFile = id;
93  QString element;
94  QString parameters;
95 
96  int separatorPos = id.indexOf('!');
97  if (separatorPos != -1) {
98  svgFile = id.left(separatorPos);
99  element = id.mid(separatorPos+1);
100  }
101 
102  int parametersPos = element.indexOf('?');
103  if (parametersPos != -1) {
104  parameters = element.mid(parametersPos+1);
105  element = element.left(parametersPos);
106  }
107 
108  int hSlicesCount = 0;
109  int hSlice = 0;
110  int vSlicesCount = 0;
111  int vSlice = 0;
112  int border = 0;
113  if (!parameters.isEmpty()) {
114  QRegExp hSliceRx("hslice=(\\d+):(\\d+)");
115  if (hSliceRx.indexIn(parameters) != -1) {
116  hSlice = hSliceRx.cap(1).toInt();
117  hSlicesCount = hSliceRx.cap(2).toInt();
118  }
119  QRegExp vSliceRx("vslice=(\\d+):(\\d+)");
120  if (vSliceRx.indexIn(parameters) != -1) {
121  vSlice = vSliceRx.cap(1).toInt();
122  vSlicesCount = vSliceRx.cap(2).toInt();
123  }
124  QRegExp borderRx("border=(\\d+)");
125  if (borderRx.indexIn(parameters) != -1) {
126  border = borderRx.cap(1).toInt();
127  }
128  }
129 
130  if (size)
131  *size = QSize();
132 
133  QSvgRenderer *renderer = loadRenderer(svgFile);
134  if (!renderer)
135  return QImage();
136 
137  qreal xScale = 1.0;
138  qreal yScale = 1.0;
139 
140  QSize docSize = renderer->defaultSize();
141 
142  if (!requestedSize.isEmpty()) {
143  if (!element.isEmpty()) {
144  QRectF elementBounds = renderer->boundsOnElement(element);
145  xScale = qreal(requestedSize.width())/elementBounds.width();
146  yScale = qreal(requestedSize.height())/elementBounds.height();
147  } else if (!docSize.isEmpty()) {
148  xScale = qreal(requestedSize.width())/docSize.width();
149  yScale = qreal(requestedSize.height())/docSize.height();
150  }
151  }
152 
153  //keep the aspect ratio
154  //TODO: how to configure it? as a part of image path?
155  xScale = yScale = qMin(xScale, yScale);
156 
157  if (!element.isEmpty()) {
158  if (!renderer->elementExists(element)) {
159  qWarning() << "invalid element:" << element << "of" << svgFile;
160  return QImage();
161  }
162 
163  QRectF elementBounds = renderer->boundsOnElement(element);
164  int elementWidth = qRound(elementBounds.width() * xScale);
165  int elementHeigh = qRound(elementBounds.height() * yScale);
166  int w = elementWidth;
167  int h = elementHeigh;
168  int x = 0;
169  int y = 0;
170 
171  if (hSlicesCount > 1) {
172  x = (w*hSlice)/hSlicesCount;
173  w = (w*(hSlice+1))/hSlicesCount - x;
174  }
175 
176  if (vSlicesCount > 1) {
177  y = (h*(vSlice))/vSlicesCount;
178  h = (h*(vSlice+1))/vSlicesCount - y;
179  }
180 
181  QImage img(w+border*2, h+border*2, QImage::Format_ARGB32_Premultiplied);
182  img.fill(0);
183  QPainter p(&img);
184  p.setRenderHints(QPainter::TextAntialiasing |
185  QPainter::Antialiasing |
186  QPainter::SmoothPixmapTransform);
187 
188  p.translate(-x+border,-y+border);
189  renderer->render(&p, element, QRectF(0, 0, elementWidth, elementHeigh));
190 
191  if (size)
192  *size = QSize(w, h);
193 
194  //img.save(element+parameters+".png");
195  return img;
196  } else {
197  //render the whole svg file
198  int w = qRound(docSize.width() * xScale);
199  int h = qRound(docSize.height() * yScale);
200 
201  QImage img(w, h, QImage::Format_ARGB32_Premultiplied);
202  img.fill(0);
203  QPainter p(&img);
204  p.setRenderHints(QPainter::TextAntialiasing |
205  QPainter::Antialiasing |
206  QPainter::SmoothPixmapTransform);
207 
208  p.scale(xScale, yScale);
209  renderer->render(&p, QRectF(QPointF(), QSizeF(docSize)));
210 
211  if (size)
212  *size = QSize(w, h);
213  return img;
214  }
215 }
216 
217 QPixmap SvgImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
218 {
219  return QPixmap::fromImage(requestImage(id, size, requestedSize));
220 }
221 
228 QRectF SvgImageProvider::scaledElementBounds(const QString &svgFile, const QString &elementName)
229 {
230  QSvgRenderer *renderer = loadRenderer(svgFile);
231 
232  if (!renderer)
233  return QRectF();
234 
235  if (!renderer->elementExists(elementName)) {
236  qWarning() << "invalid element:" << elementName << "of" << svgFile;
237  return QRectF();
238  }
239 
240  QRectF elementBounds = renderer->boundsOnElement(elementName);
241  QMatrix matrix = renderer->matrixForElement(elementName);
242  elementBounds = matrix.mapRect(elementBounds);
243 
244  QSize docSize = renderer->defaultSize();
245  return QRectF(elementBounds.x()/docSize.width(),
246  elementBounds.y()/docSize.height(),
247  elementBounds.width()/docSize.width(),
248  elementBounds.height()/docSize.height());
249 }
SvgImageProvider(const QString &basePath)
QSvgRenderer * loadRenderer(const QString &svgFile)
Q_INVOKABLE QRectF scaledElementBounds(const QString &svgFile, const QString &elementName)
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize)
x
Definition: OPPlots.m:100
y
Definition: OPPlots.m:101