Change the color of an svg in qt
Solution 1
This is how you can do it in Qt, don´t forget to add the xml and svg modules to your qt project (*.pro file). This code snippet changes the color by modifying the "fill" attribute of any "path" element but you could use it to modify any attribute of any element.
void SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, QString strattrval);
void ChangeSVGColor()
{
// open svg resource load contents to qbytearray
QFile file("myfile.svg");
file.open(QIODevice::ReadOnly);
QByteArray baData = file.readAll();
// load svg contents to xml document and edit contents
QDomDocument doc;
doc.setContent(baData);
// recurivelly change color
SetAttrRecur(doc.documentElement(), "path", "fill", "white");
// create svg renderer with edited contents
QSvgRenderer svgRenderer(doc.toByteArray());
// create pixmap target (could be a QImage)
QPixmap pix(svgRenderer.defaultSize());
pix.fill(Qt::transparent);
// create painter to act over pixmap
QPainter pixPainter(&pix);
// use renderer to render over painter which paints on pixmap
svgRenderer.render(&pixPainter);
QIcon myicon(pix);
// Use icon ....
}
void SetAttrRecur(QDomElement &elem, QString strtagname, QString strattr, QString strattrval)
{
// if it has the tagname then overwritte desired attribute
if (elem.tagName().compare(strtagname) == 0)
{
elem.setAttribute(strattr, strattrval);
}
// loop all children
for (int i = 0; i < elem.childNodes().count(); i++)
{
if (!elem.childNodes().at(i).isElement())
{
continue;
}
SetAttrRecur(elem.childNodes().at(i).toElement(), strtagname, strattr, strattrval);
}
}
Solution 2
Since the SVG format is XML based, and XML is just ASCII text... you could load the SVG resource in to a QString, call QString::replace("\"#000000\"", "\"#ffffff\""), and then pass the modified QString in to your QSVGRenderer.
Solution 3
If your SVG is black, there is an extremely easy way to do it: QGraphicsEffect
#include <QGraphicsItem>
#include <QGraphicsColorizeEffect>
QGraphicsItem *item;
QGraphicsColorizeEffect *effect;
item = new QGraphicsItem;
effect = new QGraphicsColorizeEffect;
effect->setColor(Qt::white);
effect->setStrength(1);
item->setGraphicsEffect(effect)
This doesn't work with white SVGs, but given that almost any website that provides icons does so in black, this is pretty neat.
Solution 4
As long as you don't need it on Mac, this should work:
http://doc-snapshot.qt-project.org/4.8/qwidget.html#setGraphicsEffect
http://doc-snapshot.qt-project.org/4.8/qgraphicscolorizeeffect.html
EDIT: Or if you need to support Mac, do the svg rendering and effects inside a QGraphicsView.
http://doc-snapshot.qt-project.org/4.8/qgraphicsitem.html#setGraphicsEffect
Setup your colorize effect to color it white, and set it to the svgWidget.
Hope that helps.
Solution 5
solution for pyqt5. You can easily convert it to c++
def QIcon_from_svg(svg_filepath, color='black'):
img = QPixmap(svg_filepath)
qp = QPainter(img)
qp.setCompositionMode(QPainter.CompositionMode_SourceIn)
qp.fillRect( img.rect(), QColor(color) )
qp.end()
return QIcon(img)

chacham15
Updated on June 06, 2022Comments
-
chacham15 7 months
I have a svg loaded in the resources, but it is black. How do I change the color to white?
-
chacham15 almost 10 yearsLol, I've been bitten by the whole QGraphicsEffects dont work on Mac more than once :(
-
phyatt almost 10 yearsIf you don't mind rendering it into a QGraphicsView, then the QGraphicsEffects should be supported. There are also ways to render it to a QPixmap or QImage, and then render it with different Composition Modes. slideshare.net/qtbynokia/special-effects-with-qt-graphics-view There are some great code samples in this slide show.
-
phyatt over 8 yearsI should double check the graphics effect thing on newer builds of Qt. I think they may have fixed it. Look at the missing note between these two links: qt-project.org/doc/qt-4.8/qwidget.html#setGraphicsEffect and qt-project.org/doc/qt-5/qwidget.html#setGraphicsEffect ... it no longer says
Note: Graphics effects are not supported on Mac, so they will not cause any difference to the rendering of the widget.
for Qt 5. -
Lennart Rolland almost 7 yearsIt seems this does not work because in qt5 doc.documentElement() returns a "read only" object. Making changes to it does not work at all.
-
Mike Bourbeau about 3 yearsI could use a bit more explanation on how to do this. How would I load the SVG resource to a QString? I'm using PySide2 if that changes the answer at all.
-
SamG101 almost 3 yearsI know this is an old post, but it has been very helpful and works perfectly - one question though: how could a gradient be used to fill, rather than a solid colour to fill? Can I simply pass a
QLinearGradient
as the colour parameter? -
SamG101 over 2 yearsWhat class / method is used to render an SVG file into a string object?
-
Jeremy Friesner over 2 years@SamG101 SVG files are text files (open one up in your favorite text editor, you'll see it's just XML inside), so you can load the contents of an SVG file into a QString using QFile::readAll() or any other text-file-reading API.
-
rtlgrmpf about 2 yearsA tiny but very important improvement:
toByteArray(-1)
. Otherwise it wreaks havoc to text elements because of wrong white spaces. That took me a while to figure out...