use crate::bbox::BoundingBox;
use crate::error::{Error, Result};
use lopdf::{Document, Object, ObjectId};
pub(crate) fn detect_annotation_bbox(
doc: &Document,
page: &lopdf::Dictionary,
_page_id: ObjectId,
) -> Result<Option<BoundingBox>> {
let annots = match page.get(b"Annots") {
Ok(obj) => obj,
Err(_) => {
return Ok(None);
}
};
let annots_array = match annots {
Object::Array(arr) => arr,
Object::Reference(ref_id) => {
match doc.get_object(*ref_id) {
Ok(Object::Array(arr)) => arr,
Ok(_) => return Err(Error::PdfParse("Annots reference is not an array".into())),
Err(e) => {
return Err(Error::PdfParse(format!(
"Failed to dereference Annots: {}",
e
)))
}
}
}
_ => {
return Err(Error::PdfParse(
"Annots is not an array or reference".into(),
))
}
};
if annots_array.is_empty() {
return Ok(None);
}
let mut min_x = f64::INFINITY;
let mut min_y = f64::INFINITY;
let mut max_x = f64::NEG_INFINITY;
let mut max_y = f64::NEG_INFINITY;
let mut found_any = false;
for annot_ref in annots_array {
let annot_id = match annot_ref {
Object::Reference(id) => id,
_ => continue, };
let annot_dict = match doc.get_object(*annot_id) {
Ok(Object::Dictionary(dict)) => dict,
_ => continue, };
let rect = match annot_dict.get(b"Rect") {
Ok(Object::Array(arr)) => arr,
Ok(Object::Reference(ref_id)) => match doc.get_object(*ref_id) {
Ok(Object::Array(arr)) => arr,
_ => continue,
},
_ => continue, };
if rect.len() != 4 {
continue; }
let x1 = extract_number(&rect[0]).unwrap_or(0.0);
let y1 = extract_number(&rect[1]).unwrap_or(0.0);
let x2 = extract_number(&rect[2]).unwrap_or(0.0);
let y2 = extract_number(&rect[3]).unwrap_or(0.0);
let left = x1.min(x2);
let right = x1.max(x2);
let bottom = y1.min(y2);
let top = y1.max(y2);
min_x = min_x.min(left);
min_y = min_y.min(bottom);
max_x = max_x.max(right);
max_y = max_y.max(top);
found_any = true;
}
if !found_any {
return Ok(None);
}
BoundingBox::new(min_x, min_y, max_x, max_y).map(Some)
}
fn extract_number(obj: &Object) -> Option<f64> {
match obj {
Object::Integer(i) => Some(*i as f64),
Object::Real(f) => Some(*f as f64),
_ => None,
}
}