Skip to content

Default HTML margin fix#220

Closed
vytenisu wants to merge 1 commit intocburgmer:masterfrom
vytenisu:default-html-margin-fix
Closed

Default HTML margin fix#220
vytenisu wants to merge 1 commit intocburgmer:masterfrom
vytenisu:default-html-margin-fix

Conversation

@vytenisu
Copy link

@vytenisu vytenisu commented Feb 3, 2022

When rendering HTML into foreignObject, its body had a default browser margin which caused inaccurate snapshot.

Off topic:
I was rendering SVG inside my HTML (because I wanted my SVG to work with CSS) and it seems that tool did not calculate content dimensions correctly - it was off by a few pixels even though SVG did not overflow. I have no idea why. To have a perfectly correct rasterized image, would need to look into this as well sometime.

@cburgmer
Copy link
Owner

cburgmer commented Feb 3, 2022

I'm trying to understand the issue, I remember something from the past: #78.

I see you added a unit test, but could you also add an integration test which would show the issue? I can help, if you provide just the HTML input that shows the issue.

@vytenisu
Copy link
Author

vytenisu commented Feb 3, 2022

Background:

I am working on a tool which allows drawing using SVG. I use SVG embedded directly into DOM which makes it easier to manipulate and style. However, browsers do not like many DOM objects and begin lagging so I am rasterizing parts of my SVG for faster execution.

At first I tried to simply put SVG into <image> as source to get same image without DOM elements in memory. It worked to some extent but I lost things like CSS, ability to overflow SVG tags, etc. I found that using your solution I can rasterize SVG and keep required styling functionality.

Basically my SVG is inside HTML, which is then put into foreignObject which is put back to SVG by your tool :D Honestly, I did not find a better solution.

Problem:

I noticed 2 problems when I tried using rasterizeHTML:

First - rasterizehtml slightly miscalculated SVG size. Resulting image was slightly bigger even though neither my HTML nor SVG inside it overflowed. I did not find the reason for this, so I implemented a simplified solution based on rasterizehtml and made sure I generate image of correct size in it. It would be great if it would be possible to override source HTML dimensions instead of calculating them. Currently it is only possible to override resulting image size.

Secondly - I then noticed that generated image does not match well when put directly under original SVG. After investigating I noticed that this was caused by margin on html body inside foreignObject. When i reset the margin - image matched original SVG perfectly. I noticed that margin was at fault by copying image source directly to Chrome and investigating spacing via developer tools.

Then I came back to rasterizehtml and since I borrowed a lot of amazing ideas from it - I wanted to give something back. Since I am quite sure that margin on body is not good for accurate rasterization, I added same fix which I have in my solution.


Content which I used for rasterization was quite complex but I was able to reproduce the issue with something as simple as:

<svg xmlns="http://www.w3.org/2000/svg"> <rect x="0" y="0" width="120" height="120" stroke="#37576D" fill="white" stroke-width="1"/> </svg>

Resulting image was appearing at slightly wrong location vertically.

@vytenisu
Copy link
Author

vytenisu commented Feb 3, 2022

#78 seems related at least partially. It is talking about HTML fragments. In my case I was dealing with HTML which was automatically added as a wrapper when using drawHTML. This wrapper caused padding.

@cburgmer
Copy link
Owner

cburgmer commented Feb 3, 2022

After some reading up on the old discussion I currently think you are exactly reporting what #78 describes.

Your goal is to pass an HTML element and just render that. However currently the drawHTML() method assumes you are passing a full blown HTML document. After all HTML5 allows under-specifying a document, and will fill in the missing html and body tag. So there is no way for the method to find out what your intentions are.

In my case I was dealing with HTML which was automatically added as a wrapper when using drawHTML.

So, it's not a wrapper provided by the library, but you are passing a full HTML element, with a body element that's implied.

The best way I still feel is to provide a dedicated method for what you want.

@cburgmer
Copy link
Owner

cburgmer commented Feb 4, 2022

So to summarise, merging this will break existing renderings by removing the margin/padding which the browser applies by default to body. We should rather make this an optional feature if the user wants to render a fragment of an html document and not a whole document.

@vytenisu
Copy link
Author

vytenisu commented Feb 4, 2022

Looks like I might have misused the tool :) Thnx for checking and probably this particular PR should then be closed without merging.

Tbh, I used a fraction of the logic to achieve what I need in my project - I did not need inlined styles, content size calculation, etc. so it made sense to write a very small function do the trick as opposed to using the full library. Hovever, it was very useful in the sense that it gave the idea on how this could be achieved. Many compliments for finding this amazing hack!

@vytenisu vytenisu closed this Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants