Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement inline SVG rendering #267

Closed
SunboX opened this issue Sep 9, 2013 · 29 comments
Closed

implement inline SVG rendering #267

SunboX opened this issue Sep 9, 2013 · 29 comments
Labels

Comments

@SunboX
Copy link

SunboX commented Sep 9, 2013

... to render Ext JS Charts:

http://docs.sencha.com/extjs/4.2.1/extjs-build/examples/charts/Area.html

@SunboX
Copy link
Author

SunboX commented Sep 10, 2013

could be implemented like this:

var img = new Image(); 
// here attach an onload handler that draws the image on the canvas  

// svgSource is the raw svg xml 
img.src = "data:image/svg+xml," + encodeURIComponent(svgSource);

@niklasvh
Copy link
Owner

SVG images taint the canvas in Chrome. https://code.google.com/p/chromium/issues/detail?id=68568

Firefox supported this without tainting the canvas from v11 or 12 onwards.

A bugfix landed 6 days ago that addressed it for non foreignObject svg's though.
https://code.google.com/p/chromium/issues/detail?id=249037

@SunboX
Copy link
Author

SunboX commented Sep 10, 2013

Oh, thx! Nice to know! But we should implement this without taking care of browser issues. By now svg images didn't get rendered at all. Maybe we should exclude browsers that will "destroy" the canvas when drawing svg images.

@niklasvh
Copy link
Owner

Setting allowTaint: true should do exactly that. But now that I think about it, I'm not sure it does.

@SunboX
Copy link
Author

SunboX commented Sep 10, 2013

Hmmm, how does http://fabricjs.com/ handle it?

@niklasvh
Copy link
Owner

Presumably same way as canvg and the others, by actually rendering SVG elements manually to canvas.

@SunboX
Copy link
Author

SunboX commented Sep 10, 2013

Fabric.js is open source, can we take the parts to render svg from it? https://github.com/kangax/fabric.js

@SunboX
Copy link
Author

SunboX commented Sep 10, 2013

Related issues (just for reference):

#95
#197
#201
#255

@niklasvh
Copy link
Owner

I'm not really keen on embedding a library +5x the size of html2canvas just to support SVG images.

Alternatively, users who need SVG rendering could use one of those libraries to convert the SVG's to canvas before running html2canvas. Besides, once the bug fix lands in Chrome this issue can be resolved for the majority of browsers by just using the native image rendering implementation.

@ydanneg
Copy link

ydanneg commented Nov 15, 2013

Can you add a callback with the svg element to allow users to fallback rendered image using 3rd party tools like canvg?
This way would be flexible and does not require additional dependencies into your wonderful tool.

@usmonster
Copy link
Contributor

FYI, the <foreignObject> part (Chrome bug) can be tracked here:
https://crbug.com/294129

@usmonster usmonster mentioned this issue Sep 1, 2014
@kevinoid
Copy link

