qt svg模块源码解析1

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

类似的

  1. findGroupFactory
    Defs
    G
    Svg
    Switch

  2. findGraphicsFactory
    Animation
    Circle
    Ellipse
    Image
    Line
    Path
    Polygon
    Polyline
    Rect
    Text
    textArea
    Tspan
    Use
    Video

  3. findUtilFactory
    Animate
    AnimateColor
    AnimateMotion
    AnimateTransform
    Audio
    Desc
    Discard
    foreignObject
    Handler
    Hkern
    Metadata
    Mpath
    Prefetch
    Script
    Set
    Style
    Tbreak
    Title

  4. findStyleFactoryMethod
    Font
    LinearGradient
    RadialGradient
    SolidColor

  5. findStyleUtilFactoryMethod
    Font-face
    Font-face-name
    Font-face-src
    Font-face-uri
    Glyph
    Missing-glyph
    Stop

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值