pdf-toolkit
v1.0.1
Published
A comprehensive npm package for PDF manipulation: merge, split, annotate, and stamp PDF files
Maintainers
Readme
PDF Toolkit
A comprehensive, production-ready npm package for PDF manipulation. Easily merge, split, annotate, and stamp PDF files with a simple, user-friendly API.
Features
- ✅ Merge PDFs - Combine multiple PDF files into one
- ✅ Split PDFs - Split PDFs into individual pages or custom ranges
- ✅ Annotate PDFs - Add text, highlights, underlines, shapes, and more
- ✅ Stamp PDFs - Add text or image stamps with full customization
Installation
npm install pdf-toolkitQuick Start
import { mergePDFs, splitPDF, annotatePDF, stampPDF } from 'pdf-toolkit';Browser Support (React/Next.js)
This package is fully compatible with React and Next.js applications! Use the buffer-based functions for browser environments.
Key Features for Browser Usage:
- ✅ Works in React, Next.js, and any browser environment
- ✅ Store PDFs in React state (as buffers or blobs)
- ✅ Optional download functionality
- ✅ Easy backend integration
- ✅ No file system dependencies
React/Next.js Quick Example
import {
mergePDFsFromBuffers,
pdfBufferToBlob,
downloadPDF,
fileToPdfBuffer
} from 'pdf-toolkit';
// In your React component
const handleMerge = async (files: File[]) => {
// Convert files to buffers
const buffers = await Promise.all(
files.map(file => fileToPdfBuffer(file))
);
// Merge PDFs (returns Uint8Array)
const mergedPdf = await mergePDFsFromBuffers(buffers);
// Store in state (as buffer)
setPdfBuffer(mergedPdf);
// Or convert to Blob for easier use
const blob = pdfBufferToBlob(mergedPdf);
setPdfBlob(blob);
// Optional: Download if user wants
// downloadPDF(mergedPdf, 'merged.pdf');
// Send to backend
const formData = new FormData();
formData.append('pdf', pdfBufferToFile(mergedPdf, 'merged.pdf'));
await fetch('/api/upload', { method: 'POST', body: formData });
};Browser Utility Functions
import {
pdfBufferToBlob, // Convert buffer to Blob (for state/display)
pdfBufferToFile, // Convert buffer to File (for FormData)
downloadPDF, // Download PDF to user's machine
fileToPdfBuffer, // Convert File/Blob to buffer (works for PDFs and images)
} from 'pdf-toolkit';See examples/react-usage.tsx for complete React examples.
Usage Examples
Merge PDFs
Merge multiple PDF files into a single document:
import { mergePDFs } from 'pdf-toolkit';
// Merge multiple PDFs
await mergePDFs(
['file1.pdf', 'file2.pdf', 'file3.pdf'],
'merged.pdf',
{
keepBookmarks: true,
keepMetadata: true
}
);Or work with buffers:
import { mergePDFsFromBuffers } from 'pdf-toolkit';
const pdf1 = await fs.readFile('file1.pdf');
const pdf2 = await fs.readFile('file2.pdf');
const merged = await mergePDFsFromBuffers([pdf1, pdf2]);Split PDFs
Split a PDF into individual pages:
import { splitPDF } from 'pdf-toolkit';
// Split into individual pages
const outputFiles = await splitPDF('input.pdf', './output', {
outputPattern: 'page_{page}.pdf'
});
// Creates: page_1.pdf, page_2.pdf, page_3.pdf, etc.Split by page ranges:
// Split by specific page ranges
const outputFiles = await splitPDF('input.pdf', './output', {
pageRanges: '1-3,5,7-9',
outputPattern: 'section_{index}.pdf'
});
// Creates: section_1.pdf (pages 1-3), section_2.pdf (page 5), section_3.pdf (pages 7-9)Or work with buffers:
import { splitPDFFromBuffer } from 'pdf-toolkit';
const pdfBuffer = await fs.readFile('input.pdf');
const splits = await splitPDFFromBuffer(pdfBuffer, {
pageRanges: '1-5,10-15'
});Annotate PDFs
Add various types of annotations to your PDFs:
import { annotatePDF } from 'pdf-toolkit';
await annotatePDF('input.pdf', 'output.pdf', [
// Text annotation
{
type: 'text',
pageNumber: 1,
x: 100,
y: 700,
width: 200,
height: 50,
text: 'Important Note',
color: [1, 0, 0], // Red
fontSize: 14
},
// Highlight annotation
{
type: 'highlight',
pageNumber: 1,
x: 100,
y: 600,
width: 300,
height: 20,
color: [1, 1, 0], // Yellow highlight
text: 'Highlighted text'
},
// Underline annotation
{
type: 'underline',
pageNumber: 1,
x: 100,
y: 550,
width: 200,
height: 15,
color: [0, 0, 1], // Blue
text: 'Underlined text'
},
// Rectangle annotation
{
type: 'rectangle',
pageNumber: 1,
x: 100,
y: 500,
width: 150,
height: 100,
color: [0, 1, 0], // Green border
text: 'Box'
},
// Circle annotation
{
type: 'circle',
pageNumber: 1,
x: 300,
y: 500,
width: 100,
height: 100,
color: [1, 0, 1], // Magenta
text: 'Circle'
}
]);Available annotation types:
text- Plain text annotationhighlight- Highlighted rectangle with optional textunderline- Underline with optional textstrikethrough- Strikethrough line with optional textrectangle- Rectangle border with optional textcircle- Circle border with optional text
Stamp PDFs
Add text or image stamps to your PDFs:
import { stampPDF } from 'pdf-toolkit';
// Text stamp
await stampPDF('input.pdf', 'output.pdf', [
{
pageNumber: 1,
x: 100,
y: 700,
width: 200,
height: 50,
text: 'CONFIDENTIAL',
backgroundColor: [1, 0, 0], // Red background
textColor: [1, 1, 1], // White text
fontSize: 24,
borderColor: [0, 0, 0],
borderWidth: 2,
opacity: 0.9
}
]);
// Image stamp
await stampPDF('input.pdf', 'output.pdf', [
{
pageNumber: 1,
x: 100,
y: 700,
width: 200,
height: 100,
imagePath: './logo.png',
rotation: 0,
opacity: 0.8
}
]);
// Combined text and image stamp
await stampPDF('input.pdf', 'output.pdf', [
{
pageNumber: 1,
x: 100,
y: 700,
width: 200,
height: 50,
text: 'APPROVED',
backgroundColor: [0, 1, 0], // Green
textColor: [1, 1, 1], // White
fontSize: 20,
rotation: -15, // Rotate 15 degrees counter-clockwise
opacity: 0.9
}
]);API Reference
Merge Functions
mergePDFs(inputPaths, outputPath, options?)
Merges multiple PDF files from file paths.
Parameters:
inputPaths: string[]- Array of PDF file paths to mergeoutputPath: string- Path where merged PDF will be savedoptions?: MergeOptions- Optional configurationkeepBookmarks?: boolean- Keep bookmarks from source PDFs (default:true)keepMetadata?: boolean- Keep metadata from source PDFs (default:true)
mergePDFsFromBuffers(inputBuffers, options?)
Merges multiple PDF files from buffers.
Parameters:
inputBuffers: Uint8Array[]- Array of PDF buffersoptions?: MergeOptions- Optional configuration
Returns: Promise<Uint8Array> - Merged PDF as buffer
Split Functions
splitPDF(inputPath, outputDir, options?)
Splits a PDF file from file path.
Parameters:
inputPath: string- Path to PDF file to splitoutputDir: string- Directory where split PDFs will be savedoptions?: SplitOptions- Optional configurationpageRanges?: string- Page ranges (e.g., "1-3,5,7-9"). If not provided, splits into individual pagesoutputPattern?: string- Output file name pattern. Use{index}for file index,{page}for page number,{basename}for original filename (default:"split_{index}.pdf")
Returns: Promise<string[]> - Array of output file paths
splitPDFFromBuffer(inputBuffer, options?)
Splits a PDF file from buffer.
Parameters:
inputBuffer: Uint8Array- PDF bufferoptions?: SplitOptions- Optional configuration
Returns: Promise<Uint8Array[]> - Array of PDF buffers
Annotate Functions
annotatePDF(inputPath, outputPath, annotations)
Adds annotations to a PDF file.
Parameters:
inputPath: string- Path to PDF fileoutputPath: string- Path where annotated PDF will be savedannotations: AnnotationOptions[]- Array of annotation configurations
AnnotationOptions:
x: number- X coordinate (in points)y: number- Y coordinate (in points, from top-left)width: number- Width (in points)height: number- Height (in points)pageNumber: number- Page number (1-indexed)text?: string- Text contentcolor?: [number, number, number]- RGB color (0-1, default:[0, 0, 0])fontSize?: number- Font size (default:12)type?: 'text' | 'highlight' | 'underline' | 'strikethrough' | 'rectangle' | 'circle'- Annotation type (default:'text')
annotatePDFFromBuffer(inputBuffer, annotations)
Adds annotations to a PDF from buffer.
Returns: Promise<Uint8Array> - Annotated PDF as buffer
Stamp Functions
stampPDF(inputPath, outputPath, stamps)
Adds stamps to a PDF file.
Parameters:
inputPath: string- Path to PDF fileoutputPath: string- Path where stamped PDF will be savedstamps: StampOptions[]- Array of stamp configurations
StampOptions:
x: number- X coordinate (in points)y: number- Y coordinate (in points, from top-left)width: number- Width (in points)height: number- Height (in points)pageNumber: number- Page number (1-indexed)text?: string- Text content for text stampsimagePath?: string- Path to image file (PNG, JPG) for image stampsimageData?: Uint8Array- Image data as buffer for image stampsrotation?: number- Rotation angle in degrees (default:0)opacity?: number- Opacity 0-1 (default:1)backgroundColor?: [number, number, number]- Background color (RGB 0-1)textColor?: [number, number, number]- Text color (RGB 0-1, default:[0, 0, 0])fontSize?: number- Font size (default:24)borderColor?: [number, number, number]- Border color (RGB 0-1)borderWidth?: number- Border width in points (default:0)
stampPDFFromBuffer(inputBuffer, stamps)
Adds stamps to a PDF from buffer.
Returns: Promise<Uint8Array> - Stamped PDF as buffer
Coordinate System
PDF coordinates use points (1/72 inch) with the origin (0, 0) at the bottom-left corner. However, for convenience, this library uses top-left origin (like web coordinates) for the y parameter. The library automatically converts coordinates internally.
Standard page sizes:
- Letter: 612 × 792 points
- A4: 595 × 842 points
Error Handling
All functions throw descriptive errors if:
- Required parameters are missing
- Files cannot be read or written
- Page numbers are out of range
- Invalid PDF format
- Other processing errors
Always wrap calls in try-catch blocks:
try {
await mergePDFs(['file1.pdf', 'file2.pdf'], 'merged.pdf');
} catch (error) {
console.error('Failed to merge PDFs:', error.message);
}Requirements
- Node.js >= 14.0.0
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Support
For issues, questions, or feature requests, please open an issue on GitHub.
