use anyhow::{Context, Result};
use crate::cli::args::{PdfaConvertArgs, PdfaValidateArgs};
pub fn pdfa_validate(args: &PdfaValidateArgs) -> Result<()> {
use printwell::pdfa::{IssueSeverity, PdfALevel, validate_pdfa};
let pdf_data = std::fs::read(&args.input)
.with_context(|| format!("Failed to read input file: {}", args.input))?;
let level = PdfALevel::parse_arg(&args.level).ok_or_else(|| {
anyhow::anyhow!(
"Invalid PDF/A level: {}. Use 1b, 1a, 2b, 2u, 2a, 3b, 3u, or 3a",
args.level
)
})?;
let result = validate_pdfa(&pdf_data, level).context("PDF/A validation failed")?;
if args.format.as_str() == "json" {
let json = serde_json::json!({
"level": format!("{}", level),
"is_compliant": result.is_compliant,
"error_count": result.error_count,
"warning_count": result.warning_count,
"issues": result.issues.iter().map(|i| serde_json::json!({
"severity": format!("{:?}", i.severity),
"category": format!("{:?}", i.category),
"message": i.message,
"clause": i.clause,
"page": i.page,
})).collect::<Vec<_>>(),
});
println!(
"{}",
serde_json::to_string_pretty(&json).context("Failed to serialize validation result")?
);
} else {
println!("PDF/A Validation Report");
println!("=======================");
println!("File: {}", args.input);
println!("Target Level: {level}");
println!();
if result.is_compliant {
println!("Result: COMPLIANT");
} else {
println!("Result: NOT COMPLIANT");
}
println!();
println!("Errors: {}", result.error_count);
println!("Warnings: {}", result.warning_count);
if !result.issues.is_empty() {
println!();
println!("Issues:");
for issue in &result.issues {
let severity_marker = match issue.severity {
IssueSeverity::Error => "ERROR",
IssueSeverity::Warning => "WARNING",
IssueSeverity::Info => "INFO",
};
let clause = issue.clause.as_deref().unwrap_or("-");
println!(" [{:7}] [{}] {}", severity_marker, clause, issue.message);
}
}
}
if result.is_compliant {
Ok(())
} else {
anyhow::bail!("PDF is not compliant with {level}")
}
}
pub fn pdfa_convert(args: &PdfaConvertArgs) -> Result<()> {
use printwell::pdfa::{PdfALevel, add_pdfa_metadata};
let pdf_data = std::fs::read(&args.input)
.with_context(|| format!("Failed to read input file: {}", args.input))?;
let level = PdfALevel::parse_arg(&args.level).ok_or_else(|| {
anyhow::anyhow!(
"Invalid PDF/A level: {}. Use 1b, 1a, 2b, 2u, 2a, 3b, 3u, or 3a",
args.level
)
})?;
let result = add_pdfa_metadata(
&pdf_data,
level,
args.title.as_deref(),
args.author.as_deref(),
)
.context("Failed to add PDF/A metadata")?;
std::fs::write(&args.output, &result)
.with_context(|| format!("Failed to write output file: {}", args.output))?;
eprintln!("Added {} metadata, written to: {}", level, args.output);
eprintln!("Note: This adds PDF/A identification metadata. Full PDF/A conversion");
eprintln!(" requires ensuring fonts are embedded, no encryption, etc.");
Ok(())
}