Auto-repair the most frequent PDF/A conformance problems: missing output intent, unembedded fonts, transparency, and missing XMP metadata.
use pdfluent::{Document, pdfa::{PdfALevel, PdfAFixOptions}};
fn main() -> pdfluent::Result<()> {
let mut doc = Document::open("noncompliant.pdf")?;
let opts = PdfAFixOptions::for_level(PdfALevel::A2b)
.embed_missing_fonts(true)
.flatten_transparency(true)
.add_xmp_metadata(true);
let report = doc.fix_pdf_a_errors(opts)?;
println!("Fixed {} issue(s)", report.fixed_count());
doc.save("fixed.pdf")?;
Ok(())
}Run validate_pdf_a() before fixing to get a baseline list of issues.
let doc = Document::open("noncompliant.pdf")?;
let before = doc.validate_pdf_a()?;
println!("Errors before: {}", before.error_count());
for e in before.errors() {
println!(" [{}] {}", e.rule_id(), e.message());
}PdfAFixOptions controls which repairs are attempted. Each fix is opt-in to avoid unintended side effects.
use pdfluent::pdfa::{PdfALevel, PdfAFixOptions};
let opts = PdfAFixOptions::for_level(PdfALevel::A2b)
.embed_missing_fonts(true)
.flatten_transparency(true)
.add_xmp_metadata(true)
.add_output_intent_if_missing(true)
.remove_javascript(true)
.remove_embedded_files(false); // keep attachments for PDF/A-3fix_pdf_a_errors returns a FixReport listing what was changed. Inspect it to confirm each fix was applied.
let mut doc = Document::open("noncompliant.pdf")?;
let report = doc.fix_pdf_a_errors(opts)?;
for fix in report.applied_fixes() {
println!("Fixed: {}", fix.description());
}
for skipped in report.skipped_fixes() {
println!("Skipped (manual): {}", skipped.description());
}Confirm no errors remain. Some issues (e.g. non-embeddable fonts) require manual intervention.
let after = doc.validate_pdf_a()?;
if after.is_conformant() {
println!("Document is now PDF/A-2b conformant.");
} else {
println!("Remaining errors: {}", after.error_count());
}Write the fixed file. The output is a full save, not an incremental update.
doc.save("fixed_a2b.pdf")?;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.