Generating Complex PDF files with Node.js and PDFMake

Yogesh Rajput / Senior NodeJS Developer

In the world of modern application development, generating complex PDF files can often be a challenging task. Whether you need to create detailed reports, invoices, or complex documents, having a reliable solution to generate PDFs is crucial.

In this blog post, we will explore how to generate complex PDF files using Node.js and a powerful library called PDFMake. We will cover the entire process, provide relevant examples, and delve into best practices to ensure your PDF generation process is seamless and efficient.

The sample project is available here for reference.
https://github.com/AppGambitStudio/node-pdfmake

Table of Contents

  1. Introduction
  2. Why Choose PDFMake?
  3. Setting Up Your Node.js Environment
  4. Installing PDFMake
  5. Creating Your First PDF
  6. Customizing Document Structure
  7. Styling Your PDF
  8. Adding Images and Tables
  9. Advanced Features
  10. Handling Data Dynamically
  11. Generating PDFs Asynchronously
  12. Conclusion
  13. References

1. Introduction

PDFs have been a standard for sharing documents and information across various platforms. When it comes to generating complex PDF files programmatically, Node.js is a powerful choice due to its flexibility and a vast ecosystem of libraries. Among the many libraries available, PDFMake stands out as an excellent option for its ease of use and the ability to create complex PDFs with simple code.

2. Why Choose PDFMake?

Before we dive into the technical details, let's understand why PDFMake is an excellent choice for generating complex PDF files:

  • Simplicity: PDFMake provides a declarative approach to document generation. You define the structure of your PDF using JavaScript objects, making it easy to understand and maintain.

  • Customization: It offers a high level of customization. You can control everything from fonts and colors to page layouts and content placement.

  • Rich Features: PDFMake supports a wide range of features, including tables, images, lists, and even watermarks. This makes it suitable for generating various types of documents.

  • Browser and Server-side: PDFMake can be used both on the client-side (browser) and server-side (Node.js), providing flexibility for different use cases.

Now that we understand why PDFMake is a compelling choice, let's set up our Node.js environment and get started.

3. Setting Up Your Node.js Environment

