MCPcopy Index your code
hub / github.com/Hopding/pdf-lib

github.com/Hopding/pdf-lib @v1.17.1

repository ↗ · DeepWiki ↗ · release v1.17.1 ↗ · Ask this repo → · + Follow
1,644 symbols 6,616 edges 277 files 329 documented · 20% 17 cross-repo links updated 1y agov1.17.1 · 2021-11-06★ 8,522279 open issues
README

pdf-lib

Create and modify PDF documents in any JavaScript environment.

Designed to work in any modern JavaScript runtime. Tested in Node, Browser, Deno, and React Native environments.

NPM Version

CircleCI Build Status

Prettier Badge

Discord Badge

Learn more at pdf-lib.js.org

Table of Contents

Features

  • Create new PDFs
  • Modify existing PDFs
  • Create forms
  • Fill forms
  • Flatten forms
  • Add Pages
  • Insert Pages
  • Remove Pages
  • Copy pages between PDFs
  • Draw Text
  • Draw Images
  • Draw PDF Pages
  • Draw Vector Graphics
  • Draw SVG Paths
  • Measure width and height of text
  • Embed Fonts (supports UTF-8 and UTF-16 character sets)
  • Set document metadata
  • Read document metadata
  • Set viewer preferences
  • Read viewer preferences
  • Add attachments

Motivation

pdf-lib was created to address the JavaScript ecosystem's lack of robust support for PDF manipulation (especially for PDF modification).

Two of pdf-lib's distinguishing features are:

  1. Supporting modification (editing) of existing documents.
  2. Working in all JavaScript environments - not just in Node or the Browser.

There are other good open source JavaScript PDF libraries available. However, most of them can only create documents, they cannot modify existing ones. And many of them only work in particular environments.

Usage Examples

Create Document

This example produces this PDF.

Try the JSFiddle demo

import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'

// Create a new PDFDocument
const pdfDoc = await PDFDocument.create()

// Embed the Times Roman font
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman)

// Add a blank page to the document
const page = pdfDoc.addPage()

// Get the width and height of the page
const { width, height } = page.getSize()

// Draw a string of text toward the top of the page
const fontSize = 30
page.drawText('Creating PDFs in JavaScript is awesome!', {
  x: 50,
  y: height - 4 * fontSize,
  size: fontSize,
  font: timesRomanFont,
  color: rgb(0, 0.53, 0.71),
})

// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()

// For example, `pdfBytes` can be:
//   • Written to a file in Node
//   • Downloaded from the browser
//   • Rendered in an <iframe>

Modify Document

This example produces this PDF (when this PDF is used for the existingPdfBytes variable).

Try the JSFiddle demo

import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib';

// This should be a Uint8Array or ArrayBuffer
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const existingPdfBytes = ...

// Load a PDFDocument from the existing PDF bytes
const pdfDoc = await PDFDocument.load(existingPdfBytes)

// Embed the Helvetica font
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)

// Get the first page of the document
const pages = pdfDoc.getPages()
const firstPage = pages[0]

// Get the width and height of the first page
const { width, height } = firstPage.getSize()

// Draw a string of text diagonally across the first page
firstPage.drawText('This text was added with JavaScript!', {
  x: 5,
  y: height / 2 + 300,
  size: 50,
  font: helveticaFont,
  color: rgb(0.95, 0.1, 0.1),
  rotate: degrees(-45),
})


// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()

// For example, `pdfBytes` can be:
//   • Written to a file in Node
//   • Downloaded from the browser
//   • Rendered in an <iframe>

Create Form

This example produces this PDF.

Try the JSFiddle demo

See also Creating and Filling Forms

import { PDFDocument } from 'pdf-lib'

// Create a new PDFDocument
const pdfDoc = await PDFDocument.create()

// Add a blank page to the document
const page = pdfDoc.addPage([550, 750])

// Get the form so we can add fields to it
const form = pdfDoc.getForm()

// Add the superhero text field and description
page.drawText('Enter your favorite superhero:', { x: 50, y: 700, size: 20 })

const superheroField = form.createTextField('favorite.superhero')
superheroField.setText('One Punch Man')
superheroField.addToPage(page, { x: 55, y: 640 })

// Add the rocket radio group, labels, and description
page.drawText('Select your favorite rocket:', { x: 50, y: 600, size: 20 })

page.drawText('Falcon Heavy', { x: 120, y: 560, size: 18 })
page.drawText('Saturn IV', { x: 120, y: 500, size: 18 })
page.drawText('Delta IV Heavy', { x: 340, y: 560, size: 18 })
page.drawText('Space Launch System', { x: 340, y: 500, size: 18 })

