canvg
canvg copied to clipboard
Canvas and SVG render results are different
Canvas and SVG render results are different, as follows:
canvg result:
svg result:
svg code:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="图层_1" x="0px" y="0px" viewBox="0 0 1000 600" enable-background="new 0 0 1000 600" xml:space="preserve" style="width: 583.333px; height: 350px;">
<g id="c_105_" opacity="0.85">
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="331.7825" y1="-749.6113" x2="553.6317" y2="-352.8736" gradientTransform="matrix(0.9996 2.833383e-02 2.833383e-02 -0.9996 106.1187 -138.3644)">
<stop offset="0.2354" style="stop-color:#225CFF"/>
<stop offset="0.4433" style="stop-color:#91AEFF"/>
<stop offset="0.6243" style="stop-color:#225CFF"/>
<stop offset="0.9118" style="stop-color:#225CFF"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M569.5,310.5c0,0-82.9,105.6-154.3,109c-71.4,3.4-255.4-120.4-285.7-81 c-63.5,36,3.8,117.3,36,107.6c70.5-21.2,136.9-18,97.7,12c-39.3,30,35.9,29.1,74.3,28.4c38.4-0.7,79.7-43.4,152-12 c72.3,31.4,47.6,68.7,140,34.8s50.1-76.6,172-51.2c121.9,25.5,23.1,163,99.7,101.2c68.6-55.4,82.6-121.5,39.7-159.3 s-135.5-60.7-135.5-60.7L569.5,310.5z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="487.5439" y1="377.6481" x2="663.0073" y2="553.1114" gradientTransform="matrix(0.9871 -0.1599 -0.133 -0.8208 167.9462 844.796)">
<stop offset="0" style="stop-color:#FF003A"/>
<stop offset="1" style="stop-color:#FF837F"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M480.7,306.8c-64.6,46.1-81.6,79.5-29.1,117.2c52.5,37.8,194.5,22.5,270.3-12.8 s153.5-92.6,232.4-63.7c0,0-103.1-52.7-219.3-72.5C618.7,255.2,542.1,263,480.7,306.8z"/>
</g>
</g>
<g id="c_109_" opacity="0.85">
<g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1721.9917" y1="-417.6683" x2="1473.6665" y2="-643.0983" gradientTransform="matrix(0.9997 -2.570367e-02 -2.210279e-02 -0.8596 -1346.933 -212.363)">
<stop offset="0" style="stop-color:#FF4E00"/>
<stop offset="1" style="stop-color:#FFB696"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M236.9,86.4c0,0,54,41.1,25.4,96.4c-28.5,55.3-79.8,80.9-137.8,89.1c-57.9,8.3-111.4,20.3-60,28.8 c51.3,8.6,239.8,5.3,341.6-79.9c101.7-85.2,60.5-111.5,53-129.5S383,45.5,319.1,63C255.2,80.6,236.9,86.4,236.9,86.4z"/>
<g>
<path fill="#FFD833" d="M456,87.9c0,0-74.6-29.4-111.3,9.2c-41.6,43.8-60.3,102.8-122.2,108.4s-94.6-26.7-75.9-72.2 c18.8-45.4,78.1-86.7,159.9-94.4C388.3,31.3,433.2,59.8,456,87.9z"/>
</g>
</g>
</g>
</svg>
yea it's kind of a regression from https://github.com/canvg/canvg/pull/602/files ...
i'm not treating the g
element differently but it appears that the group opacity applies to the group, not to the individual elements. this present a challenge when working w/ html5 canvas as you can only have a global opacity.
for example:
<svg>
<g opacity="0.5">
<rect x="0" y="0" width="100" height="100" fill="red" />
<rect x="50" y="50" width="100" height="100" fill="green" />
</g>
</svg>
the rectangles should both be pale colored due to the 0.5 but the green should sit on top of the red. canvg unfortunately has an overlap area:
i think we'll need to change the handling of g
to render in temporary canvas, then apply opacity and render in the main canvas for it to be truly working.
@gabelerner Thanks for your help! Has it been released in version 1.5.2 ?
this issue hasn't been fixed until somebody (or me) writes code for it. i'm just documenting for now.
Well, thank you all the same.
It sounds like we'd need to build an analog of getComputedStyle
for SVG so they can inherit the opacity from parents g
and we can treat groups as non-opaque.
@gabelerner I'm seeing that the gradientTransform
for the first group is messing with the canvas cropping:
If I remove said property from the first group, the canvas doesn't crop (of course, the gradient is lost in the SVG element so this is just a comment)
It seems the logic for parsing a gradient with matrix type transform is affecting the calculated size of the output, which shouldn't be since the definition of the gradient is not an element by itself.
@gabelerner another comment:
If we take just the second group (I'm adjusting its size and viewbox for the example)
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="图层_1" x="0px" y="0px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve" style="width: 300px; height: 300px;">
<g id="c_109_" opacity="0.85">
<g>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1721.9917" y1="-417.6683" x2="1473.6665" y2="-643.0983" gradientTransform="matrix(0.9997 -2.570367e-02 -2.210279e-02 -0.8596 -1346.933 -212.363)">
<stop offset="0" style="stop-color:#FF4E00"/>
<stop offset="1" style="stop-color:#FFB696"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M236.9,86.4c0,0,54,41.1,25.4,96.4c-28.5,55.3-79.8,80.9-137.8,89.1c-57.9,8.3-111.4,20.3-60,28.8 c51.3,8.6,239.8,5.3,341.6-79.9c101.7-85.2,60.5-111.5,53-129.5S383,45.5,319.1,63C255.2,80.6,236.9,86.4,236.9,86.4z"/>
<g>
<path fill="#FFD833" d="M456,87.9c0,0-74.6-29.4-111.3,9.2c-41.6,43.8-60.3,102.8-122.2,108.4s-94.6-26.7-75.9-72.2 c18.8-45.4,78.1-86.7,159.9-94.4C388.3,31.3,433.2,59.8,456,87.9z"/>
</g>
</g>
</g>
</svg>
The problem can be seen as:
But if we unnest the groups, as in:
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="图层_1" x="0px" y="0px" viewBox="0 0 600 600" enable-background="new 0 0 600 600" xml:space="preserve" style="width: 300px; height: 300px;">
<g id="c_109_" opacity="0.85">
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1721.9917" y1="-417.6683" x2="1473.6665" y2="-643.0983" gradientTransform="matrix(0.9997 -2.570367e-02 -2.210279e-02 -0.8596 -1346.933 -212.363)">
<stop offset="0" style="stop-color:#FF4E00"/>
<stop offset="1" style="stop-color:#FFB696"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M236.9,86.4c0,0,54,41.1,25.4,96.4c-28.5,55.3-79.8,80.9-137.8,89.1c-57.9,8.3-111.4,20.3-60,28.8 c51.3,8.6,239.8,5.3,341.6-79.9c101.7-85.2,60.5-111.5,53-129.5S383,45.5,319.1,63C255.2,80.6,236.9,86.4,236.9,86.4z"/>
</g>
<g>
<path fill="#FFD833" d="M456,87.9c0,0-74.6-29.4-111.3,9.2c-41.6,43.8-60.3,102.8-122.2,108.4s-94.6-26.7-75.9-72.2 c18.8-45.4,78.1-86.7,159.9-94.4C388.3,31.3,433.2,59.8,456,87.9z"/>
</g>
</svg>
The opacity of the background group doesn't affect the front path fill
Again, I don't know if unnesting groups would be of any help, since there are plenty scenarios where they should be nested indeed.
Hi folks. Here's a separate reduction of a similar issue (I believe), involving just a single rect
.
Entering this svg on the test page:
<svg>
<rect x="10" y="10" width="100" height="100" fill="#888" stroke-width="6" stroke="#888" opacity="0.5">
</rect>
</svg>
produces this output:

The stroke and fill appear to have their opacity applied separately, leading to the stroke/fill overlap being darker. Applying the opacity
value to both together ought to produce a flat color, as on the right.