Qt:无法解析某些 svg 项目样式
Qt: Unable to parse certain svg item styles
我正在尝试显示和修改一些 svg,我希望能够读取或修改它们的颜色。
GraphicsColorSvgItem::GraphicsColorSvgItem(QString svgContent, QGraphicsItem *parent) :
QGraphicsSvgItem(parent),
_svgXML()
{
_svgXML.setContent(svgContent);
setSharedRenderer(new QSvgRenderer(_svgXML.toByteArray()));
}
void GraphicsColorSvgItem::setColor(QColor c)
{
changeAttributes("fill", c.name().toUpper());
changeAttributes("stroke", c.name().toUpper());
changeAttributes("style", c.name().toUpper()); // this obviously needs to be treated separately just don't know how
renderer()->load(_svgXML.toByteArray());
}
void GraphicsColorSvgItem::changeAttributes(QString attName, QString attValue)
{
QDomElement rootElem = _svgXML.documentElement();
QDomNode n = rootElem.firstChild();
while(!n.isNull())
{
if(n.isElement())
{
QDomElement e = n.toElement();
QSTRING_DEBUG(e.tagName());
if(e.hasAttribute(attName))
{
e.setAttribute(attName, attValue);
}
if(n.hasChildNodes())
recursiveChangeAttributes(n.firstChild(), attName, attValue);
}
n = n.nextSibling();
}
}
void GraphicsColorSvgItem::recursiveChangeAttributes(QDomNode node, QString attName, QString attValue)
{
QDomNode n = node;
while(!n.isNull())
{
if(n.isElement())
{
QDomElement e = n.toElement();
if(e.hasAttribute(attName))
{
e.setAttribute(attName, attValue);
}
if(n.hasChildNodes())
recursiveChangeAttributes(n.firstChild(), attName, attValue);
}
n = n.nextSibling();
}
}
下面svg改成我pass的颜色成功
<!DOCTYPE html>
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
下面的 svg 虽然有 "style" 属性 - 我不知道如何解析它
<!DOCTYPE html>
<svg height="250" width="500">
<circle cx="50" cy="50" r="40" style="fill:red;stroke:black;stroke-width:3" />
Sorry, your browser does not support inline SVG.
</svg>
结果为黑色 - 因为整个 "style" 设置为不受支持的内容。
编辑:现在我正在做一个字符串替换,它似乎工作...但我希望有一个 xml 方法...
if(attName=="style")
{
QString value = e.attribute(attName);
int fill1 = value.indexOf(QString("fill:")) + 5;
int fill2 = value.indexOf(QString(";"), fill1);
if(fill2<=fill1)
fill2 = value.indexOf(QString("\""), fill1);
QString subString = value.mid(fill1, fill2 - fill1);
value.replace(subString, attValue);
fill1 = value.indexOf(QString("stroke:")) + 7;
fill2 = value.indexOf(QString(";"), fill1);
if(fill2<=fill1)
fill2 = value.indexOf(QString("\""), fill1);
subString = value.mid(fill1, fill2 - fill1);
value.replace(subString, attValue);
e.setAttribute(attName, value);
}
else
{
e.setAttribute(attName, attValue);
}
样式属性中的内容通常是 CSS 样式语法。因此,使用支持 CSS 的解析器可能是您最好的选择。正则表达式可能有用,但可能不是最容易使用的...
话虽如此,我会切换到类似的内容:
if(attName=="style")
{
QString value = e.attribute(attName);
QStringList styleList = value.split(";");
QStringList newStyleList;
foreach(QString style, styleList)
{
QStringList propertyVal = style.split(":");
QString prop = propertyVal.first().trimmed();
QString newVal = propertyVal.at(1).trimmed();
if(prop == "stroke")
{
newVal = attValue;
}
else if(prop == "fill")
{
newVal = attValue;
}
else
{
// no changes
}
newStyleList.append(prop + ":" + newVal);
}
e.setAttribute(attName, newStyleList.join(";"));
}
这是一个可以工作的正则表达式示例。
/fill:(.*?)(?=;|$)/
转换为:
找到单词 fill
,后跟冒号,然后找到尽可能少的字符,直到找到分号或找到字符串结尾。
在捕获组列表中,第一组(第 0 组之后)应包含 属性 值对的值的字符串。
然后需要将此表达式放在 QRegularExpression
中并用在字符串上。
http://doc.qt.io/qt-5/qregularexpression.html#details
希望对您有所帮助。
我正在尝试显示和修改一些 svg,我希望能够读取或修改它们的颜色。
GraphicsColorSvgItem::GraphicsColorSvgItem(QString svgContent, QGraphicsItem *parent) :
QGraphicsSvgItem(parent),
_svgXML()
{
_svgXML.setContent(svgContent);
setSharedRenderer(new QSvgRenderer(_svgXML.toByteArray()));
}
void GraphicsColorSvgItem::setColor(QColor c)
{
changeAttributes("fill", c.name().toUpper());
changeAttributes("stroke", c.name().toUpper());
changeAttributes("style", c.name().toUpper()); // this obviously needs to be treated separately just don't know how
renderer()->load(_svgXML.toByteArray());
}
void GraphicsColorSvgItem::changeAttributes(QString attName, QString attValue)
{
QDomElement rootElem = _svgXML.documentElement();
QDomNode n = rootElem.firstChild();
while(!n.isNull())
{
if(n.isElement())
{
QDomElement e = n.toElement();
QSTRING_DEBUG(e.tagName());
if(e.hasAttribute(attName))
{
e.setAttribute(attName, attValue);
}
if(n.hasChildNodes())
recursiveChangeAttributes(n.firstChild(), attName, attValue);
}
n = n.nextSibling();
}
}
void GraphicsColorSvgItem::recursiveChangeAttributes(QDomNode node, QString attName, QString attValue)
{
QDomNode n = node;
while(!n.isNull())
{
if(n.isElement())
{
QDomElement e = n.toElement();
if(e.hasAttribute(attName))
{
e.setAttribute(attName, attValue);
}
if(n.hasChildNodes())
recursiveChangeAttributes(n.firstChild(), attName, attValue);
}
n = n.nextSibling();
}
}
下面svg改成我pass的颜色成功
<!DOCTYPE html>
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
Sorry, your browser does not support inline SVG.
</svg>
下面的 svg 虽然有 "style" 属性 - 我不知道如何解析它
<!DOCTYPE html>
<svg height="250" width="500">
<circle cx="50" cy="50" r="40" style="fill:red;stroke:black;stroke-width:3" />
Sorry, your browser does not support inline SVG.
</svg>
结果为黑色 - 因为整个 "style" 设置为不受支持的内容。
编辑:现在我正在做一个字符串替换,它似乎工作...但我希望有一个 xml 方法...
if(attName=="style")
{
QString value = e.attribute(attName);
int fill1 = value.indexOf(QString("fill:")) + 5;
int fill2 = value.indexOf(QString(";"), fill1);
if(fill2<=fill1)
fill2 = value.indexOf(QString("\""), fill1);
QString subString = value.mid(fill1, fill2 - fill1);
value.replace(subString, attValue);
fill1 = value.indexOf(QString("stroke:")) + 7;
fill2 = value.indexOf(QString(";"), fill1);
if(fill2<=fill1)
fill2 = value.indexOf(QString("\""), fill1);
subString = value.mid(fill1, fill2 - fill1);
value.replace(subString, attValue);
e.setAttribute(attName, value);
}
else
{
e.setAttribute(attName, attValue);
}
样式属性中的内容通常是 CSS 样式语法。因此,使用支持 CSS 的解析器可能是您最好的选择。正则表达式可能有用,但可能不是最容易使用的...
话虽如此,我会切换到类似的内容:
if(attName=="style")
{
QString value = e.attribute(attName);
QStringList styleList = value.split(";");
QStringList newStyleList;
foreach(QString style, styleList)
{
QStringList propertyVal = style.split(":");
QString prop = propertyVal.first().trimmed();
QString newVal = propertyVal.at(1).trimmed();
if(prop == "stroke")
{
newVal = attValue;
}
else if(prop == "fill")
{
newVal = attValue;
}
else
{
// no changes
}
newStyleList.append(prop + ":" + newVal);
}
e.setAttribute(attName, newStyleList.join(";"));
}
这是一个可以工作的正则表达式示例。
/fill:(.*?)(?=;|$)/
转换为:
找到单词 fill
,后跟冒号,然后找到尽可能少的字符,直到找到分号或找到字符串结尾。
在捕获组列表中,第一组(第 0 组之后)应包含 属性 值对的值的字符串。
然后需要将此表达式放在 QRegularExpression
中并用在字符串上。
http://doc.qt.io/qt-5/qregularexpression.html#details
希望对您有所帮助。