📄 qsvggenerator.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtSVG module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qsvggenerator.h"#include "qpainterpath.h"#include "private/qpaintengine_p.h"#include "private/qtextengine_p.h"#include "qfile.h"#include "qtextstream.h"#include "qbuffer.h"#include "qdebug.h"static void translate_color(const QColor &color, QString *color_string, QString *opacity_string){ Q_ASSERT(color_string); Q_ASSERT(opacity_string); *color_string = QString::fromLatin1("#%1%2%3") .arg(color.red(), 2, 16, QLatin1Char('0')) .arg(color.green(), 2, 16, QLatin1Char('0')) .arg(color.blue(), 2, 16, QLatin1Char('0')); *opacity_string = QString::number(color.alphaF());}static void translate_dashPattern(QVector<qreal> pattern, const qreal& width, QString *pattern_string){ Q_ASSERT(pattern_string); // Note that SVG operates in absolute lengths, whereas Qt uses a length/width ratio. foreach (qreal entry, pattern) *pattern_string += QString::fromLatin1("%1,").arg(entry * width); pattern_string->chop(1);}class QSvgPaintEnginePrivate : public QPaintEnginePrivate{public: QSvgPaintEnginePrivate() { size = QSize(100, 100); outputDevice = 0; resolution = 72; attributes.document_title = QLatin1String("Qt Svg Document"); attributes.document_description = QLatin1String("Generated with Qt"); attributes.font_family = QLatin1String("serif"); attributes.font_size = QLatin1String("10pt"); attributes.font_style = QLatin1String("normal"); attributes.font_weight = QLatin1String("normal"); afterFirstUpdate = false; numGradients = 0; } QSize size; QIODevice *outputDevice; QTextStream *stream; int resolution; QString header; QString defs; QString body; bool afterFirstUpdate; QBrush brush; QPen pen; QMatrix matrix; QFont font; QString generateGradientName() { ++numGradients; currentGradientName = QString::fromLatin1("gradient%1").arg(numGradients); return currentGradientName; } QString currentGradientName; int numGradients; struct _attributes { QString document_title; QString document_description; QString font_weight; QString font_size; QString font_family; QString font_style; QString stroke, strokeOpacity; QString dashPattern, dashOffset; QString fill, fillOpacity; } attributes;};static inline QPaintEngine::PaintEngineFeatures svgEngineFeatures(){ return QPaintEngine::PaintEngineFeatures( QPaintEngine::AllFeatures & ~QPaintEngine::PatternBrush & ~QPaintEngine::PerspectiveTransform & ~QPaintEngine::ConicalGradientFill & ~QPaintEngine::PorterDuff);}class QSvgPaintEngine : public QPaintEngine{ Q_DECLARE_PRIVATE(QSvgPaintEngine)public: QSvgPaintEngine() : QPaintEngine(*new QSvgPaintEnginePrivate, svgEngineFeatures()) { } bool begin(QPaintDevice *device); bool end(); void updateState(const QPaintEngineState &state); void popGroup(); void drawPath(const QPainterPath &path); void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); void drawTextItem(const QPointF &pt, const QTextItem &item); void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, Qt::ImageConversionFlag = Qt::AutoColor); QPaintEngine::Type type() const { return QPaintEngine::SVG; } QSize size() const { return d_func()->size; } void setSize(const QSize &size) { Q_ASSERT(!isActive()); d_func()->size = size; } QIODevice *outputDevice() const { return d_func()->outputDevice; } void setOutputDevice(QIODevice *device) { Q_ASSERT(!isActive()); d_func()->outputDevice = device; } int resolution() { return d_func()->resolution; } void setResolution(int resolution) { Q_ASSERT(!isActive()); d_func()->resolution = resolution; } void saveLinearGradientBrush(const QGradient *g) { QTextStream str(&d_func()->defs, QIODevice::Append); const QLinearGradient *grad = static_cast<const QLinearGradient*>(g); str << QLatin1String("<linearGradient "); saveGradientUnits(str, g); if (grad) { str << QLatin1String("x1=\"") <<grad->start().x()<< QLatin1String("\" ") << QLatin1String("y1=\"") <<grad->start().y()<< QLatin1String("\" ") << QLatin1String("x2=\"") <<grad->finalStop().x() << QLatin1String("\" ") << QLatin1String("y2=\"") <<grad->finalStop().y() << QLatin1String("\" "); } str << QLatin1String("id=\"") << d_func()->generateGradientName() << QLatin1String("\">\n"); saveGradientStops(str, g); str << QLatin1String("</linearGradient>") <<endl; } void saveRadialGradientBrush(const QGradient *g) { QTextStream str(&d_func()->defs, QIODevice::Append); const QRadialGradient *grad = static_cast<const QRadialGradient*>(g); str << QLatin1String("<radialGradient "); saveGradientUnits(str, g); if (grad) { str << QLatin1String("cx=\"") <<grad->center().x()<< QLatin1String("\" ") << QLatin1String("cy=\"") <<grad->center().y()<< QLatin1String("\" ") << QLatin1String("r=\"") <<grad->radius() << QLatin1String("\" ") << QLatin1String("fx=\"") <<grad->focalPoint().x() << QLatin1String("\" ") << QLatin1String("fy=\"") <<grad->focalPoint().y() << QLatin1String("\" "); } str << QLatin1String("xml:id=\"") <<d_func()->generateGradientName()<< QLatin1String("\">\n"); saveGradientStops(str, g); str << QLatin1String("</radialGradient>") << endl; } void saveConicalGradientBrush(const QGradient *) { qWarning("svg's don't support conical gradients!"); } void saveGradientStops(QTextStream &str, const QGradient *g) { QGradientStops stops = g->stops(); foreach(QGradientStop stop, stops) { QString color = QString::fromLatin1("#%1%2%3") .arg(stop.second.red(), 2, 16, QLatin1Char('0')) .arg(stop.second.green(), 2, 16, QLatin1Char('0')) .arg(stop.second.blue(), 2, 16, QLatin1Char('0')); str << QLatin1String(" <stop offset=\"")<< stop.first << QLatin1String("\" ") << QLatin1String("stop-color=\"") << color << QLatin1String("\" ") << QLatin1String("stop-opacity=\"") << stop.second.alphaF() <<QLatin1String("\" />\n"); } } void saveGradientUnits(QTextStream &str, const QGradient *gradient) { str << QLatin1String("gradientUnits=\""); if (gradient && gradient->coordinateMode() == QGradient::ObjectBoundingMode) str << QLatin1String("objectBoundingBox"); else str << QLatin1String("userSpaceOnUse"); str << QLatin1String("\" "); } void generateQtDefaults() { *d_func()->stream << QLatin1String("fill=\"none\" "); *d_func()->stream << QLatin1String("stroke=\"black\" "); *d_func()->stream << QLatin1String("vector-effect=\"non-scaling-stroke\" "); *d_func()->stream << QLatin1String("stroke-width=\"1\" "); *d_func()->stream << QLatin1String("fill-rule=\"evenodd\" "); *d_func()->stream << QLatin1String("stroke-linecap=\"square\" "); *d_func()->stream << QLatin1String("stroke-linejoin=\"bevel\" "); *d_func()->stream << QLatin1String(">\n"); } inline QTextStream &stream() { return *d_func()->stream; } void qpenToSvg(const QPen &spen) { QString width; d_func()->pen = spen; switch (spen.style()) { case Qt::NoPen: stream() << QLatin1String("stroke=\"none\" "); d_func()->attributes.stroke = QLatin1String("none"); d_func()->attributes.strokeOpacity = QString(); return; break; case Qt::SolidLine: { QString color, colorOpacity; translate_color(spen.color(), &color, &colorOpacity); d_func()->attributes.stroke = color; d_func()->attributes.strokeOpacity = colorOpacity; stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" "); stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" "); } break; case Qt::DashLine: case Qt::DotLine: case Qt::DashDotLine: case Qt::DashDotDotLine: case Qt::CustomDashLine: { QString color, colorOpacity, dashPattern, dashOffset; qreal penWidth = spen.width() == 0 ? qreal(1) : spen.widthF(); translate_color(spen.color(), &color, &colorOpacity); translate_dashPattern(spen.dashPattern(), penWidth, &dashPattern); // SVG uses absolute offset dashOffset = QString::fromLatin1("%1").arg(spen.dashOffset() * penWidth); d_func()->attributes.stroke = color; d_func()->attributes.strokeOpacity = colorOpacity; d_func()->attributes.dashPattern = dashPattern; d_func()->attributes.dashOffset = dashOffset; stream() << QLatin1String("stroke=\"")<<color<< QLatin1String("\" "); stream() << QLatin1String("stroke-opacity=\"")<<colorOpacity<< QLatin1String("\" "); stream() << QLatin1String("stroke-dasharray=\"")<<dashPattern<< QLatin1String("\" "); stream() << QLatin1String("stroke-dashoffset=\"")<<dashOffset<< QLatin1String("\" "); break; } default: qWarning("Unsupported pen style"); break; } if (spen.widthF() == 0) { width = QLatin1String("1"); stream() << "vector-effect=\"non-scaling-stroke\" "; } else width = QString::number(spen.widthF()); stream() <<"stroke-width=\""<<width<<"\" "; switch (spen.capStyle()) { case Qt::FlatCap: stream() << "stroke-linecap=\"butt\" "; break; case Qt::SquareCap: stream() << "stroke-linecap=\"square\" "; break; case Qt::RoundCap: stream() << "stroke-linecap=\"round\" "; break; default: qWarning("Unhandled cap style"); } switch (spen.joinStyle()) { case Qt::MiterJoin: stream() << "stroke-linejoin=\"miter\" "; stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; break; case Qt::BevelJoin: stream() << "stroke-linejoin=\"bevel\" "; break; case Qt::RoundJoin: stream() << "stroke-linejoin=\"round\" "; break; case Qt::SvgMiterJoin: stream() << "stroke-linejoin=\"miter\" "; stream() << "stroke-miterlimit=\""<<spen.miterLimit()<<"\" "; break; default: qWarning("Unhandled join style"); } } void qbrushToSvg(const QBrush &sbrush) { d_func()->brush = sbrush; switch (sbrush.style()) { case Qt::SolidPattern: { QString color, colorOpacity; translate_color(sbrush.color(), &color, &colorOpacity); stream() << "fill=\"" << color << "\" "; stream() << "fill-opacity=\"" << colorOpacity << "\" "; d_func()->attributes.fill = color; d_func()->attributes.fillOpacity = colorOpacity; } break; case Qt::LinearGradientPattern: saveLinearGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::RadialGradientPattern: saveRadialGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::ConicalGradientPattern: saveConicalGradientBrush(sbrush.gradient()); d_func()->attributes.fill = QString::fromLatin1("url(#%1)").arg(d_func()->currentGradientName); d_func()->attributes.fillOpacity = QString(); stream() << QLatin1String("fill=\"url(#") << d_func()->currentGradientName << QLatin1String(")\" "); break; case Qt::NoBrush: stream() << QLatin1String("fill=\"none\" "); d_func()->attributes.fill = QLatin1String("none"); d_func()->attributes.fillOpacity = QString(); return; break; default: break; } } void qfontToSvg(const QFont &sfont) { Q_D(QSvgPaintEngine); d->font = sfont; d->attributes.font_size = QString::number(d->font.pointSize()) + QLatin1String("pt"); int svgWeight = d->font.weight(); switch (svgWeight) { case QFont::Light: svgWeight = 100; break; case QFont::Normal: svgWeight = 400; break; case QFont::Bold: svgWeight = 700; break; default: svgWeight *= 10; } d->attributes.font_weight = QString::number(svgWeight); d->attributes.font_family = d->font.family(); d->attributes.font_style = d->font.italic() ? QLatin1String("italic") : QLatin1String("normal"); *d->stream << "font-family=\"" << d->attributes.font_family << "\" " << "font-size=\"" << d->attributes.font_size << "\" " << "font-weight=\"" << d->attributes.font_weight << "\" " << "font-style=\"" << d->attributes.font_style << "\" " << endl; }};class QSvgGeneratorPrivate{public: QSvgPaintEngine *engine; uint owns_iodevice : 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -