text2png icon indicating copy to clipboard operation
text2png copied to clipboard

Rendered font is smaller than declared font-size

Open robbytx opened this issue 8 years ago • 6 comments

Using https://github.com/image-size/image-size:

> require('image-size')(require('text2png')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 31, height: 8, type: 'png' }
> require('image-size')(require('text2png')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 17, type: 'png' }

It appears that the problem is the use of actualBoundingBoxAscent/Descent rather than emHeightAscent/Descent, since if I switch the code to use those references, I get:

> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 31, height: 12, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 24, type: 'png' }

Furthermore, because the canvas is properly sized, the text is rendered much clearer.

https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics has a description of the difference of the metrics.

robbytx avatar Aug 03 '17 22:08 robbytx

The above behavior was reproduced on:

$ npm ls
└─┬ [email protected]
  └─┬ [email protected]
    ├── [email protected]
    ├─┬ [email protected]
    │ ├── [email protected]
    │ ├── [email protected]
    │ ├── [email protected]
    │ ├── [email protected]
    │ ├── [email protected]
    │ ├─┬ [email protected]
    │ │ └── [email protected] deduped
    │ ├── [email protected]
    │ ├── [email protected]
    │ └── [email protected]
    └─┬ [email protected]
      ├── [email protected]
      └── [email protected]

$ brew info cairo
cairo: stable 1.14.10 (bottled), HEAD
Vector graphics library with cross-device output support
https://cairographics.org/
/usr/local/Cellar/cairo/1.14.10 (118 files, 5.9MB) *
  Poured from bottle on 2017-06-22 at 14:37:54
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/cairo.rb

robbytx avatar Aug 03 '17 23:08 robbytx

With cairo 1.12.14 on Amazon Linux, it behaves quite differently:

$ rpm -q cairo cairo-devel
cairo-1.12.14-6.8.amzn1.x86_64
cairo-devel-1.12.14-6.8.amzn1.x86_64

$ node
> require('image-size')(require('text2png')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 35, height: 10, type: 'png' }
> require('image-size')(require('text2png')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 36, height: 20, type: 'png' }
# versus:
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 35, height: 15, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 36, height: 30, type: 'png' }

robbytx avatar Aug 03 '17 23:08 robbytx

One difference on Mac was that I didn't have "pango" installed. Once I installed that, text2png behaves similarly across the two platforms. However, using emHeightAscent/Descent still differs:

$ brew info pango
pango: stable 1.40.7 (bottled), HEAD
Framework for layout and rendering of i18n text
http://www.pango.org/
/usr/local/Cellar/pango/1.40.7 (105 files, 4.4MB) *
  Poured from bottle on 2017-08-03 at 18:59:23
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/pango.rb

$ node
> require('image-size')(require('text2png')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 10, type: 'png' }
> require('image-size')(require('text2png')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 20, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 12, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1\nLine 2', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 33, height: 24, type: 'png' }

It still seems that using emHeightAscent/Descent is the correct value, but I'm not sure why it returns 15px for a 12px font on Amazon Linux.

robbytx avatar Aug 04 '17 00:08 robbytx

Hmm... well after installing Arial from msttcorefonts and installing Helvetica via fondu Helvetica.dfont using fondu, I got the Linux metrics closer to correct:

$ node
> require('image-size')(require('text2png')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 35, height: 10, type: 'png' }
> require('image-size')(require('text2png')('Line 1', {font: '12px Arial', padding: 0, lineSpacing: 0}))
{ width: 34, height: 8, type: 'png' }
> require('image-size')(require('text2png')('Line 1', {font: '12px Helvetica', padding: 0, lineSpacing: 0}))
{ width: 33, height: 9, type: 'png' }

> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 35, height: 15, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px Arial', padding: 0, lineSpacing: 0}))
{ width: 34, height: 14, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '12px Helvetica', padding: 0, lineSpacing: 0}))
{ width: 33, height: 13, type: 'png' }

I continue to believe that emHeightAscent/Descent is more correct, given the differences when using larger font sizes (31px is a lot closer to 30px than 22px is):

> require('image-size')(require('text2png')('Line 1', {font: '30px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 94, height: 23, type: 'png' }
> require('image-size')(require('text2png')('Line 1', {font: '30px Arial', padding: 0, lineSpacing: 0}))
{ width: 83, height: 22, type: 'png' }
> require('image-size')(require('text2png')('Line 1', {font: '30px Helvetica', padding: 0, lineSpacing: 0}))
{ width: 83, height: 22, type: 'png' }

> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '30px sans-serif', padding: 0, lineSpacing: 0}))
{ width: 94, height: 36, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '30px Arial', padding: 0, lineSpacing: 0}))
{ width: 83, height: 35, type: 'png' }
> require('image-size')(require('./text2png-using-emheight')('Line 1', {font: '30px Helvetica', padding: 0, lineSpacing: 0}))
{ width: 83, height: 31, type: 'png' }

robbytx avatar Aug 04 '17 01:08 robbytx

Thank you for reporting! I have confirmed this font size problem, but I am not sure yet...

The difference of actualBoundingBox and emHeight does not affect font-size but line-spacing. I think it is not related to this problem.

example:

fs.writeFileSync('hoge.png', text2png('Line1\nLine2', {
  font: '24px sans-serif',
  bgColor: 'green',
  textColor: 'white',
  padding: 0,
  lineSpacing: 0
}));

results: actualBoundingBox actualboundingbox emHeight emheight

same font-size (and both look small)

tkrkt avatar Aug 07 '17 18:08 tkrkt

In my tests, at least for single-line messages, it seemed that the rendered font was shrunk because the canvas was smaller than expected. When the canvas was the proper size, it seemed that the font was rendered at the expected size, and therefore was rendered more clearly (at least on Mac OS X).

robbytx avatar Aug 11 '17 21:08 robbytx