Automattic / node-canvas

Node canvas is a Cairo backed Canvas implementation for NodeJS.
10.2k stars 1.17k forks source link

Can't load custom fonts #2097

Open bielarusajed opened 2 years ago

bielarusajed commented 2 years ago

Issue

Can't load custom fonts that not installed to /usr/share/fonts/.

My font: https://fonts.google.com/specimen/Montserrat

It still loads fonts from /usr/share/fonts, but can't load fonts with registerFont

Steps to Reproduce

  1. Unzip font archive to Montserrat/ into script __dirname
  2. Run script:
    
    const path = require('path');
    const fs = require('fs');
    const { registerFont, createCanvas } = require('canvas');

registerFont(path.join(__dirname, 'Montserrat', 'static', 'Montserrat-Regular.ttf'), { family: 'Montserrat' });

const canvas = createCanvas(500, 500); const ctx = canvas.getContext('2d');

ctx.font = '48px Montserrat'; ctx.textAlign = 'center'; ctx.fillText('Test text 123', 250, 250);

canvas.createPNGStream().pipe(fs.createWriteStream('image.png'));



## Your Environment
* Version of node-canvas (output of `npm list canvas` or `yarn list canvas`): canvas@2.9.3
* Environment (e.g. node 4.2.0 on Mac OS X 10.8): `node v16.14.2`, `Linux fedora 5.18.17-200.fc36.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Aug 11 14:36:06 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux`
bielarusajed commented 2 years ago

Also, it works normally if I just remove registerFont and install font to system. But I need to load font from project directory.

virtulis commented 2 years ago

Can confirm the same problem with 2.9.1 to 2.9.3 in multiple Linux environments. Reverting to 2.9.0 helps so probably related to https://github.com/Automattic/node-canvas/pull/1987

This happens to some fonts but not others (even in the same family) and I can't figure out any pattern so far. But guessing it's related to naming somehow.

simonhaenisch commented 1 year ago

I'm just investigating a similar issue on linux (in Docker) where registerFont doesn't fail but also doesn't register the provided font, and I could figure out the following facts:

chearon commented 1 year ago

Yeah, #1987 created a new problem. It only worked with no font configuration files on the system. It turns out that the changes to FcConfig in that PR get overwritten later by what the OS provides, which creates a worse situation than before since we only set the postscript name field.

Trying to register and select custom fonts with OS APIs is just not going to work, so I'm waiting until Pango 2 is released to revamp the whole thing using their custom font APIs.

KevinUK commented 11 months ago

I have the same issue, I'm sure I had it working for a time with Canvas 2.10.2 on Node.js 18 LTS though.

Can you please tell me what version of Node.js you are running for Canvas 2.9.0? I get compilation errors when I downgrade Canvas.

I'm also using fabric.js so maybe I need to downgrade that at the same time.

"dependencies": { "canvas": "2.9.0", "fabric": "5.3.0", "fontfaceobserver": "2.3.0" }

npm ERR! Failed to execute '/opt/hostedtoolcache/node/18.19.0/x64/bin/node /opt/hostedtoolcache/node/18.19.0/x64/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js configure --fallback-to-build --module=/home/runner/work/node_modules/canvas/build/Release/canvas.node --module_name=canvas --module_path=/home/runner/work/node_modules/canvas/build/Release --napi_version=9 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1) npm ERR! node-pre-gyp info it worked if it ends with ok npm ERR! node-pre-gyp info using node-pre-gyp@1.0.11 npm ERR! node-pre-gyp info using node@18.19.0 | linux | x64 npm ERR! node-pre-gyp info check checked for "/home/runner/work/node_modules/canvas/build/Release/canvas.node" (not found)npm ERR! node-pre-gyp http GET https://github.com/Automattic/node-canvas/releases/download/v2.9.0/canvas-v2.9.0-node-v108-linux-glibc-x64.tar.gz npm ERR! node-pre-gyp ERR! install response status 404 Not Found on https://github.com/Automattic/node-canvas/releases/download/v2.9.0/canvas-v2.9.0-node-v108-linux-glibc-x64.tar.gz

ggolda commented 10 months ago

Doesn't work for me either, custom fonts work only if they are installed in /usr/share/fonts.

mkbaranovskyi commented 4 months ago

I experience this bug on Ubuntu 24.04 with the latest canvas@2.11.2. And I can't fallback to canvas@2.9.0 - it errors on Node 20. Thank you @simonhaenisch for the suggested workarounds, registering fonts globally worked for me (although you have to be careful with font names: e.g. AlexBrush-Regular.ttf it registers as AlexBrush, not AlexBrush-Regular as one might expect).

ilya-adnymics commented 2 months ago

I've found that on Ubuntu 24.04 (canvas@2.11.2, node@20.17.0) I could make it work by setting an environment variable FONTCONFIG_FILE with a path to a font config override which excluded certain fonts. Below is the conf file I used (named 78-Reject.conf)

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd">
<!-- Generated by Font Manager. Do NOT edit this file. -->
<fontconfig>
  <selectfont>
    <rejectfont>
      <pattern>
        <patelt name="family">
          <string>Ubuntu</string>
        </patelt>
      </pattern>
      <pattern>
        <patelt name="family">
          <string>Ubuntu Mono</string>
        </patelt>
      </pattern>
      <pattern>
        <patelt name="family">
          <string>Ubuntu Sans</string>
        </patelt>
      </pattern>
      <pattern>
        <patelt name="family">
          <string>Ubuntu Sans Mono</string>
        </patelt>
      </pattern>
      <pattern>
        <patelt name="family">
          <string>Noto Color Emoji</string>
        </patelt>
      </pattern>
    </rejectfont>
  </selectfont>
</fontconfig>

Not sure how it behaves on other operating systems, for me the error was that the registerFont simply did nothing - the custom font wasn't applied, but rather some system fallback font. I spent some time figuring out which fallbacks were used (you can see them in conf file above), and after applying font config override, text is rendered using my custom font. This solution shouldn't require installing custom fonts globally.