📄 q3paintengine_svg.cpp
字号:
{ QPolygonF poly; for (int i = 0; i < pointCount; ++i) poly << points[i]; drawPolygon(poly.constData(), pointCount, mode);}void Q3SVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF & /* sr */){ Q_D(Q3SVGPaintEngine); QDomElement e = d->doc.createElement(QLatin1String("image")); e.setAttribute(QLatin1String("x"), r.x()); e.setAttribute(QLatin1String("y"), r.y()); e.setAttribute(QLatin1String("width"), r.width()); e.setAttribute(QLatin1String("height"), r.height()); QPixElement pe; pe.element = e; pe.pixmap = pm; d->pixmaps.append(pe); // saving to disk and setting the xlink:href attribute will be // done later in save() once we now the svg document name. d->appendChild(e, QPicturePrivate::PdcDrawPixmap);}void Q3SVGPaintEngine::drawTiledPixmap(const QRectF & /* r */, const QPixmap & /* pixmap */, const QPointF & /* s */){}void Q3SVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &ti){ Q_D(Q3SVGPaintEngine); QDomElement e = d->doc.createElement(QLatin1String("text"));// int x, y;// const QRect r(p.x(), p.y(), ti.width, ti.ascent + ti.descent); // horizontal text alignment // if ((ti.flags & Qt::AlignHCenter) != 0) {// x = r.x() + r.width() / 2;// e.setAttribute("text-anchor", "middle");// } else if ((textflags & Qt::AlignRight) != 0) {// x = r.right();// e.setAttribute("text-anchor", "end");// } else {// x = r.x();// }// // vertical text alignment// if ((textflags & Qt::AlignVCenter) != 0)// y = r.y() + (r.height() + ti.ascent) / 2;// else if ((textflags & Qt::AlignBottom) != 0)// y = r.bottom();// else// y = r.y() + ti.ascent;// if (x)// e.setAttribute("x", x);// if (y)// e.setAttribute("y", y); e.setAttribute(QLatin1String("x"), p.x()); e.setAttribute(QLatin1String("y"), p.y()); e.appendChild(d->doc.createTextNode(ti.text()));}void Q3SVGPaintEngine::drawImage(const QRectF &r, const QImage &im, const QRectF &, Qt::ImageConversionFlags){ Q_D(Q3SVGPaintEngine); QDomElement e = d->doc.createElement(QLatin1String("image")); e.setAttribute(QLatin1String("x"), r.x()); e.setAttribute(QLatin1String("y"), r.y()); e.setAttribute(QLatin1String("width"), r.width()); e.setAttribute(QLatin1String("height"), r.height()); QImgElement ie; ie.element = e; ie.image = im; d->images.append(ie); // saving to disk and setting the xlink:href attribute will be // done later in save() once we now the svg document name. d->appendChild(e, QPicturePrivate::PdcDrawImage);}/*! Returns the SVG as a single string of XML.*/QString Q3SVGPaintEngine::toString() const{ Q_D(const Q3SVGPaintEngine); if (d->doc.isNull()) return QString(); return d->doc.toString();}/*! Saves the SVG to \a fileName.*/bool Q3SVGPaintEngine::save(const QString &fileName){ Q_D(Q3SVGPaintEngine); // guess svg id from fileName QString svgName = fileName.endsWith(QLatin1String(".svg")) ? fileName.left(fileName.length()-4) : fileName; // now we have the info about name and dimensions available QDomElement root = d->doc.documentElement(); root.setAttribute(QLatin1String("id"), svgName); // the standard doesn't take respect x and y. But we want a // proper bounding rect. We make width and height bigger when // writing out and subtract x and y when reading in. root.setAttribute(QLatin1String("x"), d->brect.x()); root.setAttribute(QLatin1String("y"), d->brect.y()); root.setAttribute(QLatin1String("width"), d->brect.width() + d->brect.x()); root.setAttribute(QLatin1String("height"), d->brect.height() + d->brect.y()); // ... and know how to name any image files to be written out int icount = 0; ImageList::Iterator iit = d->images.begin(); for (; iit != d->images.end(); ++iit) { QString href = QString(QLatin1String("%1_%2.png")).arg(svgName).arg(icount); (*iit).image.save(href, "PNG"); (*iit).element.setAttribute(QLatin1String("xlink:href"), href); icount++; } PixmapList::Iterator pit = d->pixmaps.begin(); for (; pit != d->pixmaps.end(); ++pit) { QString href = QString(QLatin1String("%1_%2.png")).arg(svgName).arg(icount); (*pit).pixmap.save(href, "PNG"); (*pit).element.setAttribute(QLatin1String("xlink:href"), href); icount++; } QFile f(fileName); if (!f.open (QIODevice::WriteOnly)) return false; QTextStream s(&f); s.setEncoding(QTextStream::UnicodeUTF8); s << d->doc; return true;}/*! \overload \a dev is the device to use for saving.*/bool Q3SVGPaintEngine::save(QIODevice *dev){ Q_D(Q3SVGPaintEngine);#if defined(CHECK_RANGE) if (!d->images.isEmpty() || !d->pixmaps.isEmpty()) qWarning("Q3SVGPaintEngine::save: skipping external images");#endif QTextStream s(dev); s.setEncoding(QTextStream::UnicodeUTF8); s << d->doc; return true;}/*! Sets the bounding rectangle of the SVG to rectangle \a r.*/void Q3SVGPaintEngine::setBoundingRect(const QRect &r){ d_func()->brect = r;}/*! Returns the SVG's bounding rectangle.*/QRect Q3SVGPaintEngine::boundingRect() const{ return d_func()->brect;}/*! Loads and parses a SVG from \a dev into the device. Returns true on success (i.e. loaded and parsed without error); otherwise returns false.*/bool Q3SVGPaintEngine::load(QIODevice *dev){ return d_func()->doc.setContent(dev);}void Q3SVGPaintEnginePrivate::appendChild(QDomElement &e, QPicturePrivate::PaintCommand c){ if (!e.isNull()) { current.appendChild(e); if (c == QPicturePrivate::PdcSave) current = e; // ### optimize application of attributes utilizing <g> if (c == QPicturePrivate::PdcSetClipRegion || c == QPicturePrivate::PdcSetClipPath) { QDomElement ne; ne = doc.createElement(QLatin1String("g")); ne.setAttribute(QLatin1String("style"), QString(QLatin1String("clip-path:url(#clip%1)")).arg(currentClip)); if (dirtyTransform) { applyTransform(&ne); dirtyTransform = false; } current.appendChild(ne); current = ne; } else { if (dirtyStyle) // only reset when entering applyStyle(&e, c); // or leaving a <g> tag if (dirtyTransform && e.tagName() != QLatin1String("g")) { // same as above but not for <g> tags applyTransform(&e); if (c == QPicturePrivate::PdcSave) dirtyTransform = false; } } }}void Q3SVGPaintEnginePrivate::applyStyle(QDomElement *e, QPicturePrivate::PaintCommand c) const{ // ### do not write every attribute each time QColor pcol = cpen.color(); QColor bcol = cbrush.color(); QString s; if (c == QPicturePrivate::PdcDrawText2 || c == QPicturePrivate::PdcDrawText2Formatted) { // QPainter has a reversed understanding of pen/stroke vs. // brush/fill for text s += QString(QLatin1String("fill:rgb(%1,%2,%3);")).arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); s += QString(QLatin1String("stroke-width:0;")); QFont f = cfont; QFontInfo fi(f); s += QString(QLatin1String("font-size:%1;")).arg(fi.pointSize()); s += QString(QLatin1String("font-style:%1;")).arg(f.italic() ? QLatin1String("italic") : QLatin1String("normal")); // not a very scientific distribution QString fw; if (f.weight() <= QFont::Light) fw = QLatin1String("100"); else if (f.weight() <= QFont::Normal) fw = QLatin1String("400"); else if (f.weight() <= QFont::DemiBold) fw = QLatin1String("600"); else if (f.weight() <= QFont::Bold) fw = QLatin1String("700"); else if (f.weight() <= QFont::Black) fw = QLatin1String("800"); else fw = QLatin1String("900"); s += QString(QLatin1String("font-weight:%1;")).arg(fw); s += QString(QLatin1String("font-family:%1;")).arg(f.family()); } else { s += QString(QLatin1String("stroke:rgb(%1,%2,%3);")).arg(pcol.red()).arg(pcol.green()).arg(pcol.blue()); if (pcol.alpha() != 255) s += QString(QLatin1String("stroke-opacity:%1;")).arg(pcol.alpha()/255.0); if (bcol.alpha() != 255) s += QString(QLatin1String("fill-opacity:%1;")).arg(bcol.alpha()/255.0); double pw = cpen.width(); if (pw == 0 && cpen.style() != Qt::NoPen) pw = 0.9; if (c == QPicturePrivate::PdcDrawLine) pw /= (qAbs(worldMatrix.m11()) + qAbs(worldMatrix.m22())) / 2.0; s += QString(QLatin1String("stroke-width:%1;")).arg(pw); if (cpen.style() == Qt::DashLine) s+= QString(QLatin1String("stroke-dasharray:18,6;")); else if (cpen.style() == Qt::DotLine) s+= QString(QLatin1String("stroke-dasharray:3;")); else if (cpen.style() == Qt::DashDotLine) s+= QString(QLatin1String("stroke-dasharray:9,6,3,6;")); else if (cpen.style() == Qt::DashDotDotLine) s+= QString(QLatin1String("stroke-dasharray:9,3,3;")); if (cbrush.style() == Qt::NoBrush || c == QPicturePrivate::PdcDrawPolyline || c == QPicturePrivate::PdcDrawCubicBezier) s += QLatin1String("fill:none;"); // Qt polylines use no brush, neither do Beziers else s += QString(QLatin1String("fill:rgb(%1,%2,%3);")).arg(bcol.red()).arg(bcol.green()).arg(bcol.blue()); } e->setAttribute(QLatin1String("style"), s);}void Q3SVGPaintEnginePrivate::applyTransform(QDomElement *e) const{ QMatrix m = worldMatrix; QString s; bool rot = (m.m11() != 1.0 || m.m12() != 0.0 || m.m21() != 0.0 || m.m22() != 1.0); if (!rot && (m.dx() != 0.0 || m.dy() != 0.0)) { s = QString(QLatin1String("translate(%1,%2)")).arg(m.dx()).arg(m.dy()); } else if (rot) { if (m.m12() == 0.0 && m.m21() == 0.0 && m.dx() == 0.0 && m.dy() == 0.0) s = QString(QLatin1String("scale(%1,%2)")).arg(m.m11()).arg(m.m22()); else s = QString(QLatin1String("matrix(%1,%2,%3,%4,%5,%6)")) .arg(m.m11()).arg(m.m12()) .arg(m.m21()).arg(m.m22()) .arg(m.dx()).arg(m.dy()); } else { return; } e->setAttribute(QLatin1String("transform"), s);}bool Q3SVGPaintEngine::play(QPainter *pt){ Q_D(Q3SVGPaintEngine); if (!pt) { Q_ASSERT(pt); return false; } if (d->dev == 0) d->dev = pt->device(); d->wwidth = pt->window().width(); d->wheight = pt->window().height(); pt->setPen(Qt::NoPen); // SVG default pen and brush pt->setBrush(Qt::black); if (d->doc.isNull()) { qWarning("Q3SVGPaintEngine::play: No SVG data set."); return false; } QDomNode svg = d->doc.namedItem(QLatin1String("svg")); if (svg.isNull() || !svg.isElement()) { qWarning("Q3SVGPaintEngine::play: Couldn't find any svg element."); return false; } // force transform to be activated in case our sequences // are replayed later with a transformed painter pt->setWorldXForm(true); QDomNamedNodeMap attr = svg.attributes(); int x = d->lenToInt(attr, QLatin1String("x")); int y = d->lenToInt(attr, QLatin1String("y")); d->brect.setX(x); d->brect.setY(y); QString wstr = attr.contains(QLatin1String("width")) ? attr.namedItem(QLatin1String("width")).nodeValue() : QString(QLatin1String("100%")); QString hstr = attr.contains(QLatin1String("height")) ? attr.namedItem(QLatin1String("height")).nodeValue() : QString(QLatin1String("100%")); double width = d->parseLen(wstr, 0, true); double height = d->parseLen(hstr, 0, false); // SVG doesn't respect x and y. But we want a proper bounding rect. d->brect.setWidth(int(width) - x); d->brect.setHeight(int(height) - y); pt->setClipRect(d->brect); if (attr.contains(QLatin1String("viewBox"))) { QRegExp re(QString::fromLatin1("\\s*(\\S+)\\s*,?\\s*(\\S+)\\s*,?"), "\\s*(\\S+)\\s*,?\\s*(\\S+)\\s*"); if (re.indexIn(attr.namedItem(QLatin1String("viewBox")).nodeValue()) < 0) { qWarning("Q3SVGPaintEngine::play: Invalid viewBox attribute."); return false; } else { double x = re.cap(1).toDouble(); double y = re.cap(2).toDouble(); double w = re.cap(3).toDouble(); double h = re.cap(4).toDouble(); if (w < 0 || h < 0) { qWarning("Q3SVGPaintEngine::play: Invalid viewBox dimension."); return false; } else if (w == 0 || h == 0) { return true; } pt->scale(width/w, height/h); pt->translate(-x, -y); } } const struct ElementTable { const char *name; ElementType type; } etab[] = { {"a", AnchorElement }, {"#comment", CommentElement }, {"circle", CircleElement }, {"clipPath", ClipElement }, {"desc", DescElement },
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -