
Product
Introducing Reports: An Extensible Reporting Framework for Socket Data
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.
A native Node.js binding for the Poppler PDF library, providing high-performance access to PDF documents through TypeScript/JavaScript.
You need Poppler development libraries installed on your system:
sudo apt-get update
sudo apt-get install libpoppler-cpp-dev build-essential
brew install poppler
vcpkg install poppler[cpp]:x64-windows
npm install poppler-ts
When you install the package, it will automatically attempt to build the native addon:
If the automatic build fails, you can build manually after installing system dependencies:
# Install system dependencies first, then:
npm run build:native
If you're developing or need the full source:
git clone https://github.com/maifeeulasad/poppler-ts.git
cd poppler-ts
pnpm install
pnpm build
import { Document } from 'poppler-ts';
import * as fs from 'fs';
// Load a PDF document
const doc = Document.loadFromFile('./document.pdf');
// Or load from buffer
const buffer = fs.readFileSync('./document.pdf');
const doc2 = Document.loadFromBuffer(buffer);
// Get basic document info
console.log('Pages:', doc.getPageCount());
console.log('Is locked:', doc.isLocked());
console.log('Metadata:', doc.getMetadata());
// Get the first page
const page = doc.getPage(0);
// Get page properties
const size = page.getSize();
console.log(`Page size: ${size.width}x${size.height} points`);
// Extract text
const text = page.getText();
console.log('Page text:', text);
// Get page rotation
const rotation = page.getRotation();
console.log(`Page rotation: ${rotation}°`);
// Get text boxes with coordinates
const textBoxes = page.getTextBoxes();
console.log(`Found ${textBoxes.length} text boxes`);
textBoxes.forEach((box, index) => {
console.log(`Box ${index + 1}: "${box.text}"`);
console.log(` Position: (${box.bbox.x}, ${box.bbox.y})`);
console.log(` Size: ${box.bbox.width}x${box.bbox.height}`);
});
// Export page content to structured JSON
const pageJSON = page.exportToJSON();
console.log(`Page dimensions: ${pageJSON.page.width}x${pageJSON.page.height}`);
console.log(`Found ${pageJSON.lines.length} text lines`);
pageJSON.lines.forEach((line, index) => {
console.log(`Line ${index + 1}: "${line.text}"`);
console.log(` Words: ${line.words.length}`);
line.words.forEach((word, wordIndex) => {
console.log(` Word ${wordIndex + 1}: "${word.text}" at (${word.bbox.x}, ${word.bbox.y})`);
});
});
// Render page to image
const image = page.renderToImage({
dpi: 150,
rotation: 0
});
console.log(`Rendered image: ${image.width}x${image.height}`);
console.log(`Format: ${image.format}`);
console.log(`Data size: ${image.data.length} bytes`);
// Save as PNG (requires additional image processing library)
fs.writeFileSync('page.png', image.data);
// Check if document is locked
if (doc.isLocked()) {
// Try to unlock with password
const unlocked = doc.unlock('password123');
if (!unlocked) {
console.error('Failed to unlock document');
return;
}
}
// Now you can access the document content
const page = doc.getPage(0);
const text = page.getText();
Document.loadFromFile(filepath: string, password?: string): Document
Document.loadFromBuffer(buffer: Buffer, password?: string): Document
getPageCount(): number
getPage(pageIndex: number): Page
getMetadata(): DocumentMetadata
isLocked(): boolean
unlock(password: string): boolean
getSize(): PageSize
getText(): string
getTextBoxes(): TextBox[]
exportToJSON(): PageJSON
renderToImage(options?: RenderOptions): RenderedImage
getRotation(): number
getDuration(): number
interface PageSize {
width: number; // Page width in points
height: number; // Page height in points
x: number; // X offset (usually 0)
y: number; // Y offset (usually 0)
}
interface RenderOptions {
dpi?: number; // Resolution (default: 72)
rotation?: number; // Additional rotation in degrees (default: 0)
}
interface RenderedImage {
data: Buffer; // Raw image data in ARGB32 format
width: number; // Image width in pixels
height: number; // Image height in pixels
bytesPerRow: number; // Bytes per row
format: string; // Always "ARGB32"
}
interface TextBox {
text: string;
bbox: {
x: number;
y: number;
width: number;
height: number;
};
}
interface Word {
text: string;
bbox: {
x: number;
y: number;
width: number;
height: number;
};
}
interface Line {
text: string;
bbox: {
x: number;
y: number;
width: number;
height: number;
};
words: Word[];
}
interface PageJSON {
page: {
width: number;
height: number;
rotation: number;
};
lines: Line[];
}
interface DocumentMetadata {
[key: string]: string; // Key-value pairs of metadata
}
pnpm build - Build both native addon and TypeScript compilationpnpm build:native - Build only the native C++ addon using node-gyppnpm build:ts - Compile only TypeScript filespnpm clean - Clean build artifacts and native addonpnpm test - Run the test suite with a sample PDFpnpm example - Run the example demonstrating advanced featurespnpm lint - Check code style with ESLintpnpm lint:fix - Automatically fix linting issuesThe project includes comprehensive tests that demonstrate all functionality:
To run tests:
# Place a test PDF file at ./test.pdf
pnpm test
For advanced feature examples:
pnpm example
├── src/
│ ├── cpp/ # C++ native binding source
│ │ ├── poppler_binding.cpp # Main binding file
│ │ ├── document.h # Document class header
│ │ ├── document.cpp # Document class implementation
│ │ ├── page.h # Page class header
│ │ └── page.cpp # Page class implementation
│ ├── types/ # TypeScript type definitions
│ │ └── index.ts # Complete API type definitions
│ ├── index.ts # Main TypeScript entry point
│ ├── test.ts # Comprehensive test suite
│ └── example.ts # Advanced features demonstration
├── dist/ # Compiled JavaScript output
├── build/ # Native addon build artifacts
│ └── Release/
│ └── poppler_binding.node
├── .github/workflows/ # CI/CD workflows
│ ├── lint.yml # Linting on push/PR
│ └── publish2npm.yaml # NPM publishing on release
├── binding.gyp # node-gyp build configuration
├── eslint.config.ts # ESLint configuration
├── package.json # Project configuration
├── tsconfig.json # TypeScript configuration
└── README.md
The project includes GitHub Actions workflows for:
Both workflows include the necessary system dependencies for building the native addon.
If the automatic build fails during npm install:
npm run build:native after installing dependenciesbuild/Release/poppler_binding.node existsnpm cache clean --force and reinstallMissing Poppler libraries:
# Ubuntu/Debian
sudo apt-get update
sudo apt-get install libpoppler-cpp-dev build-essential
# macOS
brew install poppler
# Windows
vcpkg install poppler[cpp]:x64-windows
node-gyp compilation errors:
npm explore node-gyp -- npm run cleanmacOS path issues:
export PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:$PKG_CONFIG_PATH"
pnpm run build:native
Module not found: Ensure native addon was built:
ls build/Release/poppler_binding.node
PDF loading errors: Check file permissions and PDF validity
Memory issues: Large PDFs may require more memory allocation
Text extraction issues: Some PDFs may have complex layouts
pnpm lintMIT License - see LICENSE file for details.
Built with the excellent Poppler PDF library and Node.js addon API.
FAQs
Native Node.js binding for Poppler PDF library
We found that poppler-ts demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Explore exportable charts for vulnerabilities, dependencies, and usage with Reports, Socket’s new extensible reporting framework.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.