是否有办法使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版本
分析QSvgHandler的源代码后,我发现只有长度(宽度和高度属性)支持单位,而不支持坐标,要理解它,只需分析以下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:
parseLength()
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_())