Qt 4.8
qsvggenerator.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtSvg module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qsvggenerator.h"
43 
44 #ifndef QT_NO_SVGGENERATOR
45 
46 #include "qpainterpath.h"
47 
48 #include "private/qpaintengine_p.h"
49 #include "private/qtextengine_p.h"
50 #include "private/qdrawhelper_p.h"
51 
52 #include "qfile.h"
53 #include "qtextcodec.h"
54 #include "qtextstream.h"
55 #include "qbuffer.h"
56 #include "qmath.h"
57 
58 #include "qdebug.h"
59 
61 
62 static void translate_color(const QColor &color, QString *color_string,
63  QString *opacity_string)
64 {
65  Q_ASSERT(color_string);
66  Q_ASSERT(opacity_string);
67 
68  *color_string =
69  QString::fromLatin1("#%1%2%3")
70  .arg(color.red(), 2, 16, QLatin1Char('0'))
71  .arg(color.green(), 2, 16, QLatin1Char('0'))
72  .arg(color.blue(), 2, 16, QLatin1Char('0'));
73  *opacity_string = QString::number(color.alphaF());
74 }
75 
76 static void translate_dashPattern(QVector<qreal> pattern, const qreal& width, QString *pattern_string)
77 {
78  Q_ASSERT(pattern_string);
79 
80  // Note that SVG operates in absolute lengths, whereas Qt uses a length/width ratio.
81  foreach (qreal entry, pattern)
82  *pattern_string += QString::fromLatin1("%1,").arg(entry * width);
83 
84  pattern_string->chop(1);
85 }
86 
88 {
89 public:
91  {
92  size = QSize();
93  viewBox = QRectF();
94  outputDevice = 0;
95  resolution = 72;
96 
97  attributes.document_title = QLatin1String("Qt Svg Document");
98  attributes.document_description = QLatin1String("Generated with Qt");
101  attributes.font_style = QLatin1String("normal");
103 
104  afterFirstUpdate = false;
105  numGradients = 0;
106  }
107 
113 
118 
123 
125  ++numGradients;
127  return currentGradientName;
128  }
129 
132 
133  struct _attributes {
143  } attributes;
144 };
145 
146 static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures()
147 {
148  return QPaintEngine::PaintEngineFeatures(
154 }
155 
157 {
159 public:
160 
164  {
165  }
166 
167  bool begin(QPaintDevice *device);
168  bool end();
169 
170  void updateState(const QPaintEngineState &state);
171  void popGroup();
172 
173  void drawPath(const QPainterPath &path);
174  void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr);
175  void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode);
176  void drawTextItem(const QPointF &pt, const QTextItem &item);
177  void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr,
179 
181 
182  QSize size() const { return d_func()->size; }
183  void setSize(const QSize &size) {
184  Q_ASSERT(!isActive());
185  d_func()->size = size;
186  }
187 
188  QRectF viewBox() const { return d_func()->viewBox; }
189  void setViewBox(const QRectF &viewBox) {
190  Q_ASSERT(!isActive());
191  d_func()->viewBox = viewBox;
192  }
193 
194  QString documentTitle() const { return d_func()->attributes.document_title; }
195  void setDocumentTitle(const QString &title) {
196  d_func()->attributes.document_title = title;
197  }
198 
199  QString documentDescription() const { return d_func()->attributes.document_description; }
200  void setDocumentDescription(const QString &description) {
201  d_func()->attributes.document_description = description;
202  }
203 
204  QIODevice *outputDevice() const { return d_func()->outputDevice; }
205  void setOutputDevice(QIODevice *device) {
206  Q_ASSERT(!isActive());
207  d_func()->outputDevice = device;
208  }
209 
210  int resolution() { return d_func()->resolution; }
212  Q_ASSERT(!isActive());
213  d_func()->resolution = resolution;
214  }
216  {
217  QTextStream str(&d_func()->defs, QIODevice::Append);
218  const QLinearGradient *grad = static_cast<const QLinearGradient*>(g);
219  str << QLatin1String("<linearGradient ");
220  saveGradientUnits(str, g);
221  if (grad) {
222  str << QLatin1String("x1=\"") <<grad->start().x()<< QLatin1String("\" ")
223  << QLatin1String("y1=\"") <<grad->start().y()<< QLatin1String("\" ")
224  << QLatin1String("x2=\"") <<grad->finalStop().x() << QLatin1String("\" ")
225  << QLatin1String("y2=\"") <<grad->finalStop().y() << QLatin1String("\" ");
226  }
227 
228  str << QLatin1String("id=\"") << d_func()->generateGradientName() << QLatin1String("\">\n");
229  saveGradientStops(str, g);
230  str << QLatin1String("</linearGradient>") <<endl;
231  }
233  {
234  QTextStream str(&d_func()->defs, QIODevice::Append);
235  const QRadialGradient *grad = static_cast<const QRadialGradient*>(g);
236  str << QLatin1String("<radialGradient ");
237  saveGradientUnits(str, g);
238  if (grad) {
239  str << QLatin1String("cx=\"") <<grad->center().x()<< QLatin1String("\" ")
240  << QLatin1String("cy=\"") <<grad->center().y()<< QLatin1String("\" ")
241  << QLatin1String("r=\"") <<grad->radius() << QLatin1String("\" ")
242  << QLatin1String("fx=\"") <<grad->focalPoint().x() << QLatin1String("\" ")
243  << QLatin1String("fy=\"") <<grad->focalPoint().y() << QLatin1String("\" ");
244  }
245  str << QLatin1String("xml:id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n");
246  saveGradientStops(str, g);
247  str << QLatin1String("</radialGradient>") << endl;
248  }
250  {
251  qWarning("svg's don't support conical gradients!");
252  }
253 
254  void saveGradientStops(QTextStream &str, const QGradient *g) {
255  QGradientStops stops = g->stops();
256 
258  bool constantAlpha = true;
259  int alpha = stops.at(0).second.alpha();
260  for (int i = 1; i < stops.size(); ++i)
261  constantAlpha &= (stops.at(i).second.alpha() == alpha);
262 
263  if (!constantAlpha) {
264  const qreal spacing = qreal(0.02);
265  QGradientStops newStops;
266  QRgb fromColor = PREMUL(stops.at(0).second.rgba());
267  QRgb toColor;
268  for (int i = 0; i + 1 < stops.size(); ++i) {
269  int parts = qCeil((stops.at(i + 1).first - stops.at(i).first) / spacing);
270  newStops.append(stops.at(i));
271  toColor = PREMUL(stops.at(i + 1).second.rgba());
272 
273  if (parts > 1) {
274  qreal step = (stops.at(i + 1).first - stops.at(i).first) / parts;
275  for (int j = 1; j < parts; ++j) {
276  QRgb color = INV_PREMUL(INTERPOLATE_PIXEL_256(fromColor, 256 - 256 * j / parts, toColor, 256 * j / parts));
277  newStops.append(QGradientStop(stops.at(i).first + j * step, QColor::fromRgba(color)));
278  }
279  }
280  fromColor = toColor;
281  }
282  newStops.append(stops.back());
283  stops = newStops;
284  }
285  }
286 
287  foreach(QGradientStop stop, stops) {
288  QString color =
289  QString::fromLatin1("#%1%2%3")
290  .arg(stop.second.red(), 2, 16, QLatin1Char('0'))
291  .arg(stop.second.green(), 2, 16, QLatin1Char('0'))
292  .arg(stop.second.blue(), 2, 16, QLatin1Char('0'));
293  str << QLatin1String(" <stop offset=\"")<< stop.first << QLatin1String("\" ")
294  << QLatin1String("stop-color=\"") << color << QLatin1String("\" ")
295  << QLatin1String("stop-opacity=\"") << stop.second.alphaF() <<QLatin1String("\" />\n");
296  }
297  }
298 
299  void saveGradientUnits(QTextStream &str, const QGradient *gradient)
300  {
301  str << QLatin1String("gradientUnits=\"");
302  if (gradient && gradient->coordinateMode() == QGradient::ObjectBoundingMode)
303  str << QLatin1String("objectBoundingBox");
304  else
305  str << QLatin1String("userSpaceOnUse");
306  str << QLatin1String("\" ");
307  }
308 
310  {
311  *d_func()->stream << QLatin1String("fill=\"none\" ");
312  *d_func()->stream << QLatin1String("stroke=\"black\" ");
313  *d_func()->stream << QLatin1String("stroke-width=\"1\" ");
314  *d_func()->stream << QLatin1String("fill-rule=\"evenodd\" ");
315  *d_func()->stream << QLatin1String("stroke-linecap=\"square\" ");
316  *d_func()->stream << QLatin1String("stroke-linejoin=\"bevel\" ");
317  *d_func()->stream << QLatin1String(">\n");
318  }
319  inline QTextStream &stream()
320  {
321  return *d_func()->stream;
322  }
323 
324 
325  void qpenToSvg(const QPen &spen)
326  {
327  QString width;
328 
329  d_func()->pen = spen;
330 
331  switch (spen.style()) {
332  case Qt::NoPen:
333  stream() << QLatin1String("stroke=\"none\" ");
334 
335  d_func()->attributes.stroke = QLatin1String("none");
336  d_func()->attributes.strokeOpacity = QString();
337  return;
338  break;
339  case Qt::SolidLine: {
340  QString color, colorOpacity;
341 
342  translate_color(spen.color(), &color,
343  &colorOpacity);
344  d_func()->attributes.stroke = color;
345  d_func()->attributes.strokeOpacity = colorOpacity;
346 
347  stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
348  stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
349  }
350  break;
351  case Qt::DashLine:
352  case Qt::DotLine:
353  case Qt::DashDotLine:
354  case Qt::DashDotDotLine:
355  case Qt::CustomDashLine: {
356  QString color, colorOpacity, dashPattern, dashOffset;
357 
358  qreal penWidth = spen.width() == 0 ? qreal(1) : spen.widthF();
359 
360  translate_color(spen.color(), &color, &colorOpacity);
361  translate_dashPattern(spen.dashPattern(), penWidth, &dashPattern);
362 
363  // SVG uses absolute offset
364  dashOffset = QString::number(spen.dashOffset() * penWidth);
365 
366  d_func()->attributes.stroke = color;
367  d_func()->attributes.strokeOpacity = colorOpacity;
368  d_func()->attributes.dashPattern = dashPattern;
369  d_func()->attributes.dashOffset = dashOffset;
370 
371  stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" ");
372  stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" ");
373  stream() << QLatin1String("stroke-dasharray=\"")<<dashPattern<< QLatin1String("\" ");
374  stream() << QLatin1String("stroke-dashoffset=\"")<<dashOffset<< QLatin1String("\" ");
375  break;
376  }
377  default:
378  qWarning("Unsupported pen style");
379  break;
380  }
381 
382  if (spen.widthF() == 0)
383  stream() <<"stroke-width=\"1\" ";
384  else
385  stream() <<"stroke-width=\"" << spen.widthF() << "\" ";
386 
387  switch (spen.capStyle()) {
388  case Qt::FlatCap:
389  stream() << "stroke-linecap=\"butt\" ";
390  break;
391  case Qt::SquareCap:
392  stream() << "stroke-linecap=\"square\" ";
393  break;
394  case Qt::RoundCap:
395  stream() << "stroke-linecap=\"round\" ";
396  break;
397  default:
398  qWarning("Unhandled cap style");
399  }
400  switch (spen.joinStyle()) {
401  case Qt::MiterJoin:
402  stream() << "stroke-linejoin=\"miter\" "
403  "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
404  break;
405  case Qt::BevelJoin:
406  stream() << "stroke-linejoin=\"bevel\" ";
407  break;
408  case Qt::RoundJoin:
409  stream() << "stroke-linejoin=\"round\" ";
410  break;
411  case Qt::SvgMiterJoin:
412  stream() << "stroke-linejoin=\"miter\" "
413  "stroke-miterlimit=\""<<spen.miterLimit()<<"\" ";
414  break;
415  default:
416  qWarning("Unhandled join style");
417  }
418  }
419  void qbrushToSvg(const QBrush &sbrush)
420  {
421  d_func()->brush = sbrush;
422  switch (sbrush.style()) {
423  case Qt::SolidPattern: {
424  QString color, colorOpacity;
425  translate_color(sbrush.color(), &color, &colorOpacity);
426  stream() << "fill=\"" << color << "\" "
427  "fill-opacity=\""
428  << colorOpacity << "\" ";
429  d_func()->attributes.fill = color;
430  d_func()->attributes.fillOpacity = colorOpacity;
431  }
432  break;
434  saveLinearGradientBrush(sbrush.gradient());
435  d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
436  d_func()->attributes.fillOpacity = QString();
437  stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
438  break;
440  saveRadialGradientBrush(sbrush.gradient());
441  d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
442  d_func()->attributes.fillOpacity = QString();
443  stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
444  break;
446  saveConicalGradientBrush(sbrush.gradient());
447  d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName);
448  d_func()->attributes.fillOpacity = QString();
449  stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" ");
450  break;
451  case Qt::NoBrush:
452  stream() << QLatin1String("fill=\"none\" ");
453  d_func()->attributes.fill = QLatin1String("none");
454  d_func()->attributes.fillOpacity = QString();
455  return;
456  break;
457  default:
458  break;
459  }
460  }
461  void qfontToSvg(const QFont &sfont)
462  {
464 
465  d->font = sfont;
466 
467  if (d->font.pixelSize() == -1)
468  d->attributes.font_size = QString::number(d->font.pointSizeF() * d->resolution / 72);
469  else
470  d->attributes.font_size = QString::number(d->font.pixelSize());
471 
472  int svgWeight = d->font.weight();
473  switch (svgWeight) {
474  case QFont::Light:
475  svgWeight = 100;
476  break;
477  case QFont::Normal:
478  svgWeight = 400;
479  break;
480  case QFont::Bold:
481  svgWeight = 700;
482  break;
483  default:
484  svgWeight *= 10;
485  }
486 
487  d->attributes.font_weight = QString::number(svgWeight);
488  d->attributes.font_family = d->font.family();
489  d->attributes.font_style = d->font.italic() ? QLatin1String("italic") : QLatin1String("normal");
490 
491  *d->stream << "font-family=\"" << d->attributes.font_family << "\" "
492  "font-size=\"" << d->attributes.font_size << "\" "
493  "font-weight=\"" << d->attributes.font_weight << "\" "
494  "font-style=\"" << d->attributes.font_style << "\" "
495  << endl;
496  }
497 };
498 
500 {
501 public:
503 
506 };
507 
552  : d_ptr(new QSvgGeneratorPrivate)
553 {
555 
556  d->engine = new QSvgPaintEngine;
557  d->owns_iodevice = false;
558 }
559 
564 {
566  if (d->owns_iodevice)
567  delete d->engine->outputDevice();
568  delete d->engine;
569 }
570 
581 {
582  Q_D(const QSvgGenerator);
583 
584  return d->engine->documentTitle();
585 }
586 
588 {
590 
591  d->engine->setDocumentTitle(title);
592 }
593 
604 {
605  Q_D(const QSvgGenerator);
606 
607  return d->engine->documentDescription();
608 }
609 
611 {
613 
614  d->engine->setDocumentDescription(description);
615 }
616 
635 {
636  Q_D(const QSvgGenerator);
637  return d->engine->size();
638 }
639 
641 {
643  if (d->engine->isActive()) {
644  qWarning("QSvgGenerator::setSize(), cannot set size while SVG is being generated");
645  return;
646  }
647  d->engine->setSize(size);
648 }
649 
668 {
669  Q_D(const QSvgGenerator);
670  return d->engine->viewBox();
671 }
672 
684 {
685  Q_D(const QSvgGenerator);
686  return d->engine->viewBox().toRect();
687 }
688 
690 {
692  if (d->engine->isActive()) {
693  qWarning("QSvgGenerator::setViewBox(), cannot set viewBox while SVG is being generated");
694  return;
695  }
696  d->engine->setViewBox(viewBox);
697 }
698 
700 {
701  setViewBox(QRectF(viewBox));
702 }
703 
715 {
716  Q_D(const QSvgGenerator);
717  return d->fileName;
718 }
719 
721 {
723  if (d->engine->isActive()) {
724  qWarning("QSvgGenerator::setFileName(), cannot set file name while SVG is being generated");
725  return;
726  }
727 
728  if (d->owns_iodevice)
729  delete d->engine->outputDevice();
730 
731  d->owns_iodevice = true;
732 
733  d->fileName = fileName;
734  QFile *file = new QFile(fileName);
735  d->engine->setOutputDevice(file);
736 }
737 
752 {
753  Q_D(const QSvgGenerator);
754  return d->engine->outputDevice();
755 }
756 
758 {
760  if (d->engine->isActive()) {
761  qWarning("QSvgGenerator::setOutputDevice(), cannot set output device while SVG is being generated");
762  return;
763  }
764  d->owns_iodevice = false;
765  d->engine->setOutputDevice(outputDevice);
766  d->fileName = QString();
767 }
768 
782 int QSvgGenerator::resolution() const
783 {
784  Q_D(const QSvgGenerator);
785  return d->engine->resolution();
786 }
787 
789 {
791  d->engine->setResolution(dpi);
792 }
793 
799 {
800  Q_D(const QSvgGenerator);
801  return d->engine;
802 }
803 
808 {
809  Q_D(const QSvgGenerator);
810  switch (metric) {
812  return 32;
814  return d->engine->size().width();
816  return d->engine->size().height();
818  return d->engine->resolution();
820  return d->engine->resolution();
822  return qRound(d->engine->size().height() * 25.4 / d->engine->resolution());
824  return qRound(d->engine->size().width() * 25.4 / d->engine->resolution());
826  return 0xffffffff;
828  return d->engine->resolution();
830  return d->engine->resolution();
831  default:
832  qWarning("QSvgGenerator::metric(), unhandled metric %d\n", metric);
833  break;
834  }
835  return 0;
836 }
837 
838 /*****************************************************************************
839  * class QSvgPaintEngine
840  */
841 
843 {
845  if (!d->outputDevice) {
846  qWarning("QSvgPaintEngine::begin(), no output device");
847  return false;
848  }
849 
850  if (!d->outputDevice->isOpen()) {
851  if (!d->outputDevice->open(QIODevice::WriteOnly | QIODevice::Text)) {
852  qWarning("QSvgPaintEngine::begin(), could not open output device: '%s'",
853  qPrintable(d->outputDevice->errorString()));
854  return false;
855  }
856  } else if (!d->outputDevice->isWritable()) {
857  qWarning("QSvgPaintEngine::begin(), could not write to read-only output device: '%s'",
858  qPrintable(d->outputDevice->errorString()));
859  return false;
860  }
861 
862  d->stream = new QTextStream(&d->header);
863 
864  // stream out the header...
865  *d->stream << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" << endl << "<svg";
866 
867  if (d->size.isValid()) {
868  qreal wmm = d->size.width() * 25.4 / d->resolution;
869  qreal hmm = d->size.height() * 25.4 / d->resolution;
870  *d->stream << " width=\"" << wmm << "mm\" height=\"" << hmm << "mm\"" << endl;
871  }
872 
873  if (d->viewBox.isValid()) {
874  *d->stream << " viewBox=\"" << d->viewBox.left() << ' ' << d->viewBox.top();
875  *d->stream << ' ' << d->viewBox.width() << ' ' << d->viewBox.height() << '\"' << endl;
876  }
877 
878  *d->stream << " xmlns=\"http://www.w3.org/2000/svg\""
879  " xmlns:xlink=\"http://www.w3.org/1999/xlink\" "
880  " version=\"1.2\" baseProfile=\"tiny\">" << endl;
881 
882  if (!d->attributes.document_title.isEmpty()) {
883  *d->stream << "<title>" << d->attributes.document_title << "</title>" << endl;
884  }
885 
886  if (!d->attributes.document_description.isEmpty()) {
887  *d->stream << "<desc>" << d->attributes.document_description << "</desc>" << endl;
888  }
889 
890  d->stream->setString(&d->defs);
891  *d->stream << "<defs>\n";
892 
893  d->stream->setString(&d->body);
894  // Start the initial graphics state...
895  *d->stream << "<g ";
896  generateQtDefaults();
897  *d->stream << endl;
898 
899  return true;
900 }
901 
903 {
905 
906  d->stream->setString(&d->defs);
907  *d->stream << "</defs>\n";
908 
909  d->stream->setDevice(d->outputDevice);
910 #ifndef QT_NO_TEXTCODEC
911  d->stream->setCodec(QTextCodec::codecForName("UTF-8"));
912 #endif
913 
914  *d->stream << d->header;
915  *d->stream << d->defs;
916  *d->stream << d->body;
917  if (d->afterFirstUpdate)
918  *d->stream << "</g>" << endl; // close the updateState
919 
920  *d->stream << "</g>" << endl // close the Qt defaults
921  << "</svg>" << endl;
922 
923  delete d->stream;
924 
925  return true;
926 }
927 
928 void QSvgPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm,
929  const QRectF &sr)
930 {
931  drawImage(r, pm.toImage(), sr);
932 }
933 
934 void QSvgPaintEngine::drawImage(const QRectF &r, const QImage &image,
935  const QRectF &sr,
937 {
938  //Q_D(QSvgPaintEngine);
939 
940  Q_UNUSED(sr);
941  Q_UNUSED(flags);
942  stream() << "<image ";
943  stream() << "x=\""<<r.x()<<"\" "
944  "y=\""<<r.y()<<"\" "
945  "width=\""<<r.width()<<"\" "
946  "height=\""<<r.height()<<"\" "
947  "preserveAspectRatio=\"none\" ";
948 
950  QBuffer buffer(&data);
951  buffer.open(QBuffer::ReadWrite);
952  image.save(&buffer, "PNG");
953  buffer.close();
954  stream() << "xlink:href=\"data:image/png;base64,"
955  << data.toBase64()
956  <<"\" />\n";
957 }
958 
960 {
962  QPaintEngine::DirtyFlags flags = state.state();
963 
964  // always stream full gstate, which is not required, but...
965  flags |= QPaintEngine::AllDirty;
966 
967  // close old state and start a new one...
968  if (d->afterFirstUpdate)
969  *d->stream << "</g>\n\n";
970 
971  *d->stream << "<g ";
972 
973  if (flags & QPaintEngine::DirtyBrush) {
974  qbrushToSvg(state.brush());
975  }
976 
977  if (flags & QPaintEngine::DirtyPen) {
978  qpenToSvg(state.pen());
979  }
980 
981  if (flags & QPaintEngine::DirtyTransform) {
982  d->matrix = state.matrix();
983  *d->stream << "transform=\"matrix(" << d->matrix.m11() << ','
984  << d->matrix.m12() << ','
985  << d->matrix.m21() << ',' << d->matrix.m22() << ','
986  << d->matrix.dx() << ',' << d->matrix.dy()
987  << ")\""
988  << endl;
989  }
990 
991  if (flags & QPaintEngine::DirtyFont) {
992  qfontToSvg(state.font());
993  }
994 
995  if (flags & QPaintEngine::DirtyOpacity) {
996  if (!qFuzzyIsNull(state.opacity() - 1))
997  stream() << "opacity=\""<<state.opacity()<<"\" ";
998  }
999 
1000  *d->stream << '>' << endl;
1001 
1002  d->afterFirstUpdate = true;
1003 }
1004 
1006 {
1008 
1009  *d->stream << "<path vector-effect=\""
1010  << (state->pen().isCosmetic() ? "non-scaling-stroke" : "none")
1011  << "\" fill-rule=\""
1012  << (p.fillRule() == Qt::OddEvenFill ? "evenodd" : "nonzero")
1013  << "\" d=\"";
1014 
1015  for (int i=0; i<p.elementCount(); ++i) {
1016  const QPainterPath::Element &e = p.elementAt(i);
1017  switch (e.type) {
1019  *d->stream << 'M' << e.x << ',' << e.y;
1020  break;
1022  *d->stream << 'L' << e.x << ',' << e.y;
1023  break;
1025  *d->stream << 'C' << e.x << ',' << e.y;
1026  ++i;
1027  while (i < p.elementCount()) {
1028  const QPainterPath::Element &e = p.elementAt(i);
1030  --i;
1031  break;
1032  } else
1033  *d->stream << ' ';
1034  *d->stream << e.x << ',' << e.y;
1035  ++i;
1036  }
1037  break;
1038  default:
1039  break;
1040  }
1041  if (i != p.elementCount() - 1) {
1042  *d->stream << ' ';
1043  }
1044  }
1045 
1046  *d->stream << "\"/>" << endl;
1047 }
1048 
1049 void QSvgPaintEngine::drawPolygon(const QPointF *points, int pointCount,
1050  PolygonDrawMode mode)
1051 {
1052  Q_ASSERT(pointCount >= 2);
1053 
1054  //Q_D(QSvgPaintEngine);
1055 
1056  QPainterPath path(points[0]);
1057  for (int i=1; i<pointCount; ++i)
1058  path.lineTo(points[i]);
1059 
1060  if (mode == PolylineMode) {
1061  stream() << "<polyline fill=\"none\" vector-effect=\""
1062  << (state->pen().isCosmetic() ? "non-scaling-stroke" : "none")
1063  << "\" points=\"";
1064  for (int i = 0; i < pointCount; ++i) {
1065  const QPointF &pt = points[i];
1066  stream() << pt.x() << ',' << pt.y() << ' ';
1067  }
1068  stream() << "\" />" <<endl;
1069  } else {
1070  path.closeSubpath();
1071  drawPath(path);
1072  }
1073 }
1074 
1075 void QSvgPaintEngine::drawTextItem(const QPointF &pt, const QTextItem &textItem)
1076 {
1078  if (d->pen.style() == Qt::NoPen)
1079  return;
1080 
1081  const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem);
1083 
1084  *d->stream << "<text "
1085  "fill=\"" << d->attributes.stroke << "\" "
1086  "fill-opacity=\"" << d->attributes.strokeOpacity << "\" "
1087  "stroke=\"none\" "
1088  "xml:space=\"preserve\" "
1089  "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" ";
1090  qfontToSvg(textItem.font());
1091  *d->stream << " >"
1092  << Qt::escape(s)
1093  << "</text>"
1094  << endl;
1095 }
1096 
1098 
1099 #endif // QT_NO_SVGGENERATOR
ElementType type
the type of element
Definition: qpainterpath.h:81
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qstring.cpp:6448
void setResolution(int resolution)
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition: qcolor.h:67
double d
Definition: qnumeric_p.h:62
QPointF focalPoint() const
Returns the focal point of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2251
The QPainterPath::Element class specifies the position and type of a subpath.
Definition: qpainterpath.h:77
QImage toImage() const
Converts the pixmap to a QImage.
Definition: qpixmap.cpp:542
void setDocumentDescription(const QString &description)
QPaintEngine::DirtyFlags state() const
Returns a combination of flags identifying the set of properties that need to be updated when updatin...
Definition: qpaintengine.h:292
qreal y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:667
int resolution() const
qreal alphaF() const
Returns the alpha color component of this color.
Definition: qcolor.cpp:1106
unsigned int QRgb
Definition: qrgb.h:53
double qreal
Definition: qglobal.h:1193
static void translate_dashPattern(QVector< qreal > pattern, const qreal &width, QString *pattern_string)
qreal opacity() const
Returns the opacity in the current paint engine state.
Definition: qpainter.cpp:9529
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const QColor & color() const
Returns the brush color.
Definition: qbrush.h:183
int qCeil(qreal v)
Definition: qmath.h:63
const QGradient * gradient() const
Returns the gradient describing this brush.
Definition: qbrush.cpp:871
The QMatrix class specifies 2D transformations of a coordinate system.
Definition: qmatrix.h:61
const QChar * chars
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
Definition: qpainterpath.h:67
struct QSvgPaintEnginePrivate::_attributes attributes
Qt::PenStyle style() const
Returns the pen style.
Definition: qpen.cpp:428
CoordinateMode coordinateMode() const
Returns the coordinate mode of this gradient.
Definition: qbrush.cpp:1563
bool open(OpenMode openMode)
Reimplemented Function
Definition: qbuffer.cpp:338
void drawPath(const QPainterPath &path)
The default implementation ignores the path and does nothing.
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
void chop(int n)
Removes n characters from the end of the string.
Definition: qstring.cpp:4623
void close()
Reimplemented Function
Definition: qbuffer.cpp:359
The QPointF class defines a point in the plane using floating point precision.
Definition: qpoint.h:214
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
T1 first
Definition: qpair.h:65
void setOutputDevice(QIODevice *device)
T2 second
Definition: qpair.h:66
bool save(const QString &fileName, const char *format=0, int quality=-1) const
Saves the image to the file with the given fileName, using the given image file format and quality fa...
Definition: qimage.cpp:5346
QColor color() const
Returns the color of this pen&#39;s brush.
Definition: qpen.cpp:771
QTextStream & stream()
void qbrushToSvg(const QBrush &sbrush)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
static void translate_color(const QColor &color, QString *color_string, QString *opacity_string)
~QSvgGenerator()
Destroys the generator.
ushort red
Returns the red color component of this color.
Definition: qcolor.h:243
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:57
The QRadialGradient class is used in combination with QBrush to specify a radial gradient brush...
Definition: qbrush.h:297
qreal y
the y coordinate of the element&#39;s position.
Definition: qpainterpath.h:80
void qpenToSvg(const QPen &spen)
The QString class provides a Unicode character string.
Definition: qstring.h:83
QMatrix matrix() const
Returns the matrix in the current paint engine state.
Definition: qpainter.cpp:9355
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
#define Q_D(Class)
Definition: qglobal.h:2482
void setFileName(const QString &fileName)
The QPen class defines how a QPainter should draw lines and outlines of shapes.
Definition: qpen.h:64
static QString fromRawData(const QChar *, int size)
Constructs a QString that uses the first size Unicode characters in the array unicode.
Definition: qstring.cpp:7673
void drawTextItem(const QPointF &pt, const QTextItem &item)
This function draws the text item textItem at position p.
QVector< qreal > dashPattern() const
Returns the dash pattern of this pen.
Definition: qpen.cpp:466
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Definition: qpainterpath.h:402
InterpolationMode interpolationMode() const
Returns the interpolation mode of this gradient.
Definition: qbrush.cpp:1607
QIODevice * outputDevice() const
void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
Reimplement this virtual function to draw the polygon defined by the pointCount first points in point...
qreal x() const
Returns the x-coordinate of this point.
Definition: qpoint.h:282
QRectF viewBoxF() const
QPaintEngine * paintEngine() const
Returns the paint engine used to render graphics to be converted to SVG format information.
QSize size() const
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
QGradientStops stops() const
Returns the stop points for this gradient.
Definition: qbrush.cpp:1520
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QBrush brush() const
Returns the brush in the current paint engine state.
Definition: qpainter.cpp:9273
QRectF viewBox() const
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
static FILE * stream
static QColor fromRgba(QRgb rgba)
Static convenience function that returns a QColor constructed from the given QRgb value rgba...
Definition: qcolor.cpp:1974
void saveConicalGradientBrush(const QGradient *)
ImageConversionFlag
Definition: qnamespace.h:559
QString title() const
Q_STATIC_INLINE_FUNCTION uint PREMUL(uint x)
Qt::PenJoinStyle joinStyle() const
Returns the pen&#39;s join style.
Definition: qpen.cpp:736
Q_STATIC_INLINE_FUNCTION uint INTERPOLATE_PIXEL_256(uint x, uint a, uint y, uint b)
QFont font() const
Returns the font in the current paint engine state.
Definition: qpainter.cpp:9331
bool end()
Reimplement this function to finish painting on the current paint device.
qreal height() const
Returns the height of the rectangle.
Definition: qrect.h:710
void saveGradientUnits(QTextStream &str, const QGradient *gradient)
QString documentDescription() const
void append(const T &t)
Inserts value at the end of the vector.
Definition: qvector.h:573
Q_CORE_EXPORT void qWarning(const char *,...)
Internal QTextItem.
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
void saveGradientStops(QTextStream &str, const QGradient *g)
qreal width() const
Returns the width of the rectangle.
Definition: qrect.h:707
QString documentTitle() const
void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlag=Qt::AutoColor)
Qt::FillRule fillRule() const
Returns the painter path&#39;s currently set fill rule.
Qt::BrushStyle style() const
Returns the brush style.
Definition: qbrush.h:182
void setDescription(const QString &description)
void saveLinearGradientBrush(const QGradient *g)
The QPaintEngine class provides an abstract definition of how QPainter draws to a given device on a g...
Definition: qpaintengine.h:90
QPointF start() const
Returns the start point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1796
void setResolution(int dpi)
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
Q_GUI_EXPORT QString escape(const QString &plain)
Converts the plain text string plain to a HTML string with HTML metacharacters <, >...
void setSize(const QSize &size)
void setViewBox(const QRect &viewBox)
int width() const
Returns the pen width with integer precision.
Definition: qpen.cpp:630
QSize size() const
The QBrush class defines the fill pattern of shapes drawn by QPainter.
Definition: qbrush.h:76
QSvgGenerator()
Constructs a new generator.
static QPaintEngine::PaintEngineFeatures svgEngineFeatures()
void setDocumentTitle(const QString &title)
QPaintEngine::Type type() const
Reimplement this function to return the paint engine Type.
QString description() const
QString arg(qlonglong a, int fieldwidth=0, int base=10, const QChar &fillChar=QLatin1Char(' ')) const Q_REQUIRED_RESULT
Definition: qstring.cpp:7186
void setOutputDevice(QIODevice *outputDevice)
ushort blue
Returns the blue color component of this color.
Definition: qcolor.h:245
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
void setViewBox(const QRectF &viewBox)
The QTextStream class provides a convenient interface for reading and writing text.
Definition: qtextstream.h:73
The QLinearGradient class is used in combination with QBrush to specify a linear gradient brush...
Definition: qbrush.h:280
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
The QGradient class is used in combination with QBrush to specify gradient fills. ...
Definition: qbrush.h:201
qreal x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:664
int metric(QPaintDevice::PaintDeviceMetric metric) const
Reimplemented Function
QPair< qreal, QColor > QGradientStop
Definition: qbrush.h:196
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
qreal miterLimit() const
Returns the miter limit of the pen.
Definition: qpen.cpp:589
bool begin(QPaintDevice *device)
Reimplement this function to initialise your paint engine when painting is to start on the paint devi...
QString fileName() const
reference back()
This function is provided for STL compatibility.
Definition: qvector.h:289
void setSize(const QSize &size)
QString & fill(QChar c, int size=-1)
Sets every character in the string to character ch.
Definition: qstring.cpp:4641
QRect viewBox() const
qreal widthF() const
Returns the pen width with floating point precision.
Definition: qpen.cpp:645
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
qreal radius() const
Returns the radius of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2150
QByteArray toBase64() const
Returns a copy of the byte array, encoded as Base64.
static QTextCodec * codecForName(const QByteArray &name)
Searches all installed QTextCodec objects and returns the one which best matches name; the match is c...
QIODevice * outputDevice() const
qreal x
the x coordinate of the element&#39;s position.
Definition: qpainterpath.h:79
qreal y() const
Returns the y-coordinate of this point.
Definition: qpoint.h:287
QPointF center() const
Returns the center of this radial gradient in logical coordinates.
Definition: qbrush.cpp:2102
The QPixmap class is an off-screen image representation that can be used as a paint device...
Definition: qpixmap.h:71
QSvgPaintEngine * engine
qreal dashOffset() const
Returns the dash offset for the pen.
Definition: qpen.cpp:547
static Q_DECL_CONSTEXPR bool qFuzzyIsNull(double d)
Definition: qglobal.h:2043
The QPaintEngineState class provides information about the active paint engine&#39;s current state...
Definition: qpaintengine.h:289
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
#define Q_DECLARE_PRIVATE(Class)
Definition: qglobal.h:2467
int elementCount() const
Returns the number of path elements in the painter path.
Definition: qpainterpath.h:397
#define INV_PREMUL(p)
QPen pen() const
Returns the pen in the current paint engine state.
Definition: qpainter.cpp:9259
The QTextItem class provides all the information required to draw text in a custom paint engine...
Definition: qpaintengine.h:68
Qt::PenCapStyle capStyle() const
Returns the pen&#39;s cap style.
Definition: qpen.cpp:706
static const KeyPair *const end
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
#define qPrintable(string)
Definition: qglobal.h:1750
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
ushort green
Returns the green color component of this color.
Definition: qcolor.h:244
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
QFont font() const
Returns the font that should be used to draw the text.
void saveRadialGradientBrush(const QGradient *g)
The QSvgGenerator class provides a paint device that is used to create SVG drawings.
Definition: qsvggenerator.h:62
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
void setTitle(const QString &title)
Q_DECL_CONSTEXPR int qRound(qreal d)
Definition: qglobal.h:1203
void qfontToSvg(const QFont &sfont)
void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
Reimplement this function to draw the part of the pm specified by the sr rectangle in the given r...
QPointF finalStop() const
Returns the final stop point of this linear gradient in logical coordinates.
Definition: qbrush.cpp:1856
Q_CORE_EXPORT QTextStream & endl(QTextStream &s)
void updateState(const QPaintEngineState &state)
Reimplement this function to update the state of a paint engine.