pdf-lib: how to add custom font

Viewed 6936

My environment is node v12.16.1 with typescript added.

I am using pdf-lib v1.16.0 (https://www.npmjs.com/package/pdf-lib) in order to fill the form for given PDF file. Library source code can be found here https://github.com/Hopding/pdf-lib and more on docs here https://pdf-lib.js.org/.

Regarding fonts pdf-lib has a set of called StandardFonts which is provided inside the lib.

export enum StandardFonts {
  Courier = 'Courier',
  CourierBold = 'Courier-Bold',
  CourierOblique = 'Courier-Oblique',
  CourierBoldOblique = 'Courier-BoldOblique',
  Helvetica = 'Helvetica',
  HelveticaBold = 'Helvetica-Bold',
  HelveticaOblique = 'Helvetica-Oblique',
  HelveticaBoldOblique = 'Helvetica-BoldOblique',
  TimesRoman = 'Times-Roman',
  TimesRomanBold = 'Times-Bold',
  TimesRomanItalic = 'Times-Italic',
  TimesRomanBoldItalic = 'Times-BoldItalic',
  Symbol = 'Symbol',
  ZapfDingbats = 'ZapfDingbats',
}

Very often you would have requirement to apply font which is not on the list. One example is when you have some user documents/forms to fill and then to apply electronical signature on it in order to approve them. Sometimes that electronic signature can be of a different font type, chosen by the user.

So, how we can add new font type of our choice?

2 Answers

From the specs https://www.npmjs.com/package/pdf-lib#embed-font-and-measure-text

pdf-lib relies on a sister module to support embedding custom fonts: @pdf-lib/fontkit. You must add the @pdf-lib/fontkit module to your project and register it using pdfDoc.registerFontkit(...) before embedding custom fonts.

We have to npm i --save @pdf-lib/fontkit and we have to have source from where which we will read the font. In my case I have added .otf file in project and loaded font. Files are structured like on the image: enter image description here

import path from 'path';
import fs from 'fs';
import {PDFDocument, PDFForm, StandardFonts, PDFFont} from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';

const pdfBytes = fs.readFileSync(path.join(__dirname, `/w_template/` + fileName + '.pdf'));
const pdfDoc = await PDFDocument.load(pdfBytes);

pdfDoc.registerFontkit(fontkit);
//load font and embed it to pdf document
const fontBytes = fs.readFileSync(path.join(__dirname, 'HouschkaHead-BoldItalic.otf'));
const customFont = await pdfDoc.embedFont(fontBytes);

const form = pdfDoc.getForm();
const textField = form.getTextField('signature');
textField.setFontSize(11);
textField.setText('stefan z');
textField.updateAppearances(customFont);

// form flatten is available from v1.16.0 and it makes form read-only (not editable)
form.flatten();
const modifiedPdf = await pdfDoc.save();

And this is the final result: check how the signature input form field is different from rest of input fields which are filled with default font enter image description here Bonus: if you want to play with color of the text of inputs in form, this is what I have found while digging more under the library source code (it might be not optimal, but it can give you starting point for more things):

import {setFillingRgbColor} from 'pdf-lib'

const textField = form.getTextField(fieldName);
const da = textField.acroField.getDefaultAppearance() ?? '';
const newDa = da + '\n' + setFillingRgbColor(1, 0, 0).toString(); 
textField.acroField.setDefaultAppearance(newDa);

enter image description here

If anyone is struggling to change the fontSize in filling text fields using the latest inbuilt function called setFontSize(). You can use this approach.

const { PDFDocument, setFontAndSize } = require('pdf-lib');

   const pdfDoc = await PDFDocument.load(file);
   const form = pdfDoc.getForm();

const textField = form.getTextField('106Mobile.1');
    textField.setText('This works fine');
    const da = textField.acroField.getDefaultAppearance() ?? '';
    const newDa = da + '\n' + setFontAndSize('Courier', 8).toString(); //setFontAndSize() method came to resuce
    textField.acroField.setDefaultAppearance(newDa);

I had to use this because I got an error saying

No /DA (default appearance) entry found for field: 106Title.1

when setting font sizes to some text fields (not all of it). But I degenerately had those text fields. Fixed it using the above workaround.

Related