linebender / resvg

An SVG rendering library.
Apache License 2.0
2.84k stars 229 forks source link

`style="opacity: 0.3;fill:#FF0000"` - opacity not parsed #716

Closed simbleau closed 9 months ago

simbleau commented 9 months ago

Example file: image

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.2.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 128 128" style="enable-background:new 0 0 128 128;" xml:space="preserve">
<g>
    <path style="fill:#689F38;" d="M116.46,3.96h-104c-4.42,0-8,3.58-8,8v104c0,4.42,3.58,8,8,8h104c4.42,0,8-3.58,8-8v-104
        C124.46,7.54,120.88,3.96,116.46,3.96z"/>
    <path style="fill:#7CB342;" d="M110.16,3.96h-98.2c-4.13,0.03-7.47,3.37-7.5,7.5v97.9c-0.01,4.14,3.34,7.49,7.48,7.5
        c0.01,0,0.01,0,0.02,0h98.1c4.14,0.01,7.49-3.34,7.5-7.48c0-0.01,0-0.01,0-0.02v-97.9c0.09-4.05-3.13-7.41-7.18-7.5
        C110.31,3.96,110.23,3.96,110.16,3.96z"/>
    <path style="opacity:0.3;fill:#FFFFFF;" d="M40.16,12.86c0-2.3-1.6-3-10.8-2.7c-7.7,0.3-11.5,1.2-13.8,4
        s-2.9,8.5-3,15.3c0,4.8,0,9.3,2.5,9.3c3.4,0,3.4-7.9,6.2-12.3C26.66,17.76,40.16,15.86,40.16,12.86z"/>
    <path style="fill:#FBF9F9;" d="M43.26,109.46c-3.96,0.11-7.51-2.42-8.7-6.2l-15.1-45.5c-1.46-4.81,1.26-9.9,6.07-11.36
        c4.65-1.41,9.59,1.08,11.23,5.66l9.8,29.5l47.1-59.6c3.12-3.95,8.85-4.62,12.8-1.5s4.62,8.85,1.5,12.8l-57.6,72.7
        C48.65,108.15,46.04,109.44,43.26,109.46z"/>
</g>
</svg>

The button highlight gets parsed as if it has full opacity, e.g.

image

Internally, this is because usvg parses it into this Path:

Path(Path { id: "", visibility: Visible, fill: Some(Fill { paint: Color(Color { red: 255, green: 255, blue: 255 }), opacity: NormalizedF32(FiniteF32(1.0)), rule: NonZero }), stroke: None, paint_order: FillAndStroke, rendering_mode: GeometricPrecision, data: Path { segments: "M 40.16 12.86 C 40.16 10.56 38.56 9.86 29.36 10.16 C 21.66 10.46 17.86 11.36 15.56 14.16 C 13.26 16.96 12.66 22.66 12.56 29.46 C 12.56 34.26 12.56 38.76 15.06 38.76 C 18.46 38.76 18.46 30.86 21.26 26.46 C 26.66 17.76 40.16 15.86 40.16 12.86 Z", bounds: Rect { left: 12.56, top: 9.86, right: 40.16, bottom: 38.76 } } })

It never reads opacity

LaurenzV commented 9 months ago

Are you sure you are using the newest version? It renders fine for me:

test

simbleau commented 9 months ago

It uses 0.37, but I didn't see anything in the changelog to address opacity parsing.

LaurenzV commented 9 months ago

I tried it on v0.37 and it also works fine there. :/

simbleau commented 9 months ago

This applies to usvg, not resvg.

I'm not sure how yours is rendering correctly. The path is parsed into this:

Path(Path { id: "", visibility: Visible, fill: Some(Fill { paint: Color(Color { red: 255, green: 255, blue: 255 }), opacity: NormalizedF32(FiniteF32(1.0)), rule: NonZero }), stroke: None, paint_order: FillAndStroke, rendering_mode: GeometricPrecision, data: Path { segments: "M 40.16 12.86 C 40.16 10.56 38.56 9.86 29.36 10.16 C 21.66 10.46 17.86 11.36 15.56 14.16 C 13.26 16.96 12.66 22.66 12.56 29.46 C 12.56 34.26 12.56 38.76 15.06 38.76 C 18.46 38.76 18.46 30.86 21.26 26.46 C 26.66 17.76 40.16 15.86 40.16 12.86 Z", bounds: Rect { left: 12.56, top: 9.86, right: 40.16, bottom: 38.76 } } })

Nothing in that string says 0.3 opacity, infact it says 1.0 opacity.

simbleau commented 9 months ago

Dually mentioned, I am rendering the svg using vello, not resvg. If this works in resvg, I must be missing where the 0.3 opacity is passed down. usvg parses the tree without opacity on my end.

RazrFalcon commented 9 months ago

Nothing in that string says 0.3 opacity, infact it says 1.0 opacity.

This is because opacity can only be set on groups. The opacity you're looking at is fill-opacity. I guess this is just a vello bug then. You have to look at path's parent node to get opacity.

simbleau commented 9 months ago

Nothing in that string says 0.3 opacity, infact it says 1.0 opacity.

This is because opacity can only be set on groups. The opacity you're looking at is fill-opacity. I guess this is just a vello bug then. You have to look at path's parent node to get opacity.

That seems weird. The SVG itself doesn't have groups?

Are groups only a logical implementation, not part of SVG itself?

RazrFalcon commented 9 months ago

In SVG:

<path opacity="0.5"/>

is just a syntax sugar for:

<g opacity="0.5">
    <path/>
</g>

If you look at vello SVG implementation it's insanely primitive and you probably shouldn't be using it.

The SVG itself doesn't have groups?

If you mean something like Photoshop groups then no. See: https://razrfalcon.github.io/notes-on-svg-parsing/isolated-groups.html

simbleau commented 9 months ago
<path opacity="0.5"/>

is just a syntax sugar for:

<g opacity="0.5">
    <path/>
</g>

Ah, this is great info! I'll close the issue, then.

If you look at vello SVG implementation it's insanely primitive and you probably shouldn't be using it.

Actually I asked because I'm trying to contribute to vello.

RazrFalcon commented 9 months ago

I see. Good luck. I think vello needs a couple of more years to be good enough for a proper SVG renderer.

simbleau commented 9 months ago

My motivation is only to get it compatible with the outputs of simpler tooling like Figma and LottieLab so it can be used for realtime graphics applications like Figma.

RazrFalcon commented 9 months ago

Afaik, Figma supports complex stroking (caps, joins, dashing) and SVG filters (mainly blur). vello doesn't support this at the moment. But you can use tiny_skia::Path::stroke to get fill-ready stroke path. Not sure how well it would work.

Either way, good luck. SVG is a monster.