const rocketField = form.createRadioGroup('favorite.rocket')
rocketField.addOptionToPage('Falcon Heavy', page, { x: 55, y: 540 })
rocketField.addOptionToPage('Saturn IV', page, { x: 55, y: 480 })
rocketField.addOptionToPage('Delta IV Heavy', page, { x: 275, y: 540 })
rocketField.addOptionToPage('Space Launch System', page, { x: 275, y: 480 })
rocketField.select('Saturn IV')

// Add the gundam check boxes, labels, and description
page.drawText('Select your favorite gundams:', { x: 50, y: 440, size: 20 })

page.drawText('Exia', { x: 120, y: 400, size: 18 })
page.drawText('Kyrios', { x: 120, y: 340, size: 18 })
page.drawText('Virtue', { x: 340, y: 400, size: 18 })
page.drawText('Dynames', { x: 340, y: 340, size: 18 })

const exiaField = form.createCheckBox('gundam.exia')
const kyriosField = form.createCheckBox('gundam.kyrios')
const virtueField = form.createCheckBox('gundam.virtue')
const dynamesField = form.createCheckBox('gundam.dynames')

exiaField.addToPage(page, { x: 55, y: 380 })
kyriosField.addToPage(page, { x: 55, y: 320 })
virtueField.addToPage(page, { x: 275, y: 380 })
dynamesField.addToPage(page, { x: 275, y: 320 })

exiaField.check()
dynamesField.check()

// Add the planet dropdown and description
page.drawText('Select your favorite planet*:', { x: 50, y: 280, size: 20 })

const planetsField = form.createDropdown('favorite.planet')
planetsField.addOptions(['Venus', 'Earth', 'Mars', 'Pluto'])
planetsField.select('Pluto')
planetsField.addToPage(page, { x: 55, y: 220 })

// Add the person option list and description
page.drawText('Select your favorite person:', { x: 50, y: 180, size: 18 })

const personField = form.createOptionList('favorite.person')
personField.addOptions([
  'Julius Caesar',
  'Ada Lovelace',
  'Cleopatra',
  'Aaron Burr',
  'Mark Antony',
])
personField.select('Ada Lovelace')
personField.addToPage(page, { x: 55, y: 70 })

// Just saying...
page.drawText(`* Pluto should be a planet too!`, { x: 15, y: 15, size: 15 })

// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()

// For example, `pdfBytes` can be:
//   • Written to a file in Node
//   • Downloaded from the browser
//   • Rendered in an <iframe>

Fill Form

This example produces this PDF (when this PDF is used for the formPdfBytes variable, this image is used for the marioImageBytes variable, and this image is used for the emblemImageBytes variable).

Try the JSFiddle demo

See also Creating and Filling Forms

import { PDFDocument } from 'pdf-lib'

// These should be Uint8Arrays or ArrayBuffers
// This data can be obtained in a number of different ways
// If your running in a Node environment, you could use fs.readFile()
// In the browser, you could make a fetch() call and use res.arrayBuffer()
const formPdfBytes = ...
const marioImageBytes = ...
const emblemImageBytes = ...

// Load a PDF with form fields
const pdfDoc = await PDFDocument.load(formPdfBytes)

// Embed the Mario and emblem images
const marioImage = await pdfDoc.embedPng(marioImageBytes)
const emblemImage = await pdfDoc.embedPng(emblemImageBytes)

// Get the form containing all the fields
const form = pdfDoc.getForm()

// Get all fields in the PDF by their names
const nameField = form.getTextField('CharacterName 2')
const ageField = form.getTextField('Age')
const heightField = form.getTextField('Height')
const weightField = form.getTextField('Weight')
const eyesField = form.getTextField('Eyes')
const skinField = form.getTextField('Skin')
const hairField = form.getTextField('Hair')

const alliesField = form.getTextField('Allies')
const factionField = form.getTextField('FactionName')
const backstoryField = form.getTextField('Backstory')
const traitsField = form.getTextField('Feat+Traits')
const treasureField = form.getTextField('Treasure')

const characterImageField = form.getButton('CHARACTER IMAGE')
const factionImageField = form.getTextField('Faction Symbol Image')

// Fill in the basic info fields
nameField.setText('Mario')
ageField.setText('24 years')
heightField.setText(`5' 1"`)
weightField.setText('196 lbs')
eyesField.setText('blue')
skinField.setText('white')
hairField.setText('brown')

// Fill the character image field with our Mario image
characterImageField.setImage(marioImage)

