use crate::structure::decode_pdf_string;
use spectre_parse::Object as SpObject;
use std::collections::HashMap;
pub fn extract_metadata_impl(pdf_bytes: &[u8]) -> Result<HashMap<String, String>, String> {
let doc = crate::document::open_sp_with_password(pdf_bytes, b"")
.map_err(|e| format!("Failed to load PDF: {e}"))?;
let mut meta = HashMap::new();
meta.insert("pages".to_string(), doc.get_pages().len().to_string());
meta.insert("pdf_version".to_string(), doc.version().to_string());
let Some(SpObject::Reference(info_id)) = doc.trailer().get_optional(b"Info") else {
return Ok(meta);
};
let Ok(info_dict) = doc.get_dictionary(*info_id) else {
return Ok(meta);
};
for (pdf_key, meta_key) in [
("Title", "title"),
("Author", "author"),
("Subject", "subject"),
("Keywords", "keywords"),
("Creator", "creator"),
("Producer", "producer"),
("CreationDate", "creation_date"),
("ModDate", "mod_date"),
] {
if let Some(val) = info_dict.get_optional(pdf_key.as_bytes()) {
if let Some(s) = object_to_string(val) {
meta.insert(meta_key.to_string(), s);
}
}
}
Ok(meta)
}
fn object_to_string(obj: &SpObject) -> Option<String> {
match obj {
SpObject::String(bytes, _) => Some(decode_pdf_string(bytes).trim().to_string()),
SpObject::Name(name) => std::str::from_utf8(name).ok().map(|s| s.to_string()),
SpObject::Integer(n) => Some(n.to_string()),
_ => None,
}
}