yisibl/resvg-js

Cannot render svg with image on `2.4.1`

Jackie1210 opened this issue · 16 comments

Follow up the background with #256

This is second issue:

<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><mask id="satori_om-id"><rect x="0" y="0" width="100" height="100" fill="#fff"/></mask><rect x="0" y="0" width="100" height="100" fill="#fff"/><clipPath id="satori_cp-id-0"><rect x="0" y="0" width="100" height="100"/></clipPath><mask id="satori_om-id-0"><rect x="0" y="0" width="100" height="100" fill="#fff"/></mask><image x="0" y="0" width="100" height="100" href="data:image/svg+xml;utf8,%3Csvg  fill=%22none%22 xmlns=%22http://www.w3.org/2000/svg%22 width=%22100%22 height=%22100%22 viewBox=%220 0 100 100%22%3E%3Cimage id=%22image0_1_2%22 width=%22100%22 height=%22100%22 href=%22data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNiAzNiI+PHBhdGggZmlsbD0iI0ZGQ0M0RCIgZD0iTTM2IDE4YzAgOS45NDEtOC4wNTkgMTgtMTggMTgtOS45NCAwLTE4LTguMDU5LTE4LTE4QzAgOC4wNiA4LjA2IDAgMTggMGM5Ljk0MSAwIDE4IDguMDYgMTggMTgiLz48ZWxsaXBzZSBmaWxsPSIjNjY0NTAwIiBjeD0iMTEuNSIgY3k9IjEyLjUiIHJ4PSIyLjUiIHJ5PSI1LjUiLz48ZWxsaXBzZSBmaWxsPSIjNjY0NTAwIiBjeD0iMjQuNSIgY3k9IjEyLjUiIHJ4PSIyLjUiIHJ5PSI1LjUiLz48cGF0aCBmaWxsPSIjNjY0NTAwIiBkPSJNMTggMjJjLTMuNjIzIDAtNi4wMjctLjQyMi05LTEtLjY3OS0uMTMxLTIgMC0yIDIgMCA0IDQuNTk1IDkgMTEgOSA2LjQwNCAwIDExLTUgMTEtOSAwLTItMS4zMjEtMi4xMzItMi0yLTIuOTczLjU3OC01LjM3NyAxLTkgMXoiLz48cGF0aCBmaWxsPSIjRkZGIiBkPSJNOSAyM3MzIDEgOSAxIDktMSA5LTEtMiA0LTkgNC05LTQtOS00eiIvPjwvc3ZnPg==%22%3E%3C/image%3E%3C/svg%3E" preserveAspectRatio="none" clip-path="url(#satori_cp-id-0)" mask="url(#satori_om-id-0)"/><mask id="satori_om-id-0-0"><rect x="0" y="0" width="0" height="100" fill="#fff"/></mask></svg>
yisibl commented

This is an <image> nested within an <image>, which we don't currently support and which requires further research.

image

For your test case, you can just remove the nesting and resvg-js will render it.

yisibl commented

This looks like the same issue as #254.

@yisibl Actually, it rendered correctly before i upgrade to 2.4.1

I have a similar issue. This is the svg code

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
>
 <image x="0" y="0" width="140" height="48" xlink:href="https://touchplan.io/wp-content/uploads/2021/07/Demo-Company-Logo.jpeg" />
</svg>

This is the logging info

[2023-09-21T14:40:23Z WARN  resvg::image] Failed to load an embedded raw image.
zimond commented

@dkyeremeh can you try if #258 fixes your problem?

yisibl commented

@dkyeremeh I confirm that your case can be rendered.

Load the http image you need to refer to example/image-url.js

This is an <image> nested within an <image>, which we don't currently support and which requires further research.

image

For your test case, you can just remove the nesting and resvg-js will render it.

The reason why we cannot simply remove one of href, please check this case

zimond commented

@Jackie1210 <image> tag inside an embedded base64 href is against the spec. And I think resvg does not support it on purpose. https://github.com/RazrFalcon/resvg/blob/master/crates/usvg-parser/src/image.rs#L225

zimond commented

I believe you can use <svg> tag inside <svg> to get what you want. No need to base64 wrap every layer.

<image> tag inside an embedded base64 href is against the spec

Can you show me the spec's link cuz i haven't found any proof.

zimond commented

@Jackie1210 https://www.w3.org/TR/SVG/embedded.html#ImageElementHrefAttribute

Since image references always refer to a complete document, a target-only URL is treated as a link to the same file, which is rendered again as an independent embedded image. Since the embedded image is processed in a secure mode, its own embedded references are not processed, preventing infinite recursion.

@dkyeremeh I confirm that your case can be rendered.

Load the http image you need to refer to example/image-url.js

I will try it out. On the other hand I would like to find out if there's a reason why images are not auto-loaded?

<?xml version="1.0" encoding="utf-8"?>
<svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px"
>
 <image x="0" y="0" width="140" height="48" xlink:href="https://touchplan.io/wp-content/uploads/2021/07/Demo-Company-Logo.jpeg" />
</svg>

It works. Thanks

@Jackie1210 https://www.w3.org/TR/SVG/embedded.html#ImageElementHrefAttribute

Since image references always refer to a complete document, a target-only URL is treated as a link to the same file, which is rendered again as an independent embedded image. Since the embedded image is processed in a secure mode, its own embedded references are not processed, preventing infinite recursion.

Thanks for your feedback, but use case I gave does work in most browser, so it just confuse me. 😢

zimond commented

@dkyeremeh because fetching network resource is always not safe, so we leave it as a user-motivated action instead of hiding this inside the library

zimond commented

@Jackie1210 again, I think you can use <svg> inside <svg> to get what you need.