【问题标题】:QtSvg ignores unitsQtSvg 忽略单位
【发布时间】:2020-03-28 13:08:17
【问题描述】:

有没有办法让 QSvgWidget/QSvgRenderer 与 cm/mm/in/pc 等单位一起工作?

这是一个示例 SVG,其中所有行都应具有相同的长度(它在 Firefox 和 Chrome 中正确呈现):

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="500" width="500">
  <line x1="100" y1="50" x2="100" y2="450" style="stroke:rgb(0,0,0)" />
  <line x1="400" y1="50" x2="400" y2="450" style="stroke:rgb(0,0,0)" />
  <line x1="100" y1="100" x2="400" y2="100" style="stroke:rgb(255,0,0);stroke-width:20" />
  <line x1="100" y1="200" x2="105.82mm" y2="200" style="stroke:rgb(0,255,0);stroke-width:20" />
  <line x1="100" y1="300" x2="4.17in" y2="300" style="stroke:rgb(0,0,255);stroke-width:20" />
  <line x1="100" y1="400" x2="25pc" y2="400" style="stroke:rgb(127,127,127);stroke-width:20" />
</svg>

这是我的观众:

from PySide2 import QtWidgets, QtSvg
import PySide2

app = QtWidgets.QApplication(sys.argv)
w = QtSvg.QSvgWidget("demo.svg")
w.show()
sys.exit(app.exec_())

如果我用这个查看器打开 SVG,QT 似乎会忽略所有单位并将x2="105.82mm" 之类的属性读取为x2="105.82"

Qt 中的结果:

Firefox 中的结果:

QT 和 PySide2 都是 5.14.1 版本

【问题讨论】:

    标签: python svg pyside2 qtsvg


    【解决方案1】:

    说明:

    分析QSvgHandler的源码发现只有length(width和height属性)支持单位而不支持坐标,要理解的话,分析下面2个代码片段就够了:

    // https://code.qt.io/cgit/qt/qtsvg.git/tree/src/svg/qsvghandler.cpp#n2816
    static QSvgNode *createLineNode(QSvgNode *parent,
                                    const QXmlStreamAttributes &attributes,
                                    QSvgHandler *)
    {
        const QStringRef x1 = attributes.value(QLatin1String("x1"));
        const QStringRef y1 = attributes.value(QLatin1String("y1"));
        const QStringRef x2 = attributes.value(QLatin1String("x2"));
        const QStringRef y2 = attributes.value(QLatin1String("y2"));
        qreal nx1 = toDouble(x1);
        qreal ny1 = toDouble(y1);
        qreal nx2 = toDouble(x2);
        qreal ny2 = toDouble(y2);
    
        QLineF lineBounds(nx1, ny1, nx2, ny2);
        QSvgNode *line = new QSvgLine(parent, lineBounds);
        return line;
    }
    
    // https://code.qt.io/cgit/qt/qtsvg.git/tree/src/svg/qsvghandler.cpp#n3054
    static QSvgNode *createRectNode(QSvgNode *parent,
                                    const QXmlStreamAttributes &attributes,
                                    QSvgHandler *handler)
    {
        const QStringRef x      = attributes.value(QLatin1String("x"));
        const QStringRef y      = attributes.value(QLatin1String("y"));
        const QStringRef width  = attributes.value(QLatin1String("width"));
        const QStringRef height = attributes.value(QLatin1String("height"));
        const QStringRef rx      = attributes.value(QLatin1String("rx"));
        const QStringRef ry      = attributes.value(QLatin1String("ry"));
    
        QSvgHandler::LengthType type;
        qreal nwidth = parseLength(width, type, handler);
        nwidth = convertToPixels(nwidth, true, type);
    
        qreal nheight = parseLength(height, type, handler);
        nheight = convertToPixels(nheight, true, type);
        qreal nrx = toDouble(rx);
        qreal nry = toDouble(ry);
    
        QRectF bounds(toDouble(x), toDouble(y),
                      nwidth, nheight);
    
        //9.2 The 'rect'  element clearly specifies it
        // but the case might in fact be handled because
        // we draw rounded rectangles differently
        if (nrx > bounds.width()/2)
            nrx = bounds.width()/2;
        if (nry > bounds.height()/2)
            nry = bounds.height()/2;
    
        if (!rx.isEmpty() && ry.isEmpty())
            nry = nrx;
        else if (!ry.isEmpty() && rx.isEmpty())
            nrx = nry;
    
        //we draw rounded rect from 0...99
        //svg from 0...bounds.width()/2 so we're adjusting the
        //coordinates
        nrx *= (100/(bounds.width()/2));
        nry *= (100/(bounds.height()/2));
    
        QSvgNode *rect = new QSvgRect(parent, bounds,
                                      int(nrx),
                                      int(nry));
        return rect;
    }
    

    单位转换的方法是parseLength(),只用于“宽度”和“高度”。

    解决办法:

    一种解决方法是使用 QWebEngineView:

    import os
    import sys
    
    from PySide2 import QtCore, QtWidgets, QtSvg, QtWebEngineWidgets
    
    
    CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
    
    if __name__ == "__main__":
    
        app = QtWidgets.QApplication(sys.argv)
        filename = os.path.join(CURRENT_DIR, "demo.svg")
    
        qsvgwidget = QtSvg.QSvgWidget(filename)
    
        qwebengineview = QtWebEngineWidgets.QWebEngineView()
        qwebengineview.load(QtCore.QUrl.fromLocalFile(filename))
    
        w = QtWidgets.QWidget()
        lay = QtWidgets.QHBoxLayout(w)
        lay.addWidget(qsvgwidget, strecth=1)
        lay.addWidget(qwebengineview, strecth=1)
        w.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 谢谢,看起来好多了。您可能知道如何将 QWebEngineView 呈现为像素图吗?因为我一开始关注 SVG 的原因是我想将它们包含在我使用 QPrinter 创建的报告中。
    • 转换单位的方法是parseLength(),它只用于“width”和“height”。 - 为什么会有人这样做?
    猜你喜欢
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多