How to Create and Modify PDF Files in Deno With pdf-lib

Andrew Dillon
The Startup
Published in
5 min readMay 17, 2020

Deno is an exciting new runtime for JavaScript and TypeScript. It was created by the original author of Node and corrects some key mistakes in Node’s design. Version 1.0 of Deno was announced just 5 days ago on May 13th, 2020.

Many developers (myself included) are very excited about Deno and the potential it has to change the JavaScript ecosystem for the better. Deno strives for compatibility with standard web APIs. This means that Deno does not resolve dependencies via a centralized repository such as NPM. Instead, dependencies must be imported via fully qualified URLs. In addition, Deno does not provide many of the APIs relied upon by NPM packages. For example, there is no global Buffer class or streams API. Under the hood Deno is written in Rust. This means that Node modules which bind to native C++ will have to be rewritten to interface with Rust APIs in order to be compatible with Deno.

The long-term payoff of these design choices will be significant. They will make it much easier to create sophisticated libraries that work both server-side and client-side. The Deno authors were very forward-looking in this respect. But reaching this end-state will take time. And, as always, the TANSTAAFL principle applies here. In the short-term developers will be frustrated by Deno’s incompatibility with many popular NPM packages.

Processing PDF files is a very difficult task to do from scratch. As such, few developers attempt to do this without pulling in a library. NPM hosts several great libraries that make it easy to create and even modify PDF documents with JavaScript. However, not all of these libraries will work in Deno out of the box (for reasons described above).

I am the author and maintainer of pdf-lib, an open source library for creating and modifying PDF documents. pdf-lib is written in TypeScript and compiles to pure, standard JavaScript with no native dependencies. This allows it to work in any JavaScript runtime, including web browsers, Node, React Native, and even Deno!

pdf-lib project logo

In the remainder of this article I will explain how to use a variety of pdf-lib features in simple Deno scripts, as well as how to serve PDFs from a Deno HTTP server.

Table of Contents
Creating New PDFs
Modifying Existing PDFs
Embedding Fonts and Images in PDFs
Serving New PDFs With HTTP
Serving Modified PDFs With HTTP
Embedding Fonts and Images With HTTP

Creating New PDFs

pdf-lib makes it easy to create new PDF documents with Deno. Simply import PDFDocument from the excellent Skypack CDN and call a few of its methods (and a couple PDFPage methods). You can then serialize the PDFDocument to a Uint8Array and write it to the file system!

You can execute this script yourself by running:

$ deno run --allow-write https://gist.githubusercontent.com/Hopding/8304b9f07c52904587f7b45fae4bcb8c/raw/pdf-lib-deno-create-script.ts

Note that the above script is written in TypeScript (as indicated by its .ts extension) to take full advantage of the static types provided by pdf-lib, but you can use the same code in a JavaScript (.js) file if you wish. This applies to all subsequent examples in this article as well (though you will have to remove the : ServerRequest types from the HTTP examples).

Modifying Existing PDFs

One of the features that sets pdf-lib apart is it’s ability to modify/edit existing PDF documents. To use this feature you must construct an instance of PDFDocument by calling the PDFDocument.load(...) method and passing in an ArrayBuffer (Uint8Arrays and base64 strings are also supported). Then you can perform all the same operations that are available on newly created PDFDocuments!

You can execute this script yourself by running:

$ deno run --allow-write --allow-net https://gist.githubusercontent.com/Hopding/2d25620f0fac5cf141123129cbf0a3d8/raw/pdf-lib-deno-modify-script.ts

Embedding Fonts and Images in PDFs

You can embed custom fonts, JPG/PNG images, SVG paths, and even PDF pages with pdf-lib. The below example demonstrates how to embed fonts and images. Note that you must import pdf-lib‘s sister module, @pdf-lib/fontkit, to embed fonts (read about why).

You can execute this script yourself by running:

$ deno run --allow-write --allow-net https://gist.githubusercontent.com/Hopding/29ebd6e73eb3436b94047bd29e9b9fd0/raw/pdf-lib-deno-fancy-script.ts

Serving New PDFs With HTTP

The previous three examples demonstrated how to use a variety of pdf-lib features in simple scripts that write the resulting PDF directly to the filesystem. Another very common use case is producing PDFs in a server-side application. The example below creates a basic HTTP server (with Deno’s standard http module) that serves PDFs created with pdf-lib.

You can execute this script yourself by running:

$ deno run --allow-net https://gist.githubusercontent.com/Hopding/c696413d6e8fef466e59604ad347efe3/raw/pdf-lib-deno-create-server.ts

This will start an HTTP server listening on port 8000. If you open http://localhost:8000 in your web browser you will see a PDF document (or be prompted to download one, depending on your browser and settings).

New PDF loaded from http://localhost:8000 in Firefox 🦊

Serving Modified PDFs With HTTP

This example creates an HTTP server that serves a modified/edited version of an existing PDF document.

You can execute this script yourself by running:

$ deno run --allow-net https://gist.githubusercontent.com/Hopding/15ca66533b11de94b4a156833a8ab6b8/raw/pdf-lib-deno-modify-server.ts

This will start an HTTP server listening on port 8000. If you open http://localhost:8000 in your web browser you will see a PDF document (or be prompted to download one, depending on your browser and settings).

Modified PDF loaded from http://localhost:8000 in Firefox 🦊

Embedding Fonts and Images With HTTP

This example creates an HTTP server that serves new PDF documents with embedded fonts and images.

You can execute this script yourself by running:

$ deno run --allow-net https://gist.githubusercontent.com/Hopding/c7adad158a01b8ee155baa415f6892a2/raw/pdf-lib-deno-fancy-server.ts

This will start an HTTP server listening on port 8000. If you open http://localhost:8000 in your web browser you will see a PDF document (or be prompted to download one, depending on your browser and settings).

PDF with embedded fonts and images loaded from http://localhost:8000 in Firefox 🦊

Conclusion

I hope you have found these examples to be helpful. API docs for pdf-lib can be found at pdf-lib.js.org/docs/api. The README also contains extensive documentation and usage examples. If you have any questions I encourage you to leave a comment below or create an issue on the pdf-lib GitHub repo.

Happy hacking with Deno! 🦕 🚀

--

--