Before you can start generating PDFs with PDFMake, you need to have Node.js installed on your system. You can download Node.js from the official website (https://nodejs.org/).

Once Node.js is installed, you can verify the installation by running the following command in your terminal:

node -v

This command should display the installed Node.js version. Now that you have Node.js in place, let's move on to installing PDFMake.

4. Installing PDFMake

To use PDFMake in your Node.js project, you need to install it as a dependency. Create a new Node.js project or navigate to your existing project directory in the terminal and run the following command:

npm install pdfmake

This will download and install PDFMake along with its dependencies. With PDFMake installed, we are ready to create our first PDF.

5. Creating Your First PDF

Let's start with a simple example to create a basic PDF document. In this example, we'll generate a PDF with a title and some text.

var fonts = {
  Roboto: {
    normal: 'fonts/Roboto-Regular.ttf',
    bold: 'fonts/Roboto-Medium.ttf',
    italics: 'fonts/Roboto-Italic.ttf',
    bolditalics: 'fonts/Roboto-MediumItalic.ttf',
  },
}

var PdfPrinter = require('pdfmake')
var printer = new PdfPrinter(fonts)
var fs = require('fs')

// Create a document definition
const docDefinition = {
  content: [
    { text: 'My First PDF with PDFMake', fontSize: 16, bold: true },
    {
      text: 'This is a simple example of PDF generation with Node.js and PDFMake.',
    },
  ],
}

var options = {
  // ...
}

var pdfDoc = printer.createPdfKitDocument(docDefinition, options)
pdfDoc.pipe(fs.createWriteStream('myFirstPDF.pdf'))
pdfDoc.end()

In this code:

  • We define the fonts that we want to utilise.
  • Please download and store the fonts in the fonts directory. Reference - https://www.dafont.com/roboto.font
  • We import the PDFMake library and create a document definition object.
  • The documentDefinition object specifies the content of our PDF, including the title and some text.
  • We create a PDF document using printer.createPdfKitDocument(docDefinition, options).
  • The generated PDF is then piped to a writable stream, which in this case is a file named 'myFirstPDF.pdf'.
  • Finally, we close the PDF stream.

Run this script, and you'll have your first PDF generated using PDFMake.

6. Customizing Document Structure

PDFMake allows you to customize the structure of your document in detail. You can control page margins, page size, orientation, and more. Let's see how to customize the page size and orientation:

const documentDefinition = {
  content: [
    { text: 'Customizing Page Size and Orientation', fontSize: 16, bold: true },
    { text: 'This PDF has custom page size and orientation.' },
  ],
  pageOrientation: 'landscape', // 'portrait' is the default
  pageSize: 'A4', // 'A4' is the default
}

In this example, we set the page orientation to 'landscape' and the page size to 'A4'. You can customize these options to suit your specific requirements.

7. Styling Your PDF

Styling your PDF is a crucial aspect of creating a visually appealing document. PDFMake provides various styling options, including fonts, colors, and text alignment. Here's an example of how to apply styles to your content:

For this example to work, please download and define the Courier fonts in the fonts directory. https://fontsgeek.com/fonts/Courier-Regular

var fonts = {
  Roboto: {
    normal: 'fonts/Roboto-Regular.ttf',
    bold: 'fonts/Roboto-Medium.ttf',
    italics: 'fonts/Roboto-Italic.ttf',
    bolditalics: 'fonts/Roboto-MediumItalic.ttf',
  },
  Courier: {
    normal: 'fonts/Courier Regular.ttf',
  },
}

const documentDefinition = {
  content: [
    { text: 'Styling Your PDF', fontSize: 16, bold: true },
    { text: 'This text is in blue color.', color: 'blue' },
    { text: 'This text is aligned to the center.', alignment: 'center' },
    { text: 'This text uses a custom font.', font: 'Courier' },
  ],
}

In this code, we set the color of the text to blue, align it to the center, and use the 'Courier' font. You can explore more styling options in the PDFMake documentation.

8. Adding Images and Tables

A complex PDF often includes images and tables. PDFMake makes it easy to include both in your document. Here's an example of how to add an image and a table:

const documentDefinition = {
  content: [
    { text: 'Adding Images and Tables', fontSize: 16, bold: true },
    { text: 'This is an image:', margin: [0, 10] },
    { image: 'path/to/your/image.png', width: 200 },
    { text: 'This is a table:', margin: [0, 10] },
    {
      table: {
        widths: [100, '*', 200],
        body: [
          ['Column 1', 'Column 2', 'Column 3'],
          ['Row 1', 'Row 1 Data', 'Row 1 Data'],
          ['Row 2', 'Row 2 Data', 'Row 2 Data'],
        ],
      },
    },
  ],
}

In this code, we add an image using the image property, specifying the path to the image file and its width. We also include a table with custom column widths and data.

9. Advanced Features

PDFMake offers advanced features to create complex documents. Some notable features include:

  • Lists: You can create ordered and unordered lists.
  • Headers and Footers: Add headers and footers to your document.
  • Watermarks: Apply watermarks to your PDF for branding or security.
  • Hyperlinks: Insert clickable hyperlinks in your document.
  • Page Breaks: Control page breaks to ensure content flows correctly.

These advanced features provide you with the tools to generate highly customized and professional PDFs.

10. Handling Data Dynamically

In many scenarios, you'll need to generate PDFs dynamically based on data from your application. PDFMake allows you to do this efficiently. Here's a simplified example of generating a dynamic list of items:

const dynamicData = ['Item 1', 'Item 2', 'Item 3', 'Item 4']

const dynamicContent = dynamicData.map((item) => {
  return { text: item, margin: [0, 5] }
})

const documentDefinition = {
  content: [
    { text: 'Dynamic Content', fontSize: 16, bold: true },
    ...dynamicContent,
  ],
}

In this example, we have an array of items, and we dynamically generate a list of these items in the PDF.

11. Generating PDFs Asynchronously

While the examples shown so far are synchronous, you may need to generate PDFs asynchronously, especially in a server-side environment. PDFMake supports asynchronous generation as well. Here's a basic example using a Node.js Promise:

var fonts = {
  Roboto: {
    normal: 'fonts/Roboto-Regular.ttf',
    bold: 'fonts/Roboto-Medium.ttf',
    italics: 'fonts/Roboto-Italic.ttf',
    bolditalics: 'fonts/Roboto-MediumItalic.ttf',
  },
}

var PdfPrinter = require('pdfmake')
var printer = new PdfPrinter(fonts)
var fs = require('fs')

// Create a document definition
const docDefinition = {
  content: [
    { text: 'My First PDF with PDFMake', fontSize: 16, bold: true },
    {
      text: 'This is a simple example of PDF generation with Node.js and PDFMake.',
    },
  ],
}

var options = {
  // ...
}

// Create a Promise to generate the PDF
const generatePDF = () => {
  return new Promise((resolve, reject) => {
    var pdfDoc = printer.createPdfKitDocument(docDefinition, options)
    const stream = pdfDoc.pipe(fs.createWriteStream('myFirstPDF.pdf'))
    pdfDoc.end()

    stream.on('finish', () => {
      resolve('Async PDF generated successfully!')
    })
    stream.on('error', (error) => {
      reject(error)
    })
  })
}

// Usage
generatePDF()
  .then((message) => {
    console.log(message)
  })
  .catch((error) => {
    console.error('Error generating PDF:', error)
  })

In this asynchronous example, we create a Promise to handle the PDF generation process, making it suitable for server-side applications.

12. Conclusion

Generating complex PDF files with Node.js and PDFMake offers a powerful solution for a wide range of use cases. With its simplicity, customization options, and support for advanced features, PDFMake is a valuable tool for developers working on projects that require dynamic and professional PDF generation.

In this blog post, we've covered the basics of getting started with PDFMake, including installation, creating simple and complex PDFs, customization, and handling data dynamically. We've also explored how to generate PDFs asynchronously in a server-side environment.

To delve deeper into PDFMake's capabilities and explore more advanced features, refer to the official documentation and explore real-world use cases. Whether you need to generate invoices, reports, or any other complex PDF documents, PDFMake is a reliable choice to streamline the process.

13. References

Now you have a solid foundation for generating complex PDF files with Node.js and PDFMake. Feel free to explore more and apply these techniques to your specific projects.

Happy PDF generation!

More articles

How to Build an Android React Native Application Using AWS CodePipeline

In this blog post, we'll walk you through the process of using AWS CodePipeline, along with other AWS services, to build an Android React Native application. We'll be using an AWS CodeCommit Git repository to store our code and an S3 bucket to save the final generated APK.

Read more

Embracing the Serverless Cloud-Native Approach

The evolution of cloud computing has seen a significant shift towards serverless architectures, particularly for building robust, scalable, and cost-efficient applications. Let's explore this paradigm using a ridesharing app as our illustrative example, delving deeper into the technical intricacies and advantages, while leveraging a broader range of serverless services.

Read more

Tell us about your project

Our office

  • 408-409, SNS Platina
    Opp Shrenik Residecy
    Vesu, Surat, India
    Google Map