Read the XMP metadata to determine whether a PDF claims PDF/A-1, 2, or 3 conformance, and run a structural validation check.
use pdfluent::Document;
fn main() -> pdfluent::Result<()> {
let doc = Document::open("archive.pdf")?;
match doc.pdf_a_level() {
Some(level) => println!("Claimed level: {:?}", level),
None => println!("No PDF/A claim in XMP metadata"),
}
let report = doc.validate_pdf_a()?;
if report.is_conformant() {
println!("Validation passed.");
} else {
for err in report.errors() {
println!("Error: {}", err.message());
}
}
Ok(())
}Read-only access is sufficient for conformance checking.
let doc = Document::open("archive.pdf")?;pdf_a_level() inspects the pdfaid:part and pdfaid:conformance XMP fields. It returns the declared level, not a validated one.
use pdfluent::pdfa::PdfALevel;
match doc.pdf_a_level() {
Some(PdfALevel::A1b) => println!("PDF/A-1b"),
Some(PdfALevel::A1a) => println!("PDF/A-1a"),
Some(PdfALevel::A2b) => println!("PDF/A-2b"),
Some(PdfALevel::A2a) => println!("PDF/A-2a"),
Some(PdfALevel::A2u) => println!("PDF/A-2u"),
Some(PdfALevel::A3b) => println!("PDF/A-3b"),
None => println!("Not PDF/A"),
}validate_pdf_a() checks the rules for the claimed level: embedded fonts, no encryption, no transparency (A-1), color spaces, output intent, and XMP metadata.
let report = doc.validate_pdf_a()?;
println!("Conformant: {}", report.is_conformant());
println!("Errors: {}", report.error_count());
println!("Warnings: {}", report.warning_count());Each ValidationError carries a rule ID (e.g. "6.3.3-1"), a human-readable message, and optionally the object number of the offending PDF object.
for err in report.errors() {
println!(
"[{}] {} (obj {})",
err.rule_id(),
err.message(),
err.object_number().map_or("?".to_string(), |n| n.to_string()),
);
}To validate against a target level regardless of the XMP claim, pass it explicitly.
use pdfluent::pdfa::PdfALevel;
let report = doc.validate_pdf_a_level(PdfALevel::A2b)?;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.