Adding fonts to Puppeteer PDF renderer

2020-05-24 06:03发布

Background

I am using Puppeteer in an express application that is running in a Docker image. It is necessary for us to run in Docker because of needed dependencies that Debian needs which we do not have access to install. Using Docker allows us to install what we need.

We have seen a lot of people have problems getting their fonts to render in the PDFs correctly and in every case I have seen, installing the font in a way close to this is always the answer,

 apt-get install -yq --allow-unauthenticated ttf-mscorefonts-installer

In that case they are installing specific fonts that there happens to be an apt-get for. I have seen others install the default Puppeteer fonts with RUN apt-get install -yyq fonts-liberation as well.

Code Example

const browser = await puppeteer.launch({
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
      ignoreHTTPSErrors: true,
      dumpio: false,
    });
    const page = await browser.newPage();
    await page.goto(
      `http://localhost:3000/${template}?data=${JSON.stringify(req.body)}`,
    );
    const pdfBuffer = await page.pdf({
      format: 'A4',
      margin: {
        top: '20px',
        left: '20px',
        right: '20px',
        bottom: '20px',
      },
    });
    await browser.close();

Problem

We need to install about 10 fonts that different parts of are application will use on different occasions. We have the ttf and the woff files for this. We decided to add them to the system in the way that appears to be what apt-get is doing with the other fonts we have seen people install. We did this by adding our fonts to the Debian directory,

/usr/local/share/fonts

We can see the fonts are setup correctly in the system by running,

fc-list

When we add the fonts like this, they do not render. Instead we get weird symbols where these fonts should be.

Example

We are adding our fonts like this using the Dockerfile,

RUN apt-get install -yyq fonts-liberation
COPY /fonts/*.ttf /usr/local/share/fonts/
COPY /fonts/*.woff /usr/local/share/fonts/

Question

Since we have a bunch of ttf and woff font files that need to be rendered in PDFs using Puppeteer, what is the correct way to add them to our Debian image that is running in Docker so that Puppeteer will use them as expected?

1条回答
ゆ 、 Hurt°
2楼-- · 2020-05-24 06:37

This is a sample script which goes and captures screenshot and pdf on website. Both serves same purpose on this question, to show the fonts works.

(async()=>{
  const puppeteer = require('puppeteer')

  const browser = await puppeteer.launch({
    headless: true,
    args: ["--no-sandbox", "--disable-setuid-sandbox"]
  });
  const page = await browser.newPage()
  await page.goto('https://jp.quora.com/')
  await page.screenshot({path: `/shared/_${Date.now()}.png`})
  const pdfBuffer = await page.pdf({path: `/shared/_${Date.now()}.pdf`});

  await browser.close()
})()

Here is the minimal dockerfile, this is very minimal, it doesn't include anything extra like dumb-init and various cleanup hacks as it's not required here.

FROM node:8

# Install dependencies
RUN apt-get update && \
apt-get -yq install libatk1.0-0 libgtk2.0-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 libasound2 xauth xvfb 

# Cd into /app
WORKDIR /app

# Copy package.json into app folder
COPY package.json /app

# Install dependencies
RUN npm install 

COPY . /app

# Start script on Xvfb
CMD ["xvfb-run","npm","start"]

Upon running, here is how Japanese Quora is showing on puppeteer, it is showing like this because fonts are missing.

enter image description here.

Since it is based on jessie, and we can install fonts using few different commands.

Run standard apt-get

The below will install some fonts with Japanese characters in it.

RUN apt-get -yq install xfonts-utils fonts-droid xfonts-intl-asian

Copy fonts from directory

If I have the fonts inside fonts directory, then the command is,

COPY fonts/*.* /usr/share/fonts/truetype/

That's really straightforward. However the fonts will still not work because the font cache is not updated that fast enough. Adding the following will make sure it's updated.

RUN mkfontscale && mkfontdir && fc-cache

That's it! Let us run the script again.

enter image description here

查看更多
登录 后发表回答