svg文件格式学习
SVG 教程
属性
xml:space
Understanding xml:space
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSvgRenderer render;
render.load (QString("circle.svg"));
QSize size = render.defaultSize ();
QPixmap pix(size*5); // 可以在这儿直接缩放处理
pix.fill (Qt::transparent); // 像素清空
QPainter painter(&pix);
painter.setRenderHints (QPainter::Antialiasing);
render.render (&painter);
QLabel label;
label.setPixmap (pix);
label.setAlignment (Qt::AlignCenter);
label.show ();
return a.exec();
}
void QSvgRenderer::render(QPainter *painter)
{
Q_D(QSvgRenderer);
if (d->render) {
//画图
d->render->draw(painter);
}
}
画图
void QSvgTinyDocument::draw(QPainter *p, const QRectF &bounds)
{
if (m_time == 0)
m_time = QDateTime::currentMSecsSinceEpoch();
if (displayMode() == QSvgNode::NoneMode)
return;
p->save();
//sets default style on the painter
//### not the most optimal way
mapSourceToTarget(p, bounds);
QPen pen(Qt::NoBrush, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin);
pen.setMiterLimit(4);
p->setPen(pen);
p->setBrush(Qt::black);
p->setRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::SmoothPixmapTransform);
QList<QSvgNode*>::iterator itr = m_renderers.begin();
applyStyle(p, m_states);
while (itr != m_renderers.end()) {
QSvgNode *node = *itr;
if ((node->isVisible()) && (node->displayMode() != QSvgNode::NoneMode))
node->draw(p, m_states);
++itr;
}
revertStyle(p, m_states);
p->restore();
}
解析文件
初始化
void QSvgHandler::init()
{
m_doc = 0;
m_style = 0;
m_animEnd = 0;
m_defaultCoords = LT_PX;
m_defaultPen = QPen(Qt::black, 1, Qt::SolidLine, Qt::FlatCap, Qt::SvgMiterJoin);
m_defaultPen.setMiterLimit(4);
parse();
}
用 QXmlStreamReader *const xml; 读取svg文件,并解析
enum QXmlStreamReader::TokenType:此枚举指定读取器当前读取的类型。
- NoToken:还没有读到任何东西。
- Invalid:发生了错误,在 error() 和 errorString() 中报告。
- StartDocument:在 documentVersion() 中报告 XML 版本号,在 documentEncoding() 中报告 XML 文档中指定的编码。如果文档被声明为独立的,则 isStandaloneDocument() 返回 true。
- EndDocument:报告文档的结尾。
- StartElement:使用 namespaceUri() 和 name() 报告元素的开始。 空元素也报告为 StartElement,后跟 EndElement。 属性在 attributes() 中报告,命名空间声明在 namespaceDeclarations() 中。
- EndElement:使用 namespaceUri() 和 name() 报告元素的结尾。
- Characters:在 text() 中报告字符。 如果字符都是空白字符,则 isWhitespace() 返回 true。如果字符来自 CDATA 部分,则 isCDATA() 返回 true。
- Comment:在 text() 中报告注释。
- DTD:在 text() 中报告 DTD,在 notationDeclarations() 中报告符号声明,在 entityDeclarations() 中报告实体声明。DTD 声明的详细信息在 dtdName()、dtdPublicId() 和 dtdSystemId() 中报告。
- EntityReference:报告无法解析的实体引用。引用的名称在 name() 中报告,替换文本在 text() 中。
- ProcessingInstruction:在 processingInstructionTarget() 和 processingInstructionData() 中报告处理指令。
参考链接
文档开始StartDocument,结尾EndDocument,注释都不需要关注
其中DTD 的目的是定义 XML 文档的结构。它使用一系列合法的元素来定义文档结构,与画图无关
所以代码如下:
static const int unfinishedElementsLimit = 2048;
void QSvgHandler::parse()
{
xml->setNamespaceProcessing(false);
#ifndef QT_NO_CSSPARSER
m_selector = new QSvgStyleSelector;
m_inStyle = false;
#endif
bool done = false;
int remainingUnfinishedElements = unfinishedElementsLimit;
while (!xml->atEnd() && !done) {
switch (xml->readNext()) {
case QXmlStreamReader::StartElement:
startElement(xml->name().toString(), xml->attributes())
。。。
break;
case QXmlStreamReader::EndElement:
。。。
break;
case QXmlStreamReader::Characters:
。。。
break;
case QXmlStreamReader::ProcessingInstruction:
。。。
break;
default:
break;
}
}
resolveGradients(m_doc);
resolveNodes();
}
svg 文件示例
<svg width="1250px" height="1250px" viewBox="0 0 1250 1250" fill="none" xmlns="http://www.w3.org/2000/svg" aria-labelledby="trainIconTitle" stroke="#2329D6" stroke-width="1" stroke-linecap="square" stroke-linejoin="miter" color="#2329D6">
<title id="trainIconTitle">Train</title>
<path d="M6 11V6M6 11V16C6 16.5523 6.44772 17 7 17H8M6 11H12M6 6C6.66667 5.33333 8 4 12 4C16 4 17.3333 5.33333 18 6M6 6H12M18 6V11M18 6H12M18 11V16C18 16.5523 17.5523 17 17 17H16M18 11H12M8 17H16M8 17L7 20H17L16 17M12 11V6"/>
<circle cx="9" cy="14" r="1"/> <circle cx="15" cy="14" r="1"/>
<g transform="translate(100,100)">
<text id="TextElement" x="0" y="0" style="font-family:Verdana;font-size:24; visibility:hidden"> It's SVG!
<set attributeName="visibility" attributeType="CSS" to="visible" begin="1s" dur="5s" fill="freeze" />
<animateMotion path="M 0 0 L 100 100" begin="1s" dur="5s" fill="freeze" />
<animateColor attributeName="fill" attributeType="CSS" from="red" to="blue" begin="1s" dur="5s" fill="freeze" />
<animateTransform attributeName="transform" attributeType="XML" type="rotate" from="-30" to="0" begin="1s" dur="5s" fill="freeze" />
<animateTransform attributeName="transform" attributeType="XML" type="scale" from="1" to="3" additive="sum" begin="1s" dur="5s" fill="freeze" />
</text>
</g>
<path stroke-linecap="round" d="M5 40 l215 0" />
</svg>
输出
QSvgHandler::startElement "svg" ,
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "title" ,
QXmlStreamReader::Characters "Train"
QXmlStreamReader::EndElement: "title"
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "path" ,
QXmlStreamReader::EndElement: "path"
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "circle" ,
QXmlStreamReader::EndElement: "circle"
QXmlStreamReader::Characters " "
QSvgHandler::startElement "circle" ,
QXmlStreamReader::EndElement: "circle"
QXmlStreamReader::Characters " \n "
QSvgHandler::startElement "g" ,
QXmlStreamReader::Characters " \n "
QSvgHandler::startElement "text" ,
QXmlStreamReader::Characters " It's SVG!\n "
QSvgHandler::startElement "set" ,
QXmlStreamReader::EndElement: "set"
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "animateMotion" ,
QXmlStreamReader::EndElement: "animateMotion"
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "animateColor" ,
QXmlStreamReader::EndElement: "animateColor"
QXmlStreamReader::Characters " \n "
QSvgHandler::startElement "animateTransform" ,
QXmlStreamReader::EndElement: "animateTransform"
QXmlStreamReader::Characters " \n "
QSvgHandler::startElement "animateTransform" ,
QXmlStreamReader::EndElement: "animateTransform"
QXmlStreamReader::Characters " \n "
QXmlStreamReader::EndElement: "text"
QXmlStreamReader::Characters " \n "
QXmlStreamReader::EndElement: "g"
QXmlStreamReader::Characters "\n "
QSvgHandler::startElement "path" ,
QXmlStreamReader::EndElement: "path"
QXmlStreamReader::Characters "\n "
QXmlStreamReader::EndElement: "svg"
首先
bool QSvgHandler::startElement(const QString &localName, const QXmlStreamAttributes &attributes)
拿到标签名 localName,首先要对他们分类
if (FactoryMethod method = findGroupFactory(localName))
{
}
else if (FactoryMethod method = findGraphicsFactory(localName))
{
}
else if (ParseMethod method = findUtilFactory(localName))
{
}
else if (StyleFactoryMethod method = findStyleFactoryMethod(localName))
{
}
else if (StyleParseMethod method = findStyleUtilFactoryMethod(localName))
{
}
解析标签名的首字母判断标签的含义,如下
typedef QSvgNode *(*FactoryMethod)(QSvgNode *, const QXmlStreamAttributes &, QSvgHandler *);
static FactoryMethod findGroupFactory(const QString &name)
{
if (name.isEmpty())
return 0;
QStringRef ref(&name, 1, name.length() - 1);
switch (name.at(0).unicode()) {
case 'd':
if (ref == QLatin1String("efs")) return createDefsNode;
break;
case 'g':
if (ref.isEmpty()) return createGNode;
break;
case 's':
if (ref == QLatin1String("vg")) return createSvgNode;
if (ref == QLatin1String("witch")) return createSwitchNode;
break;
default:
break;
}
return 0;
}
复习 C++ 函数指针
如果标签为以下节点,分别返回不同的函数指针
- Defs
- G
- Svg
- Switch
类似的
-
findGroupFactory
Defs
G
Svg
Switch -
findGraphicsFactory
Animation
Circle
Ellipse
Image
Line
Path
Polygon
Polyline
Rect
Text
textArea
Tspan
Use
Video -
findUtilFactory
Animate
AnimateColor
AnimateMotion
AnimateTransform
Audio
Desc
Discard
foreignObject
Handler
Hkern
Metadata
Mpath
Prefetch
Script
Set
Style
Tbreak
Title -
findStyleFactoryMethod
Font
LinearGradient
RadialGradient
SolidColor -
findStyleUtilFactoryMethod
Font-face
Font-face-name
Font-face-src
Font-face-uri
Glyph
Missing-glyph
Stop