utilvo-pdf-merger
Lightweight, zero-dependency library for inspecting PDF binary headers (%PDF-1.x), counting /Type /Page objects, validating cross-reference (xref) tables, and merging multiple PDF byte streams into a single document with renumbered indirect objects.
Built as the open-source companion library for the Merge PDF document processing utility, utilvo-pdf-merger allows developers to pre-validate PDF buffers, verify %%EOF markers, count total pages across multi-file batches, and concatenate uncompressed PDF streams programmatically in Node.js, Python, Go, Rust, PHP, Ruby, Elixir, Dart, Swift, Lua, and .NET.
Architecture & How It Works
When combining multiple PDF files into a single document, raw byte concatenation is invalid because each PDF file contains its own independent object numbering (1 0 obj, 2 0 obj, ...) and a byte-offset cross-reference (xref) table at the end of the file:
-
Header & Integrity Inspection (
inspectPdf/inspect_pdf): Reads the first 1,024 bytes of each buffer to verify the%PDF-1.xspecification header and scans the trailer for a valid%%EOFmarker. -
Page Tree Counting (
countPdfPages/count_pdf_pages): Scans indirect dictionary objects matching/Type /Page\b(?!s)to count leaf page nodes while excluding parent/Type /Pagescatalog containers. -
Indirect Object Renumbering &
xrefReconstruction (mergePdfBuffers/merge_pdf_bytes): Extracts page content streams across all input documents, assigns sequential object IDs under a unified/Type /Pagesroot array (/Kids [...]), and calculates exact byte offsets (%010d 00000 n) to emit a standards-compliantxreftable andtrailerdictionary.
Installation
Node.js (npm)
npm install utilvo-pdf-mergerPython (PyPI)
pip install utilvo-pdf-mergerRust (Cargo)
cargo add utilvo-pdf-mergerGo
go get github.com/utilvo/utilvo-pdf-mergerDart / Flutter
dart pub add utilvo_pdf_mergerElixir (Hex)
{:utilvo_pdf_merger, "~> 1.0"}Ruby (RubyGems)
gem install utilvo-pdf-mergerUsage Examples
JavaScript / TypeScript
import { inspectPdf, countPdfPages, mergePdfBuffers } from 'utilvo-pdf-merger';
// 1. Inspect an individual PDF buffer before merging
const info = inspectPdf(pdfBytes);
console.log(info.version, info.pageCount, info.isValid);
// 2. Merge multiple PDF byte buffers into a single PDF document
const mergedBytes = mergePdfBuffers([pdfBufferA, pdfBufferB]);Python
from utilvo_pdf_merger import inspect_pdf, count_pdf_pages, merge_pdf_bytes
# 1. Validate PDF header, EOF marker, and page count
info = inspect_pdf(pdf_bytes)
print(info["version"], info["page_count"], info["is_valid"])
# 2. Merge multiple PDF byte streams into a unified PDF
merged = merge_pdf_bytes([pdf_a, pdf_b])Rust
use utilvo_pdf_merger::{inspect_pdf, count_pdf_pages, merge_pdf_buffers};
let info = inspect_pdf(&pdf_bytes);
assert!(info.is_valid);
let merged = merge_pdf_buffers(&[&pdf_a, &pdf_b]);Go
import utilvopdfmerger "github.com/utilvo/utilvo-pdf-merger"
info := utilvopdfmerger.InspectPdf(pdfBytes)
merged, err := utilvopdfmerger.MergePdfBuffers([][]byte{pdfA, pdfB})API Reference
| Function | Parameters | Returns | Description |
|---|---|---|---|
inspectPdf / inspect_pdf
|
bytes: Uint8Array | bytes |
PdfInspectionResult |
Extracts PDF specification version (1.4–2.0), page count, and %%EOF integrity status. |
countPdfPages / count_pdf_pages
|
bytes: Uint8Array | bytes |
number |
Counts leaf /Type /Page dictionary entries (excluding /Type /Pages parent nodes). |
mergePdfBuffers / merge_pdf_bytes
|
documents: Array<Uint8Array | bytes> |
Uint8Array | bytes |
Extracts page content streams and constructs a consolidated PDF document with a unified /Pages root and rebuilt xref table. |
License
MIT