1extern crate alloc;
4
5use crate::annotation::{self, Annotation};
6use crate::types::LineEnding;
7use pdf_syntax::object::dict::keys::*;
8use pdf_syntax::object::{Array, Dict, Name, Rect, Stream};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum StampName {
13 Approved,
14 Experimental,
15 NotApproved,
16 AsIs,
17 Expired,
18 NotForPublicRelease,
19 Confidential,
20 Final,
21 Sold,
22 Departmental,
23 ForComment,
24 TopSecret,
25 Draft,
26 ForPublicRelease,
27 Custom(alloc::string::String),
29}
30
31impl StampName {
32 pub fn from_name(name: &[u8]) -> Self {
34 match name {
35 b"Approved" => Self::Approved,
36 b"Experimental" => Self::Experimental,
37 b"NotApproved" => Self::NotApproved,
38 b"AsIs" => Self::AsIs,
39 b"Expired" => Self::Expired,
40 b"NotForPublicRelease" => Self::NotForPublicRelease,
41 b"Confidential" => Self::Confidential,
42 b"Final" => Self::Final,
43 b"Sold" => Self::Sold,
44 b"Departmental" => Self::Departmental,
45 b"ForComment" => Self::ForComment,
46 b"TopSecret" => Self::TopSecret,
47 b"Draft" => Self::Draft,
48 b"ForPublicRelease" => Self::ForPublicRelease,
49 other => {
50 let s = core::str::from_utf8(other).unwrap_or("Unknown").to_owned();
51 Self::Custom(s)
52 }
53 }
54 }
55}
56
57#[derive(Debug)]
59pub struct StampAnnotation {
60 pub name: StampName,
62}
63
64impl StampAnnotation {
65 pub fn from_annot(annot: &Annotation<'_>) -> Self {
67 let name = annot
68 .dict()
69 .get::<Name>(NAME)
70 .map(|n: Name| StampName::from_name(n.as_ref()))
71 .unwrap_or(StampName::Draft);
72 Self { name }
73 }
74}
75
76#[derive(Debug)]
78pub struct FileAttachmentAnnotation<'a> {
79 dict: Dict<'a>,
80 pub icon: alloc::string::String,
82}
83
84impl<'a> FileAttachmentAnnotation<'a> {
85 pub fn from_annot(annot: &Annotation<'a>) -> Self {
87 let dict = annot.dict().clone();
88 let icon = dict
89 .get::<Name>(NAME)
90 .map(|n: Name| alloc::string::String::from(n.as_str()))
91 .unwrap_or_else(|| alloc::string::String::from("PushPin"));
92 Self { dict, icon }
93 }
94
95 pub fn file_spec(&self) -> Option<Dict<'a>> {
97 self.dict.get::<Dict<'_>>(FS)
98 }
99
100 pub fn embedded_file(&self) -> Option<Stream<'a>> {
102 let fs = self.file_spec()?;
103 let ef = fs.get::<Dict<'_>>(EF)?;
104 ef.get::<Stream<'_>>(F).or_else(|| ef.get::<Stream<'_>>(UF))
105 }
106
107 pub fn filename(&self) -> Option<alloc::string::String> {
109 let fs = self.file_spec()?;
110 fs.get::<pdf_syntax::object::String>(UF)
111 .or_else(|| fs.get::<pdf_syntax::object::String>(F))
112 .map(|s| annotation::pdf_string_to_string(&s))
113 }
114}
115
116#[derive(Debug)]
118pub struct FreeTextAnnotation {
119 pub default_appearance: alloc::string::String,
121 pub justification: u32,
123 pub default_style: Option<alloc::string::String>,
125 pub rich_content: Option<alloc::string::String>,
127 pub callout_line: Option<Vec<f32>>,
129 pub intent: Option<alloc::string::String>,
131 pub line_ending: LineEnding,
133 pub rd: Option<Rect>,
135}
136
137impl FreeTextAnnotation {
138 pub fn from_annot(annot: &Annotation<'_>) -> Self {
140 let dict = annot.dict();
141 let default_appearance = dict
142 .get::<pdf_syntax::object::String>(DA)
143 .map(|s| annotation::pdf_string_to_string(&s))
144 .unwrap_or_default();
145 let justification = dict.get::<u32>(Q).unwrap_or(0);
146 let default_style = dict
147 .get::<pdf_syntax::object::String>(DS)
148 .map(|s| annotation::pdf_string_to_string(&s));
149 let rich_content = dict
150 .get::<pdf_syntax::object::String>(RC)
151 .map(|s| annotation::pdf_string_to_string(&s));
152 let callout_line: Option<Vec<f32>> = dict
153 .get::<Array<'_>>(CL)
154 .map(|arr: Array<'_>| arr.iter::<f32>().collect());
155 let intent = dict
156 .get::<Name>(IT)
157 .map(|n: Name| alloc::string::String::from(n.as_str()));
158 let line_ending = dict
159 .get::<Name>(LE)
160 .map(|n: Name| LineEnding::from_name(n.as_ref()))
161 .unwrap_or(LineEnding::None);
162 let rd = dict.get::<Rect>(RD);
163 Self {
164 default_appearance,
165 justification,
166 default_style,
167 rich_content,
168 callout_line,
169 intent,
170 line_ending,
171 rd,
172 }
173 }
174}
175
176#[derive(Debug)]
178pub struct SoundAnnotation {
179 pub icon: alloc::string::String,
181}
182
183impl SoundAnnotation {
184 pub fn from_annot(annot: &Annotation<'_>) -> Self {
186 let icon = annot
187 .dict()
188 .get::<Name>(NAME)
189 .map(|n: Name| alloc::string::String::from(n.as_str()))
190 .unwrap_or_else(|| alloc::string::String::from("Speaker"));
191 Self { icon }
192 }
193}
194
195#[derive(Debug)]
197pub struct MovieAnnotation {
198 pub title: Option<alloc::string::String>,
200}
201
202impl MovieAnnotation {
203 pub fn from_annot(annot: &Annotation<'_>) -> Self {
205 let title = annot
206 .dict()
207 .get::<pdf_syntax::object::String>(T)
208 .map(|s| annotation::pdf_string_to_string(&s));
209 Self { title }
210 }
211}