Skip to main content

pdf_annot/
appearance.rs

1//! Appearance dictionary handling (ISO 32000-2 §12.5.5).
2
3use pdf_syntax::object::dict::keys::*;
4use pdf_syntax::object::{Dict, Name, Stream};
5
6/// Wrapper for an annotation's `/AP` (appearance) dictionary.
7#[derive(Debug, Clone)]
8pub struct AppearanceDict<'a> {
9    dict: Dict<'a>,
10}
11
12impl<'a> AppearanceDict<'a> {
13    /// Try to extract the appearance dictionary from an annotation dict.
14    pub fn from_annot(annot_dict: &Dict<'a>) -> Option<Self> {
15        let dict = annot_dict.get::<Dict<'_>>(AP)?;
16        Some(Self { dict })
17    }
18
19    /// Return the normal appearance stream, resolving `/AS` if needed.
20    pub fn normal(&self, annot_dict: &Dict<'a>) -> Option<Stream<'a>> {
21        resolve_appearance(&self.dict, N, annot_dict)
22    }
23
24    /// Return the rollover appearance stream.
25    pub fn rollover(&self, annot_dict: &Dict<'a>) -> Option<Stream<'a>> {
26        resolve_appearance(&self.dict, R, annot_dict)
27    }
28
29    /// Return the down (mouse-pressed) appearance stream.
30    pub fn down(&self, annot_dict: &Dict<'a>) -> Option<Stream<'a>> {
31        resolve_appearance(&self.dict, D, annot_dict)
32    }
33}
34
35/// Resolve an appearance entry.
36fn resolve_appearance<'a>(
37    ap_dict: &Dict<'a>,
38    key: &[u8],
39    annot_dict: &Dict<'a>,
40) -> Option<Stream<'a>> {
41    if let Some(stream) = ap_dict.get::<Stream<'_>>(key) {
42        return Some(stream);
43    }
44    if let Some(sub_dict) = ap_dict.get::<Dict<'_>>(key) {
45        let appearance_state = annot_dict.get::<Name>(AS)?;
46        return sub_dict.get::<Stream<'_>>(appearance_state.as_ref());
47    }
48    None
49}