Qt6 color SVG using MultiEffect
-
wrote on 2 Apr 2023, 19:25 last edited by christofer 4 Feb 2023, 19:54
Can we colorize and SVG (or PNG) using
MultiEffect
in Qt 6.5?I created a sample project that just has a puppy who should be blue but doesn't get colorized: https://gitlab.com/christoferjennings/qt-6-5-colorize-svg
The code follows the examples in the
MultiEffect
documentation. But, alas, the puppy doesn't appear blue.import QtQuick import QtQuick.Effects Window { id: window width: 500 height: 300 visible: true title: "Puppy should be blue" Image { id: theImage source: "image.svg" sourceSize.height: window.height - 20 fillMode: Image.PreserveAspectFit anchors.centerIn: parent } MultiEffect { source: theImage anchors.fill: theImage colorization: 1.0 colorizationColor: "blue" } }
In the past, I've used
ColorOverlay
. But I'd like to useMultiEffect
. This old related thread ends with a comment thatMultiEffect
is expected in Qt 6.5. Everything compiles fine but it doesn't seem to work.I'm trying this on macOS Monterey and Ubuntu 22.
-
Can we colorize and SVG (or PNG) using
MultiEffect
in Qt 6.5?I created a sample project that just has a puppy who should be blue but doesn't get colorized: https://gitlab.com/christoferjennings/qt-6-5-colorize-svg
The code follows the examples in the
MultiEffect
documentation. But, alas, the puppy doesn't appear blue.import QtQuick import QtQuick.Effects Window { id: window width: 500 height: 300 visible: true title: "Puppy should be blue" Image { id: theImage source: "image.svg" sourceSize.height: window.height - 20 fillMode: Image.PreserveAspectFit anchors.centerIn: parent } MultiEffect { source: theImage anchors.fill: theImage colorization: 1.0 colorizationColor: "blue" } }
In the past, I've used
ColorOverlay
. But I'd like to useMultiEffect
. This old related thread ends with a comment thatMultiEffect
is expected in Qt 6.5. Everything compiles fine but it doesn't seem to work.I'm trying this on macOS Monterey and Ubuntu 22.
wrote on 4 Apr 2023, 00:19 last edited by@christofer I've experienced this as well. I think the problem is in how the .svg file is composed, specifically (but not only) the use of the "fill=" field. I snagged a circle.svg file with this content:
<svg fill="#0000ff" height="200px" width="200px" version="1.1" id="Layer_1" viewBox="0 0 222.334 222.334" xml:space="preserve"> <g> <g> <g> <path d="M111.167,0C49.87,0,0,49.87,0,111.167s49.87,111.167,111.167,111.167s111.167-49.87,111.167-111.167S172.464,0,111.167,0 z M111.167,214.1c-56.758,0-102.933-46.175-102.933-102.933S54.409,8.235,111.167,8.235S214.1,54.409,214.1,111.167 S167.925,214.1,111.167,214.1z"/> </g> </g> </g> </svg>
which produces this:
Replacing the fill value from "#0000ff" to "none" produces a black circle.I tried a similar experiment with the puppy file and couldn't even get that to change color at all.
So...I think the svg file has to be composed in a particular way in order to support fills, but I can't speak with any authority on this. Hopefully someone else with some .svg file knowledge can chime in.
-
@christofer I've experienced this as well. I think the problem is in how the .svg file is composed, specifically (but not only) the use of the "fill=" field. I snagged a circle.svg file with this content:
<svg fill="#0000ff" height="200px" width="200px" version="1.1" id="Layer_1" viewBox="0 0 222.334 222.334" xml:space="preserve"> <g> <g> <g> <path d="M111.167,0C49.87,0,0,49.87,0,111.167s49.87,111.167,111.167,111.167s111.167-49.87,111.167-111.167S172.464,0,111.167,0 z M111.167,214.1c-56.758,0-102.933-46.175-102.933-102.933S54.409,8.235,111.167,8.235S214.1,54.409,214.1,111.167 S167.925,214.1,111.167,214.1z"/> </g> </g> </g> </svg>
which produces this:
Replacing the fill value from "#0000ff" to "none" produces a black circle.I tried a similar experiment with the puppy file and couldn't even get that to change color at all.
So...I think the svg file has to be composed in a particular way in order to support fills, but I can't speak with any authority on this. Hopefully someone else with some .svg file knowledge can chime in.
wrote on 4 Apr 2023, 00:26 last edited byUpdate: I tried a much simpler circle file:
<svg width="300" height="550" xmlns="http://www.w3.org/2000/svg"> <circle cx="150" cy="100" r="60" style="fill:red; stroke-width:3; stroke:rgb(0,0,0); fill-opacity:0.7" /> </svg>
(note the fill:red)
And this code:
Image { id: image Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter source: "qrc:/circle2.svg" visible: false // <== DON'T FORGET THIS LINE } MultiEffect { source: image anchors.fill: image colorization: 1.0 colorizationColor: "blue" }
And it works. So it's not a Qt problem; it's the way the .svg files are constructed.
-
Update: I tried a much simpler circle file:
<svg width="300" height="550" xmlns="http://www.w3.org/2000/svg"> <circle cx="150" cy="100" r="60" style="fill:red; stroke-width:3; stroke:rgb(0,0,0); fill-opacity:0.7" /> </svg>
(note the fill:red)
And this code:
Image { id: image Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter source: "qrc:/circle2.svg" visible: false // <== DON'T FORGET THIS LINE } MultiEffect { source: image anchors.fill: image colorization: 1.0 colorizationColor: "blue" }
And it works. So it's not a Qt problem; it's the way the .svg files are constructed.
wrote on 4 Apr 2023, 00:51 last edited by mzimmers 4 Apr 2023, 01:18another update: further testing revealed that you can't just put a fill= in the path; it has to be:
<path style="fill:#00ff00" ...
and the fill value can't be "none;" it must be a color (either by name or by RGB value).
This works on my original circle (though it's only filling the outline; I think I need to remove part of the path for it to fill the entire circle.
It worked on the puppy too (though there are 3 paths in the puppy; you'd have to add it to all of them).
So...I think we have our answer.
-
wrote on 4 Apr 2023, 13:02 last edited by christofer 4 Apr 2023, 13:14
Thanks for the replies @mzimmers !
You inspired me to experiment more. It turns out all I have to do is change the existing SVG fill from black to white.
I changed...
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
to...
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)" fill="white" stroke="none">
The changes are in the GitLab project, tag qt-forum-post-02
-
-
Thanks for the replies @mzimmers !
You inspired me to experiment more. It turns out all I have to do is change the existing SVG fill from black to white.
I changed...
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)" fill="#000000" stroke="none">
to...
<g transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)" fill="white" stroke="none">
Result...
The changes are in the GitLab project, tag qt-forum-post-02
wrote on 4 Apr 2023, 15:37 last edited by mzimmers 4 Apr 2023, 16:00@christofer interesting. I did some experimentation of my own on the puppy file, and it appears that the problem wasn't the use of the RGB format for specifying the color, but rather the fill of black, or indeed any color other than white (or #ffffff).
EDIT: scratch the comment below -- I forgot my own advice of hiding the original image.
As a side note, I also noticed that when using the Image inside a Layout, you can't use the anchors property, so the MultiEffect appear below (in the case of a ColumnLayout) the original image. My workaround was to put the Image and the MultiEffect in an Item, so I could use anchors, but there might be a more elegant way to accomplish this. -
-
@christofer interesting. I did some experimentation of my own on the puppy file, and it appears that the problem wasn't the use of the RGB format for specifying the color, but rather the fill of black, or indeed any color other than white (or #ffffff).
EDIT: scratch the comment below -- I forgot my own advice of hiding the original image.
As a side note, I also noticed that when using the Image inside a Layout, you can't use the anchors property, so the MultiEffect appear below (in the case of a ColumnLayout) the original image. My workaround was to put the Image and the MultiEffect in an Item, so I could use anchors, but there might be a more elegant way to accomplish this.@mzimmers tried to colorize a png
my old code:Image { id: image .... ColorOverlay { id: colorOverlay anchors.fill: image source: image color: primaryColor }
new code:
Image { id: image .... MultiEffect { id: colorOverlay source: image anchors.fill: image colorization: 1.0 colorizationColor: primaryColor }
But the Image isn't colorized.
-----------edit: foundSolution- separated Image and MultiEffect and placed both inside an Item
- then set visible false at Image
result: not colorized, but found the reason
the png was a black icon - changed this and used a white icon and now colorizing works.
So this is different to QtQuickEffects and Qt 5.15
-
wrote on 20 Mar 2024, 09:47 last edited by alvarosaes
Hello, I also had this question so i asked directly via Qt support. I got this response:
> Thank you for you response. So, ColorOverlayEffect from import > QtQuick.Studio.Effects 1.0 is not equivalent to this? I didnt have this > problem while using that effect Yeah, different effect: fragColor = vec4(mix(pixelColor.rgb/max(pixelColor.a, 0.00390625), color.rgb/max(color.a, 0.00390625), color.a) * pixelColor.a, pixelColor.a) * qt_Opacity; Compared to this for colorization: color.rgb = (color.rgb - 0.5 * color.a) * (1.0 + contrast) + 0.5 * color.a; color.rgb += brightness * color.a; float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); float colorizationAlpha = colorization * colorizationColor.a; color.rgb = mix(color.rgb, gray * colorizationColor.rgb, colorizationAlpha); color.rgb = mix(vec3(gray), color.rgb, 1.0 + saturation);
So i only see 2 solutions:
- Convert all your svgs to fill white
- Rollback to use ColorOverlayEffect
-
wrote on 13 May 2024, 10:54 last edited by srce
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
-
wrote on 16 Jul 2024, 12:07 last edited by
@srce thank you!!
-
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
wrote on 22 Aug 2024, 15:43 last edited by MattP2@srce said in Qt6 color SVG using MultiEffect:
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
This is the answer, a big thank you.
So, visible: false, parent Item and color in svg are not required.
This is working with any svg:Image { // image properties layer.enabled: true layer.effect: MultiEffect { brightness: 1.0 colorization: 1.0 colorizationColor: enabled ? Material.primaryTextColor : Material.secondaryTextColor } }
-
N nicwainwright referenced this topic on 20 Nov 2024, 15:01
-
@srce said in Qt6 color SVG using MultiEffect:
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
This is the answer, a big thank you.
So, visible: false, parent Item and color in svg are not required.
This is working with any svg:Image { // image properties layer.enabled: true layer.effect: MultiEffect { brightness: 1.0 colorization: 1.0 colorizationColor: enabled ? Material.primaryTextColor : Material.secondaryTextColor } }
-
@srce said in Qt6 color SVG using MultiEffect:
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
This is the answer, a big thank you.
So, visible: false, parent Item and color in svg are not required.
This is working with any svg:Image { // image properties layer.enabled: true layer.effect: MultiEffect { brightness: 1.0 colorization: 1.0 colorizationColor: enabled ? Material.primaryTextColor : Material.secondaryTextColor } }
wrote 23 days ago last edited by Aleksey Asensus@srce said in Qt6 color SVG using MultiEffect:
Rather than converting pngs from black to white, setting brightness to 1 (in addition to colorize) should have a similar effect.
Yep, this works for me, thanks, however Qt 5 solution more flexible: with
ColorOverlay
I can setcolor: "transparent"
to fully keep original icon where necessary, here icon becomes white for some reason, even ifMultiEffect
item or layer is not visible/enabled. So still forced to stay onColorOverlay
.