@manojcoder/pdf-utils
v1.0.1
Published
Browser-compatible, privacy-first PDF utility library powered by pdf-lib
Maintainers
Readme
@manojcoder/pdf-utils
A lightweight, framework-agnostic, browser-compatible, privacy-first PDF manipulation library powered by pdf-lib. Designed specifically for client-side execution to keep all documents local and secure. It acts as an offline browser pdf editor, pdf-lib wrapper, and offline pdf modifier.
- Full Documentation & API Reference: https://pdftools.manojcoder.in/docs
🚀 UI Version for Non-Developers
Not a developer? Prefer a visual interface? Use our free, offline web utilities directly in your browser at PDF Toolkit.
Features
- 100% Local: No network uploads, no servers, full GDPR/SOC2 compliance by design.
- Strict Types: Fully written in TypeScript with full JSDoc IDE Intellisense.
- Tree-Shakable: Built using
tsuptargeting ESM and CommonJS formats. - Universal Inputs: Accepts browser
File,Blob,ArrayBuffer, orUint8Arraynatively. - Consistent Output: Always returns a standard
Uint8Array.
Installation
Install using npm, yarn, or pnpm:
npm install @manojcoder/pdf-utils pdf-libNote:
pdf-libis a peer dependency and needs to be installed alongside this package.
Unified Input Normalization
To make the developer experience seamless in the browser, all utility functions accept a union type PDFInput:
type PDFInput = File | Blob | ArrayBuffer | Uint8Array;Internally, these inputs are normalized into Uint8Array byte buffers using a memory-optimized reader. You do not need to manually parse file uploads or array buffers before passing them to the SDK.
Detailed API Documentation
1. unlockPDF
Loads an encrypted PDF using the provided password, saves the document without encryption restrictions, and returns the decrypted buffer.
Signature
function unlockPDF(file: PDFInput, password?: string): Promise<Uint8Array>Example
import { unlockPDF } from "@manojcoder/pdf-utils";
const fileInput = document.getElementById("pdf-upload") as HTMLInputElement;
fileInput.addEventListener("change", async () => {
const file = fileInput.files?.[0];
if (!file) return;
try {
const password = prompt("Enter PDF Password:");
if (!password) return;
const decryptedBytes = await unlockPDF(file, password);
const blob = new Blob([decryptedBytes], { type: "application/pdf" });
const downloadUrl = URL.createObjectURL(blob);
// Use downloadUrl to download or render the file...
} catch (error) {
console.error("Decryption failed. Incorrect password or invalid file structure.", error);
}
});2. mergePDFs
Merges multiple PDF documents in sequence into a single consolidated PDF document.
Signature
function mergePDFs(files: PDFInput[]): Promise<Uint8Array>Example
import { mergePDFs } from "@manojcoder/pdf-utils";
async function combineMultiplePDFs(filesList: File[]) {
try {
if (filesList.length < 2) {
alert("Please select at least 2 PDF files to merge.");
return;
}
const mergedBytes = await mergePDFs(filesList);
const blob = new Blob([mergedBytes], { type: "application/pdf" });
const downloadUrl = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = downloadUrl;
a.download = "merged_output.pdf";
a.click();
} catch (error) {
console.error("Failed to merge PDF files:", error);
}
}3. splitPDF
Splits a PDF document according to range instructions (e.g., "1-3, 5, 7-10").
Signature
function splitPDF(file: PDFInput, pageRanges: string): Promise<Uint8Array[]>Example
import { splitPDF } from "@manojcoder/pdf-utils";
async function sliceDocument(file: File) {
try {
const rangeExpression = "1-2, 4-4, 5-8"; // Slices: pages 1 to 2, page 4, and pages 5 to 8
const outputFiles = await splitPDF(file, rangeExpression);
outputFiles.forEach((bytes, index) => {
const blob = new Blob([bytes], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
console.log(`Document segment ${index + 1} generated successfully: ${url}`);
});
} catch (error) {
console.error("Failed to split document. Check bounds and range format.", error);
}
}4. rotatePages
Rotates all pages (or specific pages) by a specified angle.
Signature
function rotatePages(
file: PDFInput,
degreesToRotate: 90 | 180 | 270,
specificPages?: number[]
): Promise<Uint8Array>Example
import { rotatePages } from "@manojcoder/pdf-utils";
async function rotateSelectedPages(file: File) {
try {
// Rotates the first page (index 0) and third page (index 2) by 90 degrees clockwise
const rotatedBytes = await rotatePages(file, 90, [0, 2]);
const blob = new Blob([rotatedBytes], { type: "application/pdf" });
// Use the rotated blob...
} catch (error) {
console.error("Rotation operation failed:", error);
}
}5. extractPages
Extracts specific 0-indexed pages and compiles them into a new PDF document.
Signature
function extractPages(file: PDFInput, pagesToExtract: number[]): Promise<Uint8Array>Example
import { extractPages } from "@manojcoder/pdf-utils";
async function extractKeyPages(file: File) {
try {
const pages = [0, 1, 4]; // Extracts page 1, 2, and 5
const extractedBytes = await extractPages(file, pages);
const blob = new Blob([extractedBytes], { type: "application/pdf" });
// Use extracted document blob...
} catch (error) {
console.error("Page extraction failed:", error);
}
}6. removePages
Removes specific 0-indexed pages from a PDF document.
Signature
function removePages(file: PDFInput, pagesToRemove: number[]): Promise<Uint8Array>Example
import { removePages } from "@manojcoder/pdf-utils";
async function deleteUnwantedPages(file: File) {
try {
const pagesToDelete = [2, 3]; // Deletes third page (index 2) and fourth page (index 3)
const sanitizedBytes = await removePages(file, pagesToDelete);
const blob = new Blob([sanitizedBytes], { type: "application/pdf" });
// Use sanitized document blob...
} catch (error) {
console.error("Page removal failed:", error);
}
}7. reorderPages
Reorders pages in the document based on a new sequence index array.
Signature
function reorderPages(file: PDFInput, newOrder: number[]): Promise<Uint8Array>Example
import { reorderPages } from "@manojcoder/pdf-utils";
async function rearrangeDocumentSequence(file: File, totalPagesCount: number) {
try {
// Reverse the sequence order of the entire PDF
const reversedOrder = Array.from({ length: totalPagesCount }, (_, i) => i).reverse();
const reorderedBytes = await reorderPages(file, reversedOrder);
const blob = new Blob([reorderedBytes], { type: "application/pdf" });
// Use reordered blob...
} catch (error) {
console.error("Reorder operation failed:", error);
}
}8. imagesToPDF
Compiles an array of images (JPEG or PNG) into a single PDF document. Automatically matches page dimensions to dimensions of the images.
Signature
function imagesToPDF(images: PDFInput[]): Promise<Uint8Array>Example
import { imagesToPDF } from "@manojcoder/pdf-utils";
async function createPDFFromImages(fileList: File[]) {
try {
// Convert array of image files into a single PDF
const pdfBytes = await imagesToPDF(fileList);
const blob = new Blob([pdfBytes], { type: "application/pdf" });
const url = URL.createObjectURL(blob);
window.open(url);
} catch (error) {
console.error("Image compilation failed:", error);
}
}9. editMetadata
Edits metadata properties of a PDF document (Title, Author, Subject, Creator, Producer, Keywords).
Signature
interface MetadataOptions {
title?: string;
author?: string;
subject?: string;
creator?: string;
keywords?: string[];
producer?: string;
}
function editMetadata(file: PDFInput, metadataOptions: MetadataOptions): Promise<Uint8Array>
Example
import { editMetadata } from "@manojcoder/pdf-utils";
async function addCompanyMetadata(file: File) {
try {
const metadata = {
title: "Quarterly Financial Analysis",
author: "Manoj Kumawat",
creator: "PDF Toolkit SDK",
keywords: ["Finance", "Report", "Q3"],
subject: "Company Internal Auditing"
};
const updatedBytes = await editMetadata(file, metadata);
const blob = new Blob([updatedBytes], { type: "application/pdf" });
// Use updated blob...
} catch (error) {
console.error("Metadata modification failed:", error);
}
}10. addWatermark
Adds diagonal, semi-transparent watermark text to every page of a PDF document.
Signature
interface WatermarkOptions {
fontSize?: number;
opacity?: number;
rotation?: number; // angle in degrees
color?: string; // Hex color code
}
function addWatermark(
file: PDFInput,
text: string,
options?: WatermarkOptions
): Promise<Uint8Array>Example
import { addWatermark } from "@manojcoder/pdf-utils";
async function applyConfidentialWatermark(file: File) {
try {
const config = {
fontSize: 56,
opacity: 0.25,
rotation: 45, // 45-degree angle diagonal
color: "#EF4444" // Crimson red color
};
const watermarkedBytes = await addWatermark(file, "CONFIDENTIAL", config);
const blob = new Blob([watermarkedBytes], { type: "application/pdf" });
// Use watermarked blob...
} catch (error) {
console.error("Watermark overlay failed:", error);
}
}⚡ Performance & Memory Optimization
Because all operations execute locally on the client's machine (often within mobile browser constraints), follow these performance best practices:
Explicit Memory Revocation: When converting output bytes to object URLs, always clean up the browser memory reference when the URL is no longer needed:
const url = URL.createObjectURL(blob); // ... after download completes or preview is closed URL.revokeObjectURL(url);Garbage Collection: Avoid keeping reference pointers to large file structures or array buffers in your application state. Nuxt/React/Vue reactive objects (e.g.
ref(uint8array)) can block browser garbage collection. Always store raw buffers in standard JavaScript local scopes wherever possible.Handle heavy loops asynchronously: When processing batches of large files, throttle operations or use a Web Worker thread to ensure the browser UI doesn't freeze during intensive document assembly processes.
License
MIT License
