use anyhow::{Context, Result};
use crate::cli::args::{PdfuaConvertArgs, PdfuaValidateArgs};
pub fn pdfua_validate(args: &PdfuaValidateArgs) -> Result<()> {
use printwell::pdfua::{IssueSeverity, PdfUALevel, validate_pdfua};
let pdf_data = std::fs::read(&args.input)
.with_context(|| format!("Failed to read input file: {}", args.input))?;
let level: PdfUALevel = args
.level
.parse()
.with_context(|| format!("Invalid PDF/UA level: {}", args.level))?;
let result = validate_pdfua(&pdf_data, level).context("PDF/UA validation failed")?;
if args.format.as_str() == "json" {
let json = serde_json::json!({
"level": level.to_string(),
"is_compliant": result.is_compliant,
"pages_checked": result.pages_checked,
"tagged_elements": result.tagged_elements,
"issues": result.issues.iter().map(|i| serde_json::json!({
"severity": i.severity.to_string(),
"category": i.category.to_string(),
"description": i.description,
"page": i.page,
"clause": i.clause,
"suggestion": i.suggestion,
})).collect::<Vec<_>>()
});
println!(
"{}",
serde_json::to_string_pretty(&json).context("Failed to serialize validation result")?
);
} else {
eprintln!("PDF/UA Validation Report for: {}", args.input);
eprintln!("Target Level: {level}");
eprintln!("Pages Checked: {}", result.pages_checked);
eprintln!("Tagged Elements Found: {}", result.tagged_elements);
eprintln!();
if result.issues.is_empty() {
eprintln!("No issues found! Document appears PDF/UA compliant.");
} else {
let errors = result
.issues
.iter()
.filter(|i| i.severity == IssueSeverity::Error)
.count();
let warnings = result
.issues
.iter()
.filter(|i| i.severity == IssueSeverity::Warning)
.count();
let infos = result
.issues
.iter()
.filter(|i| i.severity == IssueSeverity::Info)
.count();
eprintln!("Found {errors} errors, {warnings} warnings, {infos} info messages");
eprintln!();
for issue in &result.issues {
let prefix = match issue.severity {
IssueSeverity::Error => "[ERROR] ",
IssueSeverity::Warning => "[WARNING]",
IssueSeverity::Info => "[INFO] ",
};
eprintln!("{} [{}] {}", prefix, issue.category, issue.description);
if let Some(clause) = &issue.clause {
eprintln!(" Clause: {clause}");
}
if let Some(suggestion) = &issue.suggestion {
eprintln!(" Suggestion: {suggestion}");
}
if issue.page > 0 {
eprintln!(" Page: {}", issue.page);
}
}
}
eprintln!();
if result.is_compliant {
eprintln!("Result: COMPLIANT with {level}");
} else {
eprintln!("Result: NOT COMPLIANT with {level}");
}
}
if !result.is_compliant {
anyhow::bail!("PDF is not compliant with {level}")
}
Ok(())
}
pub fn pdfua_convert(args: &PdfuaConvertArgs) -> Result<()> {
use printwell::pdfua::{AccessibilityOptions, PdfUALevel, add_pdfua_metadata};
let pdf_data = std::fs::read(&args.input)
.with_context(|| format!("Failed to read input file: {}", args.input))?;
let level: PdfUALevel = args
.level
.parse()
.with_context(|| format!("Invalid PDF/UA level: {}", args.level))?;
let options = AccessibilityOptions::builder()
.language(args.language.clone())
.title(args.title.clone().unwrap_or_default())
.build();
let result =
add_pdfua_metadata(&pdf_data, level, &options).context("Failed to add PDF/UA 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!("Language: {}", args.language);
eprintln!("Note: This adds PDF/UA identification metadata and accessibility markers.");
eprintln!(" Full PDF/UA compliance requires tagged structure from source HTML.");
Ok(())
}