@niklasvh, could you comment on the current plans for inline SVG support? From looking at the code, it appears that inline SVG is only supported when using the build that includes fabric.js (html2canvas.svg.js), even on browsers which support rendering SVG to canvas natively (current Firefox, IE, and Chrome whenever foreignObject is not present - I'm unsure about other browsers). Is this correct?

Is there a reason that fabric.js isn't used as a fallback to native rendering, rather than the primary rendering method? Or is the current implementation just temporary? Given the current wide support, it seems like many common cases would be well covered without the extra overhead and loss of fidelity of using fabric.js.

It also appears that the presence of inline SVG, when the build with fabric.js is not used, causes the rendering process to fail. This seems pretty draconian compared to the behavior of 0.4 where unsupported elements were ignored. Developers could certainly wrap all calls to html2canvas with a function to remove any non-critical inline SVG (icons and the like), but that seems sub-optimal. Is there any chance the previous behavior could be made available (as an option, if not by default)?

Thanks for all of your effort on this issue!

@niklasvh
Copy link
Owner

If any of the above cases aren't true, then there is a bug in which case could you please provide an example test. Hope that answers your questions

@kevinoid
Copy link

Hey @niklasvh, thanks for the thorough response, I really appreciate it! Also great to hear that support for partial image loading is being considered.

Perhaps I was mistaken about how/when fabric is used. So to demonstrate the issue I created the following plunkr: http://run.plnkr.co/UsnuptYpKe8dPFPG/ It contains a simple inline SVG without a <foreignObject>. My understanding is that it should render natively on all current browsers. However, attempting to render results in Error: html2canvas.svg.js is not loaded, cannot render svg.

After tracing through the code, it appears that SVGNodeContainer is always instantiated for inline <svg> elements (imageloader.js:70) and that SVGNodeContainer always requires fabric.js (svgnodecontainer.js:8).

Am I misreading the code or misunderstanding how to use it?

Thanks again.

@niklasvh
Copy link
Owner

@kevinoid you are right, that's how it should work. 0a7df6d should fix it.

All 4 different forms of svg should work correctly now:
https://github.com/niklasvh/html2canvas/blob/master/tests/cases/images/svg/native_only.html

@kevinoid
Copy link

Thanks @niklasvh! That works great for my use cases. I really appreciate the quick fix!

I don't mean to be critical, but it appears that 0a7df6d doesn't check for foreignObject support, so an inline SVG which contains a foreignObject on Chrome will cause the canvas to be tainted whether or not fabric.js is available. Was this intentional? I don't have any problem with it, but I imagine it will complicate some use cases. Updated Plunker to demonstrate.

@niklasvh
Copy link
Owner

By default, allowTaint is set to false, (https://github.com/niklasvh/html2canvas/blob/master/src/core.js#L11) so it should skip all images that end up tainting the canvas (https://github.com/niklasvh/html2canvas/blob/master/src/renderers/canvas.js#L45). It can't fallback to fabric either, since it doesn't support foreignObject (although fabric could use html2canvas for it)

But again, if that's not the case, then there is another bug.

Your example is 404.

@kevinoid
Copy link

I think there's a bug since the example is using the default options. But apparently I can't figure out how to use Plunker correctly (perhaps run.plnkr.co expires pages after a few minutes...). See if this works better: http://plnkr.co/edit/tM0yPWOUSjI4eDmIdvW4

@niklasvh
Copy link
Owner

I am getting Tainted: false on chrome 37.0.2062.120

@kevinoid
Copy link

Oh, interesting. I am getting tainted: true on Chromium 35.0.1916.153 Debian jessie/sid (274914). I wonder if foreignObject support has been added since then. I'll test with a newer version.

@niklasvh
Copy link
Owner

Still don't understand how it gets past the taint test for you, it should just skip the image altogether.

@kevinoid
Copy link

Still working on testing with the latest Chromium, but I think I might be able to shed some light on how it gets past the taint test: When taints is called with the SVGNodeContainer, the imageContainer.tainted === null test at https://github.com/niklasvh/html2canvas/blob/master/src/renderers/canvas.js#L30 is false because tainted is undefined so the testing is skipped.

@niklasvh
Copy link
Owner

That would explain it, thanks :)

@kevinoid
Copy link

Sure thing. I was also able to test on Chromium Version 39.0.2166.0 and it didn't taint the canvas. Awesome!

@wiesson
Copy link

wiesson commented Dec 9, 2014

I'm trying to use this with Highcharts -> Example: http://jsfiddle.net/wiesson/9pbxode0 (just click on the small print button)- It works perfectly with chrome on my Mac, but how to render the SVG correctly on Windows (Chrome)?

Example Chrome Windows:
chrome_windows

Example Chrome Mac:
download

If you tell me, how to contribute to your tests, I would like to add some Highcharts tests.

@usmonster
Copy link
Contributor

I'm seeing the same on Chrome/Linux (Debian wheezy, x64), though it looks fine if I remove either one of the inline color or fill styles from the city names before I click "Print". Haven't looked at the code, but it seems like h2c is maybe parsing both values separately and double-drawing, possibly using the wrong font for one of them.

Not completely sure why this doesn't affect Chrome on Mac, but I'm guessing it's related to #479. In the meantime, I implemented a workaround based on the one suggested in highcharts/highcharts#1428 (comment), which should work on all platforms:

http://jsfiddle.net/0p4z1mfj/20/

With the magic sauce being:

chart: {
    // ...
    style: {
        fontFamily: 'Verdana, Arial, Helvetica, sans-serif'
    }
    // ...

The default font family starts with "Lucida Grande", "Lucida Sans Unicode", which I'm betting is on your Mac but not your Windows machine..

@wiesson
Copy link

wiesson commented Dec 9, 2014

Can you update my example?

@usmonster
Copy link
Contributor

Updated my comment.

@wiesson
Copy link

wiesson commented Dec 9, 2014

You are right thanks! Here is another example, now with Highstocks: http://jsfiddle.net/wiesson/1rn51t0g - looks definitly more worse than Highcharts ;)

Ok, I found a workaround in issue #95 .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants