niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.61k stars 4.81k forks source link

Weird spacing when font is loaded dynamically #2190

Open saurabhdaware opened 4 years ago

saurabhdaware commented 4 years ago

Please make sure you are testing with the latest release of html2canvas. Old versions are not supported and issues reported for them will be closed.

Please follow the general troubleshooting steps first:

Bug reports:

I am working on an application where the user can select a font with <input type="file" /> and then I have to take a screenshot of the div with that new font.

I am loading font using JavaScript and it does look correct in the div. but when I do html2canvas over that div, the spacing between words change.

When the font is loaded dynamically with font file upload using JavaScript: image

When I load the same font statically with CSS image

Steps to reproduce

Specifications:

IAmRC1 commented 4 years ago

use letterRendering: 1 on html2canvas 2nd arg that takes an object

saurabhdaware commented 4 years ago

use letterRendering: 1 on html2canvas 2nd arg that takes an object

Still not working properly.

const canvas = await html2canvas(document.querySelector("#text"), {letterRendering: 1});

Sandbox: https://codesandbox.io/s/dynamic-font-load-4q84e?file=/src/index.js:513-606

pxmage commented 3 years ago

Same here.

 letter-spacing: 0.01rem!important;

Worked for me, but this also means you cannot set letter-spacing anymore. I only have this bug on mobile safari.

ab-synth commented 3 years ago

I run into the same issue. letter-spacing and word-spacing doesn't help. Did you find any solution?

ab-synth commented 3 years ago

You can workaround it by appending style tag into the head instead of using FontFace interface to upload the custom font.

let markup = [
  '@font-face {\n',
  '\tfont-family: \'', fontFamilyName, '\';\n',
  '\tfont-style: \'normal\';\n',
  '\tfont-weight: \'normal\';\n',
  '\tsrc: url(\'', fontUrl, '\')\n',
  '}\n'
].join('');

const head = document.head || document.getElementsByTagName('head')[0];
let style =  document.createElement('style');
head.appendChild(style);
style.setAttribute('type', 'text/css');
style.innerHTML = markup;
saurabhdaware commented 3 years ago

Yup this should work. Though in my case, I want user to upload the font and then use that font so not sure how I can add it from style 🤔

ab-synth commented 3 years ago

I have the same use case. When you append <style /> tag in the <head/>, with the @font-face CSS, the browser will automatically load the font so it will be available for the user.