Stefan
Stefan

Reputation: 1928

pdf-lib: how to add custom font

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?

Upvotes: 11

Views: 25737

Answers (3)

Avishka Dambawinna
Avishka Dambawinna

Reputation: 1215

For Typescript

If you're using @pdf-lib/fontkit in a typescript project the way you import fontkit is different.

import * as fontkit from '@pdf-lib/fontkit';

This approach ensures compatibility with TypeScript and allows you to take advantage of TypeScript's type checking and IntelliSense features.

However, if you encounter issues with the import statement provided in other answers, you might need to switch to this syntax.

Here's an example of how to use @pdf-lib/fontkit to embed a custom font in a PDF document:

import path from 'path';
import * as fs from 'fs';
import * as path from 'path';
import { PDFDocument, PDFForm } 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 into the 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 flattening makes the form read-only (not editable)
form.flatten();

const modifiedPdf = await pdfDoc.save();

Upvotes: 0

Gimnath
Gimnath

Reputation: 1070

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.

Upvotes: 7

Stefan
Stefan

Reputation: 1928

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

Upvotes: 20

Related Questions