flatten_xfa/
flatten_xfa.rs1use std::error::Error;
17use std::path::PathBuf;
18
19fn main() -> Result<(), Box<dyn Error>> {
20 let args: Vec<String> = std::env::args().collect();
21 if args.len() < 3 {
22 eprintln!("usage: flatten_xfa <input.pdf> <output.pdf>");
23 std::process::exit(1);
24 }
25
26 let input = PathBuf::from(&args[1]);
27 let output = PathBuf::from(&args[2]);
28
29 let pdf_bytes =
30 std::fs::read(&input).map_err(|e| format!("failed to read {}: {e}", input.display()))?;
31
32 if pdf_xfa::is_pdf_encrypted(&pdf_bytes) {
34 eprintln!(
35 "SKIP: {} is encrypted — supply a decrypted copy",
36 input.display()
37 );
38 std::process::exit(2);
39 }
40
41 let (flattened, metadata) = pdf_xfa::flatten_xfa_to_pdf_with_metadata(&pdf_bytes)
42 .map_err(|e| format!("flatten failed: {e}"))?;
43
44 std::fs::write(&output, &flattened)
45 .map_err(|e| format!("failed to write {}: {e}", output.display()))?;
46
47 let page_count = count_pages(&flattened).unwrap_or(0);
49
50 println!(
51 "Flattened {} -> {} ({page_count} page{}, quality: {})",
52 input.display(),
53 output.display(),
54 if page_count == 1 { "" } else { "s" },
55 metadata.output_quality.as_str(),
56 );
57
58 Ok(())
59}
60
61fn count_pages(pdf_bytes: &[u8]) -> Option<usize> {
63 let doc = lopdf::Document::load_mem(pdf_bytes).ok()?;
64 Some(doc.page_iter().count())
65}