Extract and diff the text of two PDF documents page by page to find additions, deletions, and changes.
use pdfluent::PdfDocument;
use std::collections::HashSet;
fn main() -> pdfluent::Result<()> {
let text_a = PdfDocument::open("version_a.pdf")?.text()?;
let text_b = PdfDocument::open("version_b.pdf")?.text()?;
if text_a == text_b {
println!("Documents are text-identical.");
} else {
let lines_a: HashSet<&str> = text_a.lines().collect();
let lines_b: HashSet<&str> = text_b.lines().collect();
for line in text_b.lines().filter(|l| !lines_a.contains(l)) {
println!("+ {}", line.trim());
}
for line in text_a.lines().filter(|l| !lines_b.contains(l)) {
println!("- {}", line.trim());
}
}
Ok(())
}Open the two PDF files you want to compare as read-only Documents.
let doc_a = PdfDocument::open("original.pdf")?;
let doc_b = PdfDocument::open("revised.pdf")?;TextDiff::compare extracts the plain text from each page and computes a line-level diff using the longest common subsequence algorithm.
let text_a = doc_a.text()?;
let text_b = doc_b.text()?;is_identical() is a quick check before iterating individual changes.
if text_a == text_b {
println!("No text differences found.");
return Ok(());
}Each DiffChange carries the page index, change kind (Added, Removed, or Changed), and the text content.
use std::collections::HashSet;
let lines_a: HashSet<&str> = text_a.lines().collect();
let lines_b: HashSet<&str> = text_b.lines().collect();
for line in text_b.lines().filter(|l| !lines_a.contains(l)) {
println!("+ {}", line.trim());
}
for line in text_a.lines().filter(|l| !lines_b.contains(l)) {
println!("- {}", line.trim());
}If the documents have different page counts, pages that exist only in one document are reported as whole-page additions or deletions.
use std::collections::HashSet;
let lines_a: HashSet<&str> = text_a.lines().collect();
let lines_b: HashSet<&str> = text_b.lines().collect();
let added = text_b.lines().filter(|l| !lines_a.contains(l)).count();
let removed = text_a.lines().filter(|l| !lines_b.contains(l)).count();
println!("Pages in A: {}", doc_a.page_count());
println!("Pages in B: {}", doc_b.page_count());
println!("Total line changes: {}", added + removed);No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.
Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.
Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.