31 #include <QApplication>
32 #include <QFontDatabase>
49 m_printer.setOutputFormat (QPrinter::PdfFormat);
84 QStringList coords = str.split (
",");
85 for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 1)
87 double pt = (*p).toDouble ();
96 QStringList coords = str.split (
",");
97 for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 1)
99 double pt = (*p).toDouble ();
108 QVector<QPointF> pts;
109 str = str.trimmed ();
110 str.replace (
" ",
",");
111 QStringList coords = str.split (
",");
112 for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 2)
114 QPointF pt ((*p).toDouble (), (*(p+1)).toDouble ());
123 str = str.trimmed ();
124 str.replace (
" ",
",");
125 QStringList coords = str.split (
",");
126 for (QStringList::iterator p = coords.begin (); p != coords.end (); p += 2)
128 QPoint pt ((*p).toDouble (), (*(p+1)).toDouble ());
138 QRegExp rx (field +
"\\(([^\\)]*)\\)");
140 pos = rx.indexIn (str, pos);
171 QVector<bool> unused;
173 unused.push_back (
false);
180 for (
auto ii = 0; ii <
m_polygons.count (); ii++)
185 for (
auto jj = ii+1; jj <
m_polygons.count (); jj++)
190 if (newpoly.count ())
204 for (
auto ii = 0; ii <
m_polygons.count (); ii++)
207 tryagain = ! unused[ii];
209 while (tryagain && polygon.count () > 4)
214 for (
auto jj = 1; jj < (polygon.count () - 1); jj++)
215 if (polygon[jj-1] == polygon[jj+1])
217 if (! del.contains (jj))
220 del.push_front (jj+1);
224 polygon.remove (idx);
245 for (
int ii = 0; ii <
m_polygons.count (); ii++)
248 if (! unused[ii] && polygon.count () > 2)
249 retval.push_back (polygon);
256 bool eq (QPointF p1, QPointF p2)
258 return ((qAbs (p1.x () - p2.x ())
259 <= 0.00001 * qMin (qAbs (p1.x ()), qAbs (p2.x ())))
260 && (qAbs (p1.y () - p2.y ())
261 <= 0.00001 * qMin (qAbs (p1.y ()), qAbs (p2.y ()))));
268 poly1.push_back (poly1[0]);
269 poly2.push_back (poly2[0]);
271 for (
int ii = 0; ii < (poly1.size () - 1); ii++)
273 for (
int jj = 0; jj < (poly2.size () - 1); jj++)
275 bool forward = (
eq (poly1[ii], poly2[jj])
276 &&
eq (poly1[ii+1], poly2[jj+1]));
277 bool backward = ! forward && (
eq (poly1[ii], poly2[jj+1])
278 &&
eq (poly1[ii+1], poly2[jj]));
280 if (forward || backward)
287 for (
int kk = 0; kk < (ii+1); kk++)
288 merged.push_back (poly1[kk]);
291 std::rotate (poly2.begin (), poly2.begin () + jj, poly2.end ());
292 poly2.erase (poly2.begin ());
293 poly2.erase (poly2.begin ());
296 for (
int kk = poly2.size (); kk > 0; kk--)
297 merged.push_back (poly2[kk-1]);
299 for (
int kk = 0; kk < poly2.size (); kk++)
300 merged.push_back (poly2[kk]);
302 for (
int kk = ii+1; kk < poly1.size (); kk++)
303 merged.push_back (poly1[kk]);
306 QPolygonF out (merged.size ());
307 for (
int kk = 0; kk < merged.size (); kk++)
308 out[kk] = merged[kk];
337 QDomNodeList nodes = parent_elt.childNodes ();
339 static QString clippath_id;
345 static double dx = 0, dy = 0;
347 for (
int i = 0; i < nodes.count (); i++)
349 QDomNode node = nodes.at (i);
350 if (! node.isElement ())
353 QDomElement elt = node.toElement ();
355 if (elt.tagName () ==
"clipPath")
357 clippath_id =
"#" + elt.attribute (
"id");
359 clippath_id = QString ();
361 else if (elt.tagName () ==
"g")
363 bool current_clipstate = painter.hasClipping ();
364 QRegion current_clippath = painter.clipRegion ();
366 QString str = elt.attribute (
"clip-path");
367 if (! str.isEmpty ())
369 QVector<QPoint> pts = clippath[
get_field (str,
"url")];
370 if (! pts.isEmpty ())
372 painter.setClipRegion (QRegion (QPolygon (pts)));
373 painter.setClipping (
true);
380 painter.setClipRegion (current_clippath);
381 painter.setClipping (current_clipstate);
383 else if (elt.tagName () ==
"text")
387 QString str = elt.attribute (
"font-family");
388 if (! str.isEmpty ())
389 font.setFamily (elt.attribute (
"font-family"));
391 str = elt.attribute (
"font-weight");
392 if (! str.isEmpty () && str !=
"normal")
393 font.setWeight (QFont::Bold);
395 str = elt.attribute (
"font-style");
396 if (! str.isEmpty () && str !=
"normal")
397 font.setStyle (QFont::StyleItalic);
399 str = elt.attribute (
"font-size");
400 if (! str.isEmpty ())
401 font.setPixelSize (str.toDouble ());
403 painter.setFont (font);
407 str =
get_field (elt.attribute (
"transform"),
"translate");
408 if (! str.isEmpty ())
410 QStringList trans = str.split (
",");
411 dx = trans[0].toDouble ();
412 dy = trans[1].toDouble ();
414 str =
get_field (elt.attribute (
"transform"),
"rotate");
415 if (! str.isEmpty ())
417 QStringList rot = str.split (
",");
418 painter.translate (dx+rot[1].toDouble (),
419 dy+rot[2].toDouble ());
420 painter.rotate (rot[0].toDouble ());
421 dx = rot[1].toDouble ();
422 dy = rot[2].toDouble ();
426 painter.translate (dx, dy);
435 else if (elt.tagName () ==
"tspan")
438 QFont saved_font (font);
440 QString str = elt.attribute (
"font-family");
441 if (! str.isEmpty ())
442 font.setFamily (elt.attribute (
"font-family"));
444 str = elt.attribute (
"font-weight");
445 if (! str.isEmpty ())
448 font.setWeight (QFont::Bold);
450 font.setWeight (QFont::Normal);
453 str = elt.attribute (
"font-style");
454 if (! str.isEmpty ())
457 font.setStyle (QFont::StyleItalic);
459 font.setStyle (QFont::StyleNormal);
462 str = elt.attribute (
"font-size");
463 if (! str.isEmpty ())
464 font.setPixelSize (str.toDouble ());
466 painter.setFont (font);
469 str =
get_field (elt.attribute (
"fill"),
"rgb");
470 if (! str.isEmpty ())
472 QStringList clist = str.split (
",");
473 painter.setPen (QColor (clist[0].toInt (), clist[1].toInt (),
477 QStringList xx = elt.attribute (
"x").split (
" ");
478 int y = elt.attribute (
"y").toInt ();
480 if (! str.isEmpty ())
483 foreach (QString s, xx)
484 if (ii < str.size ())
485 painter.drawText (s.toInt ()-dx, y-dy, str.at (ii++));
491 else if (elt.tagName () ==
"polyline")
494 QColor c (elt.attribute (
"stroke"));
495 QString str = elt.attribute (
"stroke-opacity");
496 if (! str.isEmpty () && str.toDouble () != 1.0
497 && str.toDouble () >= 0.0)
498 c.setAlphaF (str.toDouble ());
504 str = elt.attribute (
"stroke-width");
505 if (! str.isEmpty ())
507 double w = str.toDouble () * painter.
get_scale ();
512 str = elt.attribute (
"stroke-linecap");
513 pen.setCapStyle (Qt::SquareCap);
515 pen.setCapStyle (Qt::RoundCap);
516 else if (str ==
"butt")
517 pen.setCapStyle (Qt::FlatCap);
519 str = elt.attribute (
"stroke-linejoin");
520 pen.setJoinStyle (Qt::MiterJoin);
522 pen.setJoinStyle (Qt::RoundJoin);
523 else if (str ==
"bevel")
524 pen.setJoinStyle (Qt::BevelJoin);
526 str = elt.attribute (
"stroke-dasharray");
527 pen.setStyle (Qt::SolidLine);
528 if (! str.isEmpty ())
531 if (pat.count () != 2 || pat[1] != 0)
537 pen.setDashPattern (pat);
541 painter.setPen (pen);
544 else if (elt.tagName () ==
"image")
547 QString href_att = elt.attribute (
"xlink:href");
548 QString prefix (
"data:image/png;base64,");
550 = QByteArray::fromBase64 (href_att.mid (prefix.length ()).toLatin1 ());
552 if (img.loadFromData (data,
"PNG"))
554 QRect pos(elt.attribute (
"x").toInt (),
555 elt.attribute (
"y").toInt (),
556 elt.attribute (
"width").toInt (),
557 elt.attribute (
"height").toInt ());
561 QString str =
get_field (elt.attribute (
"transform"),
"matrix");
562 if (! str.isEmpty ())
566 QTransform tform(
m[0]*scl,
m[1]*scl,
m[2]*scl,
567 m[3]*scl,
m[4]*scl,
m[5]*scl);
568 painter.setTransform (tform);
571 painter.setRenderHint (QPainter::Antialiasing,
false);
572 painter.drawImage (pos, img);
573 painter.setRenderHint (QPainter::Antialiasing,
true);
577 else if (elt.tagName () ==
"polygon")
579 if (! clippath_id.isEmpty ())
583 QString str = elt.attribute (
"fill");
584 if (! str.isEmpty ())
588 str = elt.attribute (
"fill-opacity");
589 if (! str.isEmpty () && str.toDouble () != 1.0
590 && str.toDouble () >= 0.0)
591 color.setAlphaF (str.toDouble ());
597 painter.setBrush (color);
598 painter.setPen (Qt::NoPen);
600 painter.setRenderHint (QPainter::Antialiasing,
false);
601 painter.drawPolygon (p);
602 painter.setRenderHint (QPainter::Antialiasing,
true);
616 if (! orig.count () || (orig.count () == polygons.count ()))
619 QDomNode last = orig.last ();
620 for (
int ii = 0; ii < polygons.count (); ii++)
622 QPolygonF polygon = polygons[ii];
624 QDomNode node = last.cloneNode ();
628 for (
int jj = 0; jj < polygon.count (); jj++)
630 pts += QString (
"%1,%2 ").arg (polygon[jj].
x ())
631 .arg (polygon[jj].y ());
634 node.toElement ().setAttribute (
"points", pts.trimmed ());
636 if (! last.isNull ())
637 last = parent_elt.insertAfter (node, last);
640 for (
int ii = 0; ii < orig.count (); ii++)
641 parent_elt.removeChild (orig.at (ii));
646 QDomNodeList nodes = parent_elt.childNodes ();
647 QColor current_color;
654 for (
int ii = 0; ii < nodes.count (); ii++)
656 QDomNode node = nodes.at (ii);
657 if (! node.isElement ())
660 QDomElement elt = node.toElement ();
662 if (elt.tagName () ==
"polygon")
664 QString str = elt.attribute (
"fill");
665 if (! str.isEmpty ())
668 str = elt.attribute (
"fill-opacity");
669 if (! str.isEmpty ())
671 double alpha = str.toDouble ();
672 if (alpha != 1.0 && str.toDouble () >= 0.0)
673 color.setAlphaF (alpha);
676 if (! current_polygon.
count ())
677 current_color = color;
679 if (color != current_color)
684 (replaced_nodes, polygons));
686 replaced_nodes.clear ();
687 current_polygon.
reset ();
689 current_color = color;
693 current_polygon.
add (p);
694 replaced_nodes.push_back (node);
699 if (current_polygon.
count ())
703 (replaced_nodes, polygons));
704 replaced_nodes.clear ();
705 current_polygon.
reset ();
715 for (
int ii = 0; ii < collection.count (); ii++)
719 int main(
int argc,
char *argv[])
721 const char *doc =
"See \"octave-svgconvert -h\"";
722 const char *help =
"Usage:\n\
723 octave-svgconvert infile fmt dpi font reconstruct outfile\n\n\
724 Convert svg file to pdf, or svg. All arguments are mandatory:\n\
725 * infile: input svg file or \"-\" to indicate that the input svg file should be \
727 * fmt: format of the output file. May be one of pdf or svg\n\
728 * dpi: device dependent resolution in screen pixel per inch\n\
729 * font: specify a file name for the default FreeSans font\n\
730 * reconstruct: specify whether to reconstruct triangle to polygons (0 or 1)\n\
731 * outfile: output file name\n";
733 if (
strcmp (argv[1],
"-h") == 0)
746 if (
strcmp (argv[1],
"-") != 0)
749 file.setFileName (argv[1]);
750 if (! file.open (QIODevice::ReadOnly | QIODevice::Text))
752 std::cerr <<
"Unable to open file " << argv[1] <<
"\n";
760 if (! file.open (stdin, QIODevice::ReadOnly | QIODevice::Text))
762 std::cerr <<
"Unable read from stdin\n";
769 QDomDocument document;
771 if (! document.setContent (&file,
false, &msg))
773 std::cerr <<
"Failed to parse XML contents" << std::endl
774 << msg.toStdString ();
783 if (
strcmp (argv[2],
"pdf") != 0 &&
strcmp (argv[2],
"svg") != 0)
785 std::cerr <<
"Unhandled output file format " << argv[2] <<
"\n";
791 double dpi = QString (argv[3]).toDouble ();
794 std::cerr <<
"DPI must be positive\n";
800 QDomElement root = document.firstChildElement();
801 double x0, y0, dx, dy;
802 QString s = root.attribute (
"viewBox");
803 QTextStream (&s) >> x0 >> y0 >> dx >> dy;
804 QRectF vp (x0, y0, dx, dy);
810 if (!
strcmp (argv[2],
"pdf"))
812 QFont font (
"FreeSans");
813 if (! font.exactMatch ())
815 QString fontpath (argv[4]);
816 if (! fontpath.isEmpty ())
818 int id = QFontDatabase::addApplicationFont (fontpath);
820 std::cerr <<
"warning: print: "
821 "Unable to add default font to database\n";
824 std::cerr <<
"warning: print: FreeSans font not found\n";
832 std::cerr <<
"Could not open temporary file\n";
837 if (QString (argv[5]).toInt ())
841 if (!
strcmp (argv[2],
"pdf"))
844 pdfpainter painter (fout.fileName (), vp, dpi);
846 draw (root, painter);
852 QTextStream out (&fout);
853 out.setCodec (
"UTF-8");
854 out << document.toByteArray ();
858 if (QFile::exists (argv[6]))
859 if (! QFile::remove (argv[6]))
861 std::cerr <<
"Unable to replace existing file " << argv[6] <<
"\n";
QList< QPolygonF > reconstruct(void)
static bool eq(QPointF p1, QPointF p2)
octave_polygon(QPolygonF p)
static QPolygonF mergepoly(QPolygonF poly1, QPolygonF poly2)
QList< QPolygonF > m_polygons
double get_scale(void) const
pdfpainter(QString fname, QRectF sizepix, double dpi)
QRectF get_rectf(void) const
QString get_fname(void) const
QRect get_rect(void) const
void scale(Matrix &m, double x, double y, double z)
F77_RET_T const F77_DBLE * x
std::complex< double > w(std::complex< double > z, double relerr=0)
bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
int main(int argc, char *argv[])
QString get_field(QString str, QString field)
QVector< double > qstr2vectord(QString str)
QVector< double > qstr2vectorf(QString str)
void replace_polygons(QDomElement &parent_elt, QList< QDomNode > orig, QList< QPolygonF > polygons)
QVector< QPointF > qstr2ptsvector(QString str)
void reconstruct_polygons(QDomElement &parent_elt)
QVector< QPoint > qstr2ptsvectord(QString str)
void draw(QDomElement &parent_elt, pdfpainter &painter)
octave_value::octave_value(const Array< char > &chm, char type) return retval