tsayen / dom-to-image

Generates an image from a DOM node using HTML5 canvas
Other
10.34k stars 1.68k forks source link

3 pixel padding rendered below SVG (Chrome). #51

Closed john-m-adams closed 8 years ago

john-m-adams commented 8 years ago

Update: Appears to be a Chrome Bug, see comment.

In testing the library, I found the resultant image was larger than the dom element I was trying to capture.

There appears to be 3 extra pixels of height rendered below SVG elements. I've found the simplest case that illustrates: [https://jsfiddle.net/8kx0una9/]

A 100x100 pixel div, containing a 100x100 pixel SVG containing a 100x100 pixel path element. Chrome inspector verifies all three elements rendered as 100x100 px (Version 52.0.2743.82 m) Firefox (Version 47.0.1) produces a 100x100px image, as expected.

toPng() creates a png of the div at 100x103, with the extra 100x3 pixels as transparent. toJpeg() creates a jpeg of the div at 100x103, with the extra 100x3 pixels as black.

Various Observations:

In the above fiddle, I could not get toPng() or toJpeg() to successfully render the SVG element directly (I don't know if that would be a separate bug, or a feature request).

Thanks for the work, btw... this looks almost perfect for my needs.

john-m-adams commented 8 years ago

This appears to be caused by a bug in Chrome. Inspector shows 100x100 on all elements, but then adding:

console.log(document.getElementById('theDiv').scrollHeight);

...outputs '100' in Firefox, but '103' in Chrome. I don't see a reason why.

toSvg() uses the scrollHeight property of the node unless a height is explicitly set, which as far as I can reason is correct (unless the node is styled overflow:hidden).

If Chrome is mis-reporting, I don't know that it would be easy or desirable to try to compensate for it.

Feel free to close this... or leave it open and watch for a fix in Chrome.

Edit: this fiddle shows the scrollHeight bug.

tsayen commented 8 years ago

Hi!. Wow, thank you for such thorough investigation! Did you consider posting a bug report in Chrome/Chromium repo?
Lib uses scrollHeight to be able to render elements which are scrolled and thus not fully visible. I'm afraid that trying to compensate for this bug will introduce some other subtle bugs. It's interesting that only SVG is affected though (because if it was not only SVG, the tests would be failing). I'll think about what to do with this bug.
Thank you once again for investigating on that!

john-m-adams commented 8 years ago

I reported in the Chrome Browser -> Help -> Report an issue, but I hadn't yet looked into checking upstream to chromium for the bug. Hadn't checked Safari / other webkit yet either.

I did a lot of fiddling back and forth... and at one point I think I saw it add that padding below an img tag too... but I haven't reproduced it again, yet.

In my application I should be able to compensate, because I'm pretty sure every case I'll use it for, I should already know the dimensions before the call, so I can set it explicitly.

john-m-adams commented 8 years ago

scrollHeight bug confirmed present in Safari (but it's showing 4 px extra).

tsayen commented 8 years ago

after some thought I decided not to compensate for the Chrome bug in any way, as it will (hopefully) be fixed soon

weilinzung commented 6 years ago

I have the same issue, the image should be 240px X 400px, but after ToJpeg & download it that said it is 241px X 400px. And check orginal image it is 240px X 400px, and the div set it as width: 240px; height: 400px; overflow: hidden.

oliverholliday commented 5 years ago

It isn't a bug, though it confused me (I got here from a google search)

The fix is to put display: block on your SVG element. https://stackoverflow.com/questions/24626908/how-to-get-rid-of-extra-space-below-svg-in-div-element

weilinzung commented 5 years ago

@oliverholliday already tested that which the issue remains.

pitus commented 3 years ago

Although the display: block is a working solution, I still consider this a bug, an annoying one too - just wasted hours of my time trying to figure it out until I found this thread. The svg handling is unique and specific to just this tag, nothing else:

Typically, elements add extra blank spacing if there's a SPACE in the HTML code and the usual way to get rid of it is to delete the SPACE (possibly splitting HTML tab into the next line when it's too long - closing brace).

In this case, however, no matter what I've tried the extra 3 pixels were always there and I would have NEVER guessed it myself that it needs the block display. Why does it? Why is svg behaving differently than other inline elements?

Also, note that even inline-block has the same issue (extra pixels) with svg while a simple span, with specific height and inline-block, renders correctly. Without the inline-block or block, the SPAN still renders correctly - can't set its height, but there's no gap between its bottom and the end of the containing DIV.

Heck, even a DIVwith display: inline renders correctly, without any extra gap so the extra 3 pixels are clearly not due to the displayproperty but have something to do with svgand only svgelement!

olliholliday commented 3 years ago

This is because inline-block elements (like \<svg> and \<img>) sit on the text baseline. The extra space you are seeing is the space left to accommodate character descenders (the tail on 'y', 'g' etc).

pitus commented 3 years ago

This is because inline-block elements (like and ) sit on the text baseline. The extra space you are seeing is the space left to accommodate character descenders (the tail on 'y', 'g' etc).

I don't think I follow. If I draw an outline via CSS around each element then it will include the space for descenders, will it not? And if there's an outline in the containing element then the bottom of the last child's outline should overlay the bottom of the parent's outline, shouldn't it? In fact, that's the case for all elements I've tried, except for the svg.