// Fill in the allies field
alliesField.setText(
  [
    `Allies:`,
    `  • Princess Daisy`,
    `  • Princess Peach`,
    `  • Rosalina`,
    `  • Geno`,
    `  • Luigi`,
    `  • Donkey Kong`,
    `  • Yoshi`,
    `  • Diddy Kong`,
    ``,
    `Organizations:`,
    `  • Italian Plumbers Association`,
  ].join('\n'),
)

// Fill in the faction name field
factionField.setText(`Mario's Emblem`)

// Fill the faction image field with our emblem image
factionImageField.setImage(emblemImage)

// Fill in the backstory field
backstoryField.setText(
  `Mario is a fictional character in the Mario video game franchise, owned by Nintendo and created by Japanese video game designer Shigeru Miyamoto. Serving as the company's mascot and the eponymous protagonist of the series, Mario has appeared in over 200 video games since his creation. Depicted as a short, pudgy, Italian plumber who resides in the Mushroom Kingdom, his adventures generally center upon rescuing Princess Peach from the Koopa villain Bowser. His younger brother and sidekick is Luigi.`,
)

// Fill in the traits field
traitsField.setText(
  [
    `Mario can use three basic three power-ups:`,
    `  • the Super Mushroom, which causes Mario to grow larger`,
    `  • the Fire Flower, which allows Mario to throw fireballs`,
    `  • the Starman, which gives Mario temporary invincibility`,
  ].join('\n'),
)

// Fill in the treasure field
treasureField.setText(['• Gold coins', '• Treasure chests'].join('\n'))

// Serialize the PDFDocument to bytes (a Uint8Array)
const pdfBytes = await pdfDoc.save()

// For example, `pdfBytes` can be:
//   • Written to a file in Node
//   • Downloaded from the browser
//   • Rendered in an <iframe>

Flatten Form

This example produces this PDF (when this PDF is used for th

Extension points exported contracts — how you extend this code

Embeddable (Interface)
(no doc) [5 implementers]
src/api/Embeddable.ts
StreamType (Interface)
(no doc) [4 implementers]
src/core/streams/Stream.ts
Fontkit (Interface)
(no doc) [1 implementers]
src/types/fontkit.ts
AttachmentOptions (Interface)
(no doc)
src/api/PDFDocumentOptions.ts
LiteralObject (Interface)
(no doc)
src/core/PDFContext.ts
BoundingBox (Interface)
(no doc)
src/types/fontkit.ts
SaveOptions (Interface)
(no doc)
src/api/PDFDocumentOptions.ts
LiteralArray (Interface)
(no doc)
src/core/PDFContext.ts

Core symbols most depended-on inside this repo

getTextField
called by 418
src/api/form/PDFForm.ts
setText
called by 418
src/api/form/PDFTextField.ts
get
called by 271
src/core/objects/PDFDict.ts
rgb
called by 214
src/api/colors.ts
create
called by 209
src/types/fontkit.ts
obj
called by 199
src/core/PDFContext.ts
set
called by 189
src/core/objects/PDFDict.ts
assertIs
called by 169
src/utils/validators.ts

Shape

Method 926
Function 359
Class 268
Interface 64
Enum 27

Languages

TypeScript100%
Java1%

Modules by API surface

src/core/errors.ts86 symbols
src/api/PDFPage.ts56 symbols
src/api/operators.ts55 symbols
src/api/PDFDocument.ts51 symbols
src/core/interactive/ViewerPreferences.ts50 symbols
src/api/errors.ts42 symbols
src/api/form/PDFTextField.ts38 symbols
src/api/form/PDFForm.ts36 symbols
src/core/structures/PDFPageLeaf.ts32 symbols
src/types/fontkit.ts31 symbols
src/api/form/PDFDropdown.ts30 symbols
src/api/svgPath.ts28 symbols

Dependencies from manifests, versioned

@babel/core7.5.0 · 1×
@babel/runtime7.5.1 · 1×
@pdf-lib/fontkit1.1.0 · 1×
@pdf-lib/standard-fonts1.0.0 · 1×
@pdf-lib/upng1.0.1 · 1×
@rollup/plugin-commonjs13.0.0 · 1×
@rollup/plugin-json4.1.0 · 1×
@rollup/plugin-node-resolve8.0.1 · 1×
@types/jest26.0.0 · 1×
@types/node-fetch2.5.7 · 1×
@types/pako1.0.1 · 1×
@zerollup/ts-transform-paths1.7.18 · 1×

For agents

$ claude mcp add pdf-lib \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact