Javascript & PDFMake
To start a new project in JavaScript, it is good practice to use a package manager. Node.js comes with the "npm" package manager by default. However, Yarn can be considered a more practical alternative (subjective opinion), so in this article Yarn is used. To install Yarn globally, run the following command:
npm install -g yarn
To initialize a new Node.js project, run the following command in the directory created for this project and answer the prompted questions about the project:
yarn init
question name (create-pdf-using-javascript-and-pdfmake):
question version (1.0.0):
question description:
question entry point (index.js):
question repository url:
question author: Gradient s.p.
question license (MIT):
question private:
success Saved package.json
Done in 36.14s.
At this point package.json file is generated.
package.json
{
"name": "create-pdf-using-javascript-and-pdfmake",
"version": "1.0.0",
"main": "index.js",
"author": "Gradient s.p.",
"license": "MIT"
}
The "main" field in "package.json" is used when a project is intended to be used as an npm dependency in other projects. Since we are not building a library, but final program, we can remove "main" field. Additionally, we configure a run script for our project and create a simple 'Hello World' JavaScript program.
package.json
{
"name": "create-pdf-using-javascript-and-pdfmake",
"version": "1.0.0",
"scripts": {
"start": "node src/index.js"
},
"author": "Gradient s.p.",
"license": "MIT"
}
src/index.js
console.log("Hello World!");
We then run it from the root of our project.
yarn start
yarn run v1.22.22
$ node src/index.js
Hello World!
Done in 0.07s.
The next step is to install the PDFMake library and create a simple 'Hello World' PDF file.
Important: PDFMake requires font files to function. For this tutorial, you can download the necessary fonts here and save them in the fonts/ directory. Refer to the following source code to see which font variants are needed for this example.
yarn add pdfmake
yarn add v1.22.22
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved 1 new dependency.
info Direct dependencies
└─ pdfmake@0.2.18
info All dependencies
└─ pdfmake@0.2.18
Done in 0.47s.
src/index.js
import PdfPrinter from "pdfmake";
import * as fs from "fs";
const fonts = {
Roboto: {
normal: 'fonts/Roboto-Regular.ttf',
bold: 'fonts/Roboto-Medium.ttf',
italics: 'fonts/Roboto-Italic.ttf',
bolditalics: 'fonts/Roboto-MediumItalic.ttf'
}
};
const printer = new PdfPrinter(fonts);
const docDefinition = {
content: [
// Content goes here
{
text: "Hello World"
},
],
};
const options = {
// General Options to be configured
}
const pdfDoc = printer.createPdfKitDocument(docDefinition, options);
pdfDoc.pipe(fs.createWriteStream('document.pdf'));
pdfDoc.end();
After executing the program, we obtain a basic 'Hello World' PDF.
In PDFMake, content is defined in the docDefinition section as an array of elements that will be included in the PDF. Since the document definition is a single large JavaScript object, it is highly practical for dynamically generating the final PDF document.
One key advantage of PDFMake is its built-in handling of page breaks, which simplifies development when working with dynamically generated content, especially when the final document length is determined at runtime.
The following code demonstrates some of PDFMake’s features and builds a more complex PDF document:
src/index.js
import PdfPrinter from "pdfmake";
import * as fs from "fs";
const fonts = {
Roboto: {
normal: 'fonts/Roboto-Regular.ttf',
bold: 'fonts/Roboto-Medium.ttf',
italics: 'fonts/Roboto-Italic.ttf',
bolditalics: 'fonts/Roboto-MediumItalic.ttf'
}
};
const printer = new PdfPrinter(fonts);
const docDefinition = {
styles: {
heading: {
fontSize: 18,
bold: true,
marginBottom: 20,
marginTop: 20,
alignment: 'center'
},
content: {
margin: [20, 0, 20, 5], // [left, top, right, bottom]
alignment: 'justify',
leadingIndent: 20
}
},
content: [
// Content goes here
{
text: 'Example document created using pdfmake',
style: 'heading'
},
{
toc: {
title: {text: 'INDEX', style: 'heading'}
}
},
{
text: 'Topic 1',
style: 'heading',
tocItem: true
},
{
text: "Content of Topic 1. ".repeat(40),
style: 'content'
},
{
text: "Content of Topic 1. ".repeat(60),
style: 'content'
},
{
text: 'Topic 2',
style: 'heading',
tocItem: true
},
{
columns: [
{
text: "Content in Columns. ".repeat(25),
style: 'content'
},
{
text: "Content in Columns. ".repeat(25),
style: 'content'
}
]
},
{
text: 'Topic 3',
style: 'heading',
tocItem: true
},
{
text: 'Some Shapes',
style: 'content'
},
{
canvas:
[
{
type: 'line',
x1: 0, y1: 0,
x2: 260, y2: 60,
lineWidth: 3
},
{
type: 'polyline',
lineWidth: 3,
closePath: true,
lineColor: 'blue',
color: 'red',
points: [{ x: 310, y: 10}, { x: 335, y: 40 }, { x: 400, y: 40 }, { x: 425, y:10 }]
}
]
}
],
};
const options = {
// General Options to be configured
}
const pdfDoc = printer.createPdfKitDocument(docDefinition, options);
pdfDoc.pipe(fs.createWriteStream('document.pdf'));
pdfDoc.end();
This implementation produces following PDF document:
For more details on using and configuring PDFMake, visit their official website.