Repository navigation
unpdf 2.0 is here! 🎉
This major release extracts every image on a page, adds page inspection and more rendering formats, and trims the API. unpdf now ships as ESM only and requires Node.js 24.
🔥 What's New
- Complete image extraction –
extractImagesreturns inline images and image masks too, as RGBA pixels or as PNG withformat: 'png', each with its position on the page inbounds. - Page inspection –
inspectPagesmeasures text and image coverage per page, e.g. to tell scanned pages from born-digital ones. - JPEG and WebP rendering –
renderPageAsImagetakesformat: 'png' | 'jpeg' | 'webp'and aquality. - CMaps and standard fonts in Node.js – with
pdfjs-distinstalled, both load from that package, so CJK text without embedded mappings extracts correctly. - Typed metadata –
getMetatypes the/Infodictionary asPDFInfo.
🚀 How to Upgrade
pnpm add unpdf@^2unpdf 2 requires Node.js 24 or later. CommonJS builds are gone – replace require('unpdf') with import. The steps below cover every other breaking change.
1. Define PDF.js Without await
definePDFJSModule stores the loader and loads PDF.js on first use. configureUnPDF and resolvePDFJSImport are removed.
- await configureUnPDF({ pdfjs: () => import('pdfjs-dist/legacy/build/pdf.mjs') })
+ definePDFJSModule(() => import('pdfjs-dist/legacy/build/pdf.mjs'))A loader that fails now throws on the first call of another method. To load PDF.js up front, call await getResolvedPDFJS() where you used resolvePDFJSImport().
2. Flatten extractLinks for All Links
links holds one array per page.
const { links } = await extractLinks(pdf)
+ const allLinks = links.flat()3. Use the Uint8Array From renderPageAsImage
const image = await renderPageAsImage(pdf, 1, {
canvasImport: () => import('@napi-rs/canvas'),
})
- await writeFile('page.png', new Uint8Array(image))
+ await writeFile('page.png', image)A scale, width, or height of 0 now throws instead of falling back to a scale of 1. createIsomorphicCanvasFactory is removed – each document carries PDF.js' own canvas factory as pdf.canvasFactory.
4. Read Extracted Images as RGBA
ExtractedImageObject is now ExtractedImage. data always holds four bytes per pixel, so channels is gone, and key is null for small inline images.
const [image] = await extractImages(pdf, 1)
await sharp(image.data, {
- raw: { width: image.width, height: image.height, channels: image.channels },
+ raw: { width: image.width, height: image.height, channels: 4 },
}).toFile('image.png')Or drop sharp and pass { format: 'png' }. A page may now return more images than before, since inline images and image masks count, or fewer, since images inside soft masks and hidden layers are skipped.
5. Check the getMeta Types
info is typed as PDFInfo and metadata as Metadata | null – the runtime values are unchanged. Non-standard /Info entries sit in info.Custom, a Map.
- const title = metadata.get('dc:title')
+ const title = metadata?.get('dc:title')6. Expect Standard Fonts in Node.js Renders
With pdfjs-dist installed, getDocumentProxy sets useSystemFonts: false in Node.js and draws non-embedded standard fonts with PDF.js' own font files instead of the host's. To keep the host fonts, pass useSystemFonts: true to getDocumentProxy.
🚨 Breaking Changes
- Ship ESM only and require Node.js 24 - by @johannschopplich (d0d6c)
- Load the defined PDF.js module on first use and drop
configureUnPDF- by @johannschopplich (e1ed1) - Return
extractLinksresults per page - by @johannschopplich (31ec4) - Type
getMetainfo fields and returnnullwithout XMP metadata - by @johannschopplich (9bb12) - Return rendered pages as
Uint8Arrayand add JPEG and WebP output - by @johannschopplich (62fc4) - Extract all images of a page as RGBA or PNG with their placement - by @johannschopplich (4b7b9)
🚀 Features
- Add
inspectPagesfor per-page text and image measurements - by @johannschopplich (7459a)
🐞 Bug Fixes
- Load CMaps and standard fonts from the local
pdfjs-distin Node.js - by @johannschopplich (7051f) - Place images of annotation appearances on the page - by @johannschopplich (8b7e7)
- Harden
renderPageAsImagesizes, formats, and canvas detection - by @johannschopplich (623e9) - Ignore soft masks and hidden layers when extracting images and inspecting pages - by @johannschopplich (5bcb2)
- Use the standard fonts of
pdfjs-distin Node.js - by @johannschopplich (3da7a) - Accept
RenderPageAsImageOptionsinrenderPageAsImageand exportMetadata- by @johannschopplich (bcf52)
🏎 Performance
- Inspect pages one at a time and release their resources - by @johannschopplich (8239f)