@zouchengxin/pdf-engine
v1.0.7
Published
A library that supports parsing and editing PDF files
Maintainers
Readme
Features
- Zero dependencies - The wasm file used is embedded in the package.
- Type-safe - TypeScript definitions are included.
- Works in browser and Node.js
- Powerful features - supports parsing and editing
Installation
# yarn add @zouchengxin/pdfium-engine
# pnpm install @zouchengxin/pdfium-engine
npm install @zouchengxin/pdfium-engineDemo
Usage
Initialization
import { PdfEngine } from '@zouchengxin/pdfium-engine';
const pdfEngine = new PdfEngine();
// API_KEY not provided, validity period until 2026-01-01, You can adjust the system time for testing.
// Or contact the developer to obtain the API key.
await pdfEngine.init(API_KEY);Parse
// Select PDF file and return uint8Array data
const selectPdfFile = async () => {
const [fileHandle] = await window.showOpenFilePicker({
types: [
{
description: 'Pdf Files',
accept: {
'application/pdf': ['.pdf'],
},
},
],
excludeAcceptAllOption: true,
multiple: false,
});
const file = await fileHandle.getFile();
const buf = await file.arrayBuffer();
const bytes = new Uint8Array(buf);
return bytes;
}
const data = await selectPdfFile();
// Load PDF documents, parameter Uint8Array
const pdfDoc = pdfEngine.loadPdf(data);
// Get the number of pages
const count = pdfDoc.getPageCount();
// Retrieves PDF metadata.
// returning the fields Title, Author, Subject, Keywords, Creator, Producer, CreationDate, and ModDate.
const meta = pdfDoc.getMetaData();
console.log('Page Count:', count);
console.log('Pdf Meta:', meta);
for (let i = 0; i < count; i++) {
// Obtain the page proxy object and perform operations such as parsing and editing.
const page = pdfDoc.getPageProxy(i);
// Get page width
const width = page.getPageWidth();
// Get page height
const height = page.getPageHeight();
// Retrieves all xobject objects on the page.
// including those of type TEXT, PATH, IMAGE, SHADING, and FORM.
const objs = page.getObjects();
// Retrieves all annotation objects on the page.
// including those of type TEXT, LINK, FREETEXT, LINE, SQUARE, CIRCLE, HIGHLIGHT, UNDERLINE, STAMP, INK etc.
const annots = page.getAnnotions();
console.log('Page Size:', width, height);
console.log('Page Objects:', objs);
console.log('Page Annotions:', annots);
}Rendering
// Retrieve the bitmap after page rendering; render only the xobject object, excluding annotations.
// Return value: ImageData object
const data = page.getBitmap();
// Retrieve page thumbnail; return empty if not stored.
// Return value: ImageData object
const data = page.getThumbnail();Create
Annotations
// Select Image file and return uint8Array data
const selectImageFile = async () => {
const [fileHandle] = await window.showOpenFilePicker({
types: [
{
description: 'Image Files',
accept: {
'image/*': ['.png','.jpeg','.jpg','.webp'],
},
},
],
excludeAcceptAllOption: true,
multiple: false,
});
const file = await fileHandle.getFile();
return file;
}
// get ImageData data
const getImageDataFromFile = async (file) =>{
const {promise,resolve} = Promise.withResolvers();
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
if (!ctx) return null;
ctx.drawImage(img, 0, 0);
const data = ctx.getImageData(0, 0, img.width, img.height);
resolve(data);
URL.revokeObjectURL(url);
};
img.src = url;
return promise;
}
// Create a link annotation.
// rect: a rectangular area.
// url: the redirect link.
page.createLinkAnno({
rect: [100, 100, 100, 40],
url: 'https://www.baidu.com',
});
// Create a FreeText annotation.
page.createFreeTextAnno({
rect: [100, 200, 100, 40],
content: 'Free Text Anno',
color: [255, 0, 0, 255],
fontSize: 14,
});
// Create a Text annotation.
page.createTextAnno({
rect: [100, 300, 100, 40],
content: 'Text Anno',
color: [255, 0, 0, 255],
fontSize: 14,
});
// Create a Square annotation.
page.createSquareAnno({
rect: [100, 400, 100, 60],
strokeColor: [255, 0, 0, 255],
fillColor: [0, 255, 0, 255],
});
// Create a Circle annotation.
page.createCircleAnno({
rect: [200, 100, 100, 100],
strokeColor: [255, 0, 0, 255],
fillColor: [0, 255, 0, 255],
});
// Create a Highlight annotation.
page.createHighlightAnno({
rect: [200, 200, 100, 60],
strokeColor: [255, 0, 0, 255],
fillColor: [0, 255, 0, 255],
});
// Create a Underline annotation.
page.createUnderlineAnno({
rect: [200, 300, 100, 60],
strokeColor: [255, 0, 0, 255],
fillColor: [0, 255, 0, 255],
});
// Create a Stamp annotation.
const file = await selectImageFile();
const data = await getImageDataFromFile(file);
page.createStampAnno({
rect: [200, 400, 100, 100],
matrix: { a: 50, b: 0, c: 0, d: 50, e: 200, f: 400 },
data,
});
// More features are under development.XObject
// Select Image file and return uint8Array data
const selectFontFile = async () => {
const [fileHandle] = await window.showOpenFilePicker({
types: [
{
description: 'Font Files',
accept: {
'font/*': ['.ttf'],
},
},
],
excludeAcceptAllOption: true,
multiple: false,
});
const file = await fileHandle.getFile();
const buf = await file.arrayBuffer();
const bytes = new Uint8Array(buf);
return bytes;
}
// Add Text XObject(system font)
// system font: Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique,
// Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic,
// Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique,
// Symbol, ZapfDingbats ( not supported for now )
// Note: system fonts only support English
page.addTextObj({
x: 300,
y: 100,
text: 'hello word!',
fontFamily: 'Helvetica-Bold',
strokeColor: [255, 0, 0, 255],
color: [0, 255, 0, 255],
});
// Add external fonts, such as Chinese fonts
// Note: Currently supports ttf files only
const data = await selectFontFile()
pdfDoc.addCustomFont('custom-font', data);
// Get registered external fonts
const fonts = pdfDoc.getCustomFonts();
console.log('custom fonts:', fonts);
// Add Text XObject(custom font)
page.addTextObj({
x: 300,
y: 200,
text: '你好世界',
fontFamily: 'custom-font',
});
// Add Image XObject
const file = await selectImageFile();
const data = await getImageDataFromFile(file);
page.addImageOBJ({
rect: [300, 300, 100, 100],
matrix: { a: 80, b: 0, c: 0, d: 80, e: 300, f: 300 },
data,
});Save
// Save the PDF data and return a Uint8Array.
const uint8Arr = pdfDoc.savePdf();Note
- color: [r, g, b, a], An array of red, green, blue, and blue
- rect: [x, y, w, h], An array consisting of the x-coordinate of the bottom left corner of the rectangular region, the y-coordinate of the bottom left corner of the rectangular region, the width of the rectangular region, and the height of the rectangular region.
- Coordinate: The origin is at the bottom left corner of the page, the horizontal direction is the x-axis, and the vertical direction is the y-axis.
- API_KEY: Contact the developer for details, or change your system time to before January 1, 2026 for testing purposes.
