Html2canvas: Not Rendering ligatures

Created on 30 Mar 2016  路  7Comments  路  Source: niklasvh/html2canvas

Hi Im using html2canvas to generate a jpeg but "ff", "fl", and "fi"s are not rendering. See images below. Any reason why or has anyone else encountered this?

screen shot 2016-03-30 at 11 20 53 am
screen shot 2016-03-30 at 11 21 00 am

Most helpful comment

The problem

The problem (pointed out in the title) is with ligatures. Some fonts combine certain letters into a single character, especially fi, fl, and ff.

When html2canvas renders text letter-by-letter (triggered by having custom letter-spacing), it asks for the position of each letter, and when it gets to fi it gets the same location for the f and the i character, so it draws them on top of each other. You can find this in the code if you search for NodeParser.prototype.getRangeBounds.

The solution

The easiest solution is to use the CSS style font-feature-settings: "liga" 0 on the root element that you're capturing. You can do this programmatically just before you run html2canvas:

var el = document.getElementById('myElement');
el.style.fontFeatureSettings = '"liga" 0';
html2canvas(el, options);

The support for font-feature-settings is alright but not perfect; a better alternative would be font-variant-ligatures: none, but that's causing a strange interaction with html2canvas's parsing of fontVariant that I haven't figured out yet. For now, font-feature-settings does the job!

All 7 comments

Hi, I've also encountered the same issue.
I'm using the v0.4.1 - 7.9.2013 version of html2canvas and solved it by replacing line 1214 :
textList = (!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) ?

with
textList = (!options.letterRendering && /^(left|right|justify|auto|start|end|center)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) ?

The solution above doesn't work if css letter spacing is applied on the text...

Could anyone tell me the css that I would need to remove to get this to work for me as well? @mtskf

I changed this:

textList = (!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) ?
      textNode.nodeValue.split(/(\b| )/)
      : textNode.nodeValue.split("");

to this:

 textList = true ?
  textNode.nodeValue.split(/(\b| )/)
  : textNode.nodeValue.split("");

and that seemed to work for me

this will have a side effect on elements with css(word-wrap: break-word;)

I solve this problem using a condition to check if the word has "fi"
textList = ((!options.letterRendering && /^(left|right|justify|auto)$/.test(textAlign) && noLetterSpacing(getCSS(el, "letterSpacing"))) || (textNode.nodeValue.indexOf("fi") !== -1) ) ?

The problem

The problem (pointed out in the title) is with ligatures. Some fonts combine certain letters into a single character, especially fi, fl, and ff.

When html2canvas renders text letter-by-letter (triggered by having custom letter-spacing), it asks for the position of each letter, and when it gets to fi it gets the same location for the f and the i character, so it draws them on top of each other. You can find this in the code if you search for NodeParser.prototype.getRangeBounds.

The solution

The easiest solution is to use the CSS style font-feature-settings: "liga" 0 on the root element that you're capturing. You can do this programmatically just before you run html2canvas:

var el = document.getElementById('myElement');
el.style.fontFeatureSettings = '"liga" 0';
html2canvas(el, options);

The support for font-feature-settings is alright but not perfect; a better alternative would be font-variant-ligatures: none, but that's causing a strange interaction with html2canvas's parsing of fontVariant that I haven't figured out yet. For now, font-feature-settings does the job!

I'm still seeing this in 1.0.0-alpha.12 with the changes above on chrome, works fine out of the box on firefox

Was this page helpful?
0 / 5 - 0 ratings