#[cfg(feature = "write")]
use lopdf::{Document, Object, ObjectId};
#[cfg(feature = "write")]
use crate::error::AnnotBuildError;
#[cfg(feature = "write")]
enum AnnotsAction {
SetArray(Vec<Object>),
AppendIndirect(ObjectId),
}
#[cfg(feature = "write")]
pub fn add_annotation_to_page(
doc: &mut Document,
page_num: u32,
annot_id: ObjectId,
) -> Result<(), AnnotBuildError> {
let pages = doc.get_pages();
let page_count = pages.len();
let page_id = *pages
.get(&page_num)
.ok_or(AnnotBuildError::PageOutOfRange(page_num, page_count))?;
let annots_action = {
match doc.get_dictionary(page_id) {
Ok(page_dict) => match page_dict.get(b"Annots").ok() {
Some(Object::Array(arr)) => {
let mut new_arr = arr.clone();
new_arr.push(Object::Reference(annot_id));
AnnotsAction::SetArray(new_arr)
}
Some(Object::Reference(r)) => AnnotsAction::AppendIndirect(*r),
_ => AnnotsAction::SetArray(vec![Object::Reference(annot_id)]),
},
Err(_) => AnnotsAction::SetArray(vec![Object::Reference(annot_id)]),
}
};
match annots_action {
AnnotsAction::SetArray(arr) => {
if let Ok(page_dict) = doc.get_dictionary_mut(page_id) {
page_dict.set("Annots", Object::Array(arr));
} else {
return Err(AnnotBuildError::PageMutationFailed);
}
}
AnnotsAction::AppendIndirect(annots_ref) => {
let appended = {
if let Ok(Object::Array(ref mut arr)) = doc.get_object_mut(annots_ref) {
arr.push(Object::Reference(annot_id));
true
} else {
false
}
};
if !appended {
let existing: Vec<Object> = match doc.get_object(annots_ref) {
Ok(Object::Array(ref arr)) => arr.clone(),
_ => Vec::new(),
};
let mut new_annots = existing;
new_annots.push(Object::Reference(annot_id));
if let Ok(page_dict) = doc.get_dictionary_mut(page_id) {
page_dict.set("Annots", Object::Array(new_annots));
} else {
return Err(AnnotBuildError::PageMutationFailed);
}
}
}
}
Ok(())
}