yisibl / resvg-js

A high-performance SVG renderer and toolkit, powered by Rust based resvg and napi-rs.
https://resvg-js.vercel.app/
Mozilla Public License 2.0
1.54k stars 53 forks source link

PNG output rendering issue #332

Open aquaductape opened 4 months ago

aquaductape commented 4 months ago

The input svg file is a circle with gradients. The issue is that on the output png file, on the very right of the circle the gradient is cut off showing a sharp line.

Input svg file.

Screenshot 2024-05-01 at 3 12 20 PM

Output png file.

Screenshot 2024-05-01 at 3 13 08 PM

Input svg code.

<svg
  data-hk="undefinedNaN-0"
  viewBox="0 0 80 80"
  fill="none"
  role="img"
  xmlns="http://www.w3.org/2000/svg"
  width="80"
  height="80"
>
  <!--$--><!--/-->
  <defs>
    <filter
      id="filter_0"
      filterUnits="userSpaceOnUse"
      color-interpolation-filters="sRGB"
    >
      <feFlood flood-opacity="0" result="BackgroundImageFix"></feFlood>
      <feBlend
        in="SourceGraphic"
        in2="BackgroundImageFix"
        result="shape"
      ></feBlend>
      <feGaussianBlur
        stdDeviation="7"
        result="effect1_foregroundBlur"
      ></feGaussianBlur>
    </filter>
  </defs>
  <mask id="0" maskUnits="userSpaceOnUse" x="0" y="0" width="80" height="80">
    <rect width="80" height="80" rx="160" fill="#FFFFFF"></rect>
  </mask>
  <g mask="url(#0)">
    <rect width="80" height="80" fill="#49007E"></rect>
    <path
      filter="url(#filter_0)"
      d="M32.414 59.35L50.376 70.5H72.5v-71H33.728L26.5 13.381l19.057 27.08L32.414 59.35z"
      fill="#FF005B"
      transform="translate(-2 2) rotate(-282 40 40) scale(1.5)"
    ></path>
    <path
      filter="url(#filter_0)"
      style="mix-blend-mode: overlay"
      d="M22.216 24L0 46.75l14.108 38.129L78 86l-3.081-59.276-22.378 4.005 12.972 20.186-23.35 27.395L22.215 24z"
      fill="#FF7D10"
      transform="translate(-3 -3) rotate(-243 40 40) scale(1.5)"
    ></path>
  </g>
</svg>
const svg = `` // svg string version from svg code example
const resvg = new Resvg(svg);
const pngData = resvg.render();
const pngBuffer = pngData.asPng();
await promises.writeFile(join(__dirname, "./text-out.png"), pngBuffer);
yisibl commented 4 months ago

I tested with the latest resvg from upstream and also got the wrong rendering, so please feedback to upstream.

aquaductape commented 4 months ago

I tested with the latest resvg from upstream and also got the wrong rendering, so please feedback to upstream.

Aight posted issue https://github.com/RazrFalcon/resvg/issues/760

vktrl commented 4 months ago

@aquaductape I found this issue because I'm doing exactly what you're doing - porting boring avatar marble to Node. I removed feGaussianBlur from the SVG and am now using Sharp to apply the blur:

sharp(svgBuffer).blur(amount).jpeg().toBuffer();

Turns out this is ~5x faster and the result is ~20x smaller.

   name                    hz      min      max     mean      p75      p99     p995     p999      rme  samples
 · marble Resvg PNG   20.5649  25.8698  70.7037  48.6264  60.7421  70.7037  70.7037  70.7037  ±19.48%       11  
 · marble Sharp JPEG  98.8347   8.8393  13.0902  10.1179  10.6770  13.0902  13.0902  13.0902   ±2.45%       50   fastest