BR: SVGParser modifies svg colour making `replaceColour` inconsistent

In SVG you can specify both fill-opacity (alpha of the color used to fill) and opacity (transparency of an object).

In JUCE, these are currently multiplied together to produce the fill color.

This means one cannot use replaceColour to replace the literal color specified in the SVG (or in your design program such as Figma) as it will no longer match the juce::Colour. For example, here’s an icon with a black circle (at 66% opacity) and a black question mark (at 100%):

Figma - 2023-08-10.29@2x

<rect height="20" opacity=".66" rx="10" stroke="#000" stroke-width="2" width="20" x="1" y="1"/>
<path d="m11.0559 5.28c.7574 0 1.4294.112 2.016.336.5867.224 1.0454.55467 1.376.992.3307.42667.496.95467.496 1.584 0 .64-.1386 1.168-.416 1.584-.2666.4053-.6293.7147-1.088.928-.4586.2027-.9653.336-1.52.4l-.112 1.504h-1.99996l.016-2.416c.71466-.0853 1.26936-.19733 1.66396-.336.4054-.14933.688-.336.848-.56.1707-.224.256-.49067.256-.8 0-.29867-.064-.54933-.192-.752-.1173-.20267-.2986-.35733-.544-.464-.2453-.10667-.56-.16-.944-.16-.5546 0-.9973.16-1.32796.48-.33067.30933-.53334.752-.608 1.328l-2.08-.8c.128-.55467.36266-1.04533.704-1.472.34133-.43733.79466-.77333 1.36-1.008.576-.24533 1.27466-.368 2.09596-.368zm-.224 8.4c.416 0 .7467.112.992.336.2454.224.368.5227.368.896 0 .384-.1226.688-.368.912-.2453.2133-.576.32-.992.32s-.7466-.1067-.99196-.32c-.24534-.224-.368-.528-.368-.912 0-.3733.12266-.672.368-.896.24536-.224.57596-.336.99196-.336z" fill="#000"/></g></svg>

Both the rect and path specify fill/stroke colors as #000.

Loaded into juce, when I use replaceColour to replace this black color with something like red, the <rect> (circle) element’s juce::Colour remains black (it doesn’t pass the equality matching, as the circle’s juce::Colour has an alpha value).

Anyway, I’m assuming this minor issue won’t be fixed (even if people agreed it’s a bug) as juce::Path doesn’t support alpha except via fills. But perhaps this post can save someone else some time wondering why replaceColour isn’t doing what they expected.

(A workaround could be to have a flavor of replaceColour that ignores alpha…)

2 Likes

Whups, didn’t realize a Drawable was created for each svg sub element

This fixes the issue: SVGParser opacity attribute should setAlpha on Drawable (not modify c… · juce-framework/JUCE@e4fbf05 · GitHub

1 Like

Just had this problem with my SVG (exported from Figma) and was looking for a workaround on the forum. As you said, having ‘stroke-opacity’ doesn’t allow me to replace the colour.

<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.0001 5L12.0001 19M19 12.0002L5 12.0002" stroke="white" stroke-opacity="0.9" stroke-linejoin="bevel"/>
</svg>

If I understood correctly we don’t have a way to work around this, is this correct? Or can we multiply the base colour of the svg with the stroke-opacity to get the color Juce uses in order to replace it?

1 Like

In my particular case I can do something as:

const auto svgStrokeOpacity = 0.9f;
const auto svgStrokeColour  = juce::Colour(0xFFFFFFFF);
    
image->replaceColour(svgStrokeColour.withMultipliedAlpha(svgStrokeOpacity), juce::Colours::red);

Not vary practical for something more complex.

1 Like

I guess you could do that!

But yeah, from an svg point of view, I think it’s a bug and opacity should modify the Drawable’s opacity as in my commit.

I’ll attach the example svg i used to in case the JUCE team wants to look into it.

help.svg.zip (828 Bytes)

1 Like