Configuring local fonts in Puppeteer using npm

Looking to incorporate locally loaded fonts when generating a PDF using the Puppeteer node module.

I successfully implemented web fonts, but this does not meet the specified requirements.

Environment Details:

  • Node: v10.18.1,
  • Puppeteer: "puppeteer": "^2.0.0",
  • Chromium: Chromium 79.0.3945.88 Fedora Project,
  • OS: CentOS Linux release 8.0.1905 (Core)

Attempted code includes loading fonts with @font-face, adjusting networkidle values, setting timeouts, adding event listeners for font updates. Even after setting up callbacks to retrieve font properties returning "Open Sans," the resulting PDF file does not display the Open Sans font.

const puppeteer = require('puppeteer');
const chromiumExecutablePath = '/bin/chromium-browser';

let document = `
    <html>
    <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>

            @font-face {
                font-family: "Open Sans";
                font-style: normal;
                font-weight: 400;
                src: local("Open Sans") url("/opt/www/webapp/resources/packed/OpenSans-Regular.eot");
                src: local("Open Sans") url("/opt/www/webapp/resources/packed/OpenSans-Regular.woof") format("woff"),
                     local("Open Sans") url("/opt/www/webapp/resources/packed/OpenSans-Regular.ttf") format("truetype");
            }

            html, body {
              font-family: 'Open Sans', sans-serif;
            }

        </style>
        <sript>

        </script>
        <link rel="stylesheet" type="text/css" href="font.css">
      </head>
      <body>
        <div class="content">
          <h1 id="hello-world">Hello world long report</h1>
        </div>
      </body>
    </html>
    `
const browser = await puppeteer.launch({
    args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-web-security', '--font-render-hinting=none'],
    headless: true,
    executablePath: chromiumExecutablePath
});
const page = await browser.newPage()

const session = await page.target().createCDPSession();
await session.send('DOM.enable');
await session.send('CSS.enable');
await new Promise(resolve => setTimeout(resolve, 500));
session.on('CSS.fontsUpdated', event => {
  console.log(event);
  // event will be received when browser updates fonts on the page due to webfont loading.
});

await page.goto("data:text/html;charset=UTF-8,"+document, { waitUntil: 'networkidle0' }).catch(e => console.error(e));
await page.waitFor(2000);

await page.evaluateHandle('document.fonts.ready');

const selector = 'h1';
const getFontProperty = async (page) => {
  const font = await page.evaluate((selector) => {
    const title = document.querySelector(selector);
    return getComputedStyle(title).font;
  }, selector);
  return font;
}
console.log(await getFontProperty(page)); // output: 700 32px "Open Sans", sans-serif 

await page.emulateMedia("print");

await page.pdf({
    displayHeaderFooter: false,
    path: outputPath,
    width: 400+'px',
    height: 400+'px',
    printBackground: true,
    margin: {
        top: '20px',
        bottom: '40px'
    }
}); // output is valid PDF file but without Open Sans font

Seeking suggestions on how to resolve this issue. There was mention of rendering images from local files in a related question, but the solution provided did not address how to handle fonts.

Answer №1

I get it, but avoid solving the problem in that manner.

It's possible that PDF files may not correctly import fonts unless they are installed on systems properly. However, some PDF consumers (especially certain inexpensive printers) may encounter difficulties when printing a PDF. I've witnessed some strange errors in such cases, like smudges caused by the printer. These issues are somewhat expected.

Instead of relying on system fonts, consider encoding the entire font as base64. This way, the resulting PDF will always contain and transport those fonts.

base64 myfont.woff > fontbase64.txt

const yourOpenSans = require('fs').readFileSync('./fontbase64.txt')

function genFont () {


    return `

     @font-face {
        font-family: 'YOUR Open Sans';
        src: url(data:font/truetype;charset=utf-8;base64,${yourOpenSans}) format('truetype');
        font-weight: normal;
        font-style: normal;
     }
    `

}

Utilize the font-face declaration in your CSS as instructed.

Keep in mind that these files are sensitive to newlines.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to transform a circular structure into JSON format?

I retrieved data from the database and now I need to format it, but I encountered the following error: TypeError: Converting circular structure to JSON --> starting at object with constructor 'NativeConnection' | property ' ...

Extract information from a JavaScript function utilizing Python's Selenium

Is there a way to extract data from within a JavaScript function using Selenium? Visit the page here Here is the input code: <script type="text/javascript"> var chartData1 = []; var chartData2 = []; var chartData3 = []; ... ...

Increase the worth of current value

Whenever a user enters their name into an input box, I want it to be shown after the word 'hello'. However, currently, the word 'hello' gets replaced by the user's name instead of being displayed after it. var name = document.ge ...

Delivering identical content to various domains using express.js

I'm in the process of creating a mobile application that can create personalized websites for users. The concept involves users registering their own domain names, linking them to my platform, and directing them to my Amazon server (although I am sti ...

What is the process for importing JSON data into Node.js following the bundling of the entire server as an executable using the "pkg" compiler?

When running my node.js environment with "npm start", I am able to require/import JSON files and access the data inside without any issues. For instance, if I have a file named "./Assets/port.json" containing {"port": 3000}, I can import it and retrieve t ...

The font size escalates following the activation of a Java alert box on an ASPX webpage

Recently, I came across an interesting solution to a problem with a PHP application. It was discovered that placing the Java Script in the body section resolved the issue where CSS file attributes were being ignored when clicking the Alert box. In my code ...

Angular's jQuery timepicker allows users to easily select a

Transitioning from jQuery to Angular, we previously utilized the for selecting times due to Firefox not supporting HTML5 input time. While searching for a similar timepicker plugin for Angular to maintain consistency with our past data and styles, I came ...

The CanJS model is unable to retrieve data from a .json file

Implementing MVC using AMD in canjs with requirejs has been my current focus. Here's a look at my domains.json file: [ "1":{"uid": "1","urls": "domain1.abc.com"}, "2":{"uid": "2","urls": "domain2.abc.com"}, "3":{"uid": "3","urls ...

The getUUID() function in ngCordova is causing an error where the device is

Getting 'device is not defined' error with ngCordova getUUID() In the process of developing a mobile app using Ionic framework, I encountered an issue with retrieving the device UUID. To tackle this problem, I decided to leverage ngCordova by in ...

Encountering the "test exited without ending" error while using asynchronous forEach loops with tape

My Current Project Edit: I created a repository with a simplified version of the issue I am facing. Currently, my focus is on setting up automated frontend testing using tools like browserstack, selenium-webdriver, and tape. More information about tape ...

Execute the identical script in NPM, but with various parameters each time

Recently, I created a nodeJS script with a parameter. Currently, using npm start allows me to pass arguments and run my script successfully. However, I'm now faced with the challenge of passing multiple arguments to npm start in order to run multipl ...

How can I transform a JSON object into a series of nested form fields?

Can anyone suggest a reliable method for converting a JSON object to nested form fields? Let's consider the following JSON object: {'a':{'b':{'c':'1200'}}}, 'z':'foo', 'bar':{&apo ...

Simple organization of a table by sorting one column in a descending direction, all without the need for any additional plugins

Currently, I am working with a simple table containing several columns. My task involves sorting the table based on the values in the first column, which are integers. The sorting should only occur once and in descending order. I need to accomplish this ...

Dropdown selection for countries that dynamically updates region choices

Looking to implement some JavaScript, preferably using jQuery, to create a cascading dropdown menu. Initially displaying a list of countries and upon selection, the corresponding regions for that country will be displayed in another dropdown. I assume an ...

Update the src of #contentImg to display the image from the clicked link

I have a jQuery mobile listview set up where I want to use jQuery to change the source of #contentImg to the source of the image thumbnail that is clicked. So, when an 'a' element within a 'ul' with the data-role of "listview" is click ...

When the primary node in MongoDB is offline, attempts to perform write operations will be declined

Our MongoDB setup consists of one primary node and two secondary nodes. During autoscaling, if the primary node goes down, one of the healthy secondary nodes is elected as the new primary through an election process. During this transition period, no write ...

Insert a fresh item into the current JSON structure

I am facing an issue with a dropdown in my code. Here is how it looks: <input id="tripFrom" type="text" angular-select2="{type:'typeahead',placeholder:'- Select -'}" select-typeahead-params="{removeTripId:currentTrip.custome ...

Issue with Bower: Missing bower_components directory

I've added a bower.json file to the root of my project, but when I execute the following command: $ bower install I receive this output: bower not-cached https://github.com/mirceasinteanu/nanoScrollerJS.git#master bower resolve https://git ...

Populate a dropdown menu using Javascript

[Code] $.ajax ({ 'method': 'GET', 'source': '/bpv-registratie/periods/show_period_list_by_year.html', 'charge': function () { }, 'finish': function (xmlHttp) { ...

Adding an object to a scene in Three.js

I've been experimenting with a code example I found online and my goal is to incorporate a textured cube into the project while specifying its position. However, despite my efforts, the cube doesn't seem to be showing up. Here's what I have ...