How to Create and Modify PDF Files in Deno With pdf-lib
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!
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 bypdf-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).
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).
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).
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! 🦕 🚀