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::{PdfDocument, PdfAProfile};
fn main() -> pdfluent::Result<()> {
let doc = PdfDocument::open("invoice.pdf")?;
let report = doc.validate_pdfa(PdfAProfile::A2b)?;
println!("compliant: {}", report.is_compliant());
Ok(())
}Read-only access is sufficient for conformance checking.
let doc = PdfDocument::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::PdfAProfile;
let report = doc.validate_pdfa(PdfAProfile::A2b)?;
println!("PDF/A-2b compliant: {}", report.is_compliant());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_pdfa(PdfAProfile::A2b)?;
println!("Compliant: {}", report.is_compliant());
println!("Violations: {}", report.violations.len());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 v in &report.violations {
println!("[{}] {} (page {:?})", v.rule, v.message, v.page);
}To validate against a target level regardless of the XMP claim, pass it explicitly.
use pdfluent::PdfAProfile;
// Validate against a specific profile (A1b, A2b, or A3b)
let report = doc.validate_pdfa(PdfAProfile::A1b)?;
println!("A1b compliant: {}", report.is_compliant());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.