1use std::{borrow::Cow, io};
7
8use crate::{common::Dict, common::Encoding, common::Matrix, common::ObjRef, common::ProcSet, common::Rectangle, encoding::ascii_85_encode, write::Formatter, write::PdfName, common::PdfString, write::Serialize};
9
10#[derive(Debug, Clone)]
12pub enum Destination {
13 PageFitH(ObjRef, usize),
15}
16
17#[derive(Debug, Clone)]
19pub enum Action {
20 GoTo(Destination),
22}
23
24impl Serialize for Destination {
25 fn write(&self, f: &mut Formatter) -> io::Result<()> {
26 match self {
27 Self::PageFitH(r, top) => f
28 .pdf_arr()
29 .entry(r)?
30 .entry(&PdfName("FitH"))?
31 .entry(top)?
32 .finish(),
33 }
34 }
35}
36
37#[derive(Debug, Clone)]
39pub struct Outline {
40 pub first: ObjRef,
42 pub last: ObjRef,
44 pub count: usize,
46}
47
48impl Serialize for Outline {
49 fn write(&self, f: &mut Formatter) -> io::Result<()> {
50 f.pdf_dict()
51 .field("Type", &PdfName("Outline"))?
52 .field("First", &self.first)?
53 .field("Last", &self.last)?
54 .field("Count", &self.count)?
55 .finish()
56 }
57}
58
59#[derive(Debug, Clone)]
61pub struct OutlineItem {
62 pub title: PdfString,
64 pub parent: ObjRef,
66 pub prev: Option<ObjRef>,
68 pub next: Option<ObjRef>,
70 pub first: Option<ObjRef>,
72 pub last: Option<ObjRef>,
74 pub count: usize,
76 pub action: Action,
78}
79
80impl Serialize for OutlineItem {
81 fn write(&self, f: &mut Formatter) -> io::Result<()> {
82 let mut dict = f.pdf_dict();
83 dict.field("Title", &self.title)?
84 .field("Parent", &self.parent)?
85 .opt_field("Prev", &self.prev)?
86 .opt_field("Next", &self.next)?
87 .opt_field("First", &self.first)?
88 .opt_field("Last", &self.last)?
89 .field("Count", &self.count)?;
90 match &self.action {
91 Action::GoTo(dest) => dict.field("Dest", dest),
92 }?;
93 dict.finish()
94 }
95}
96
97pub struct Page<'a> {
99 pub parent: ObjRef,
101 pub contents: ObjRef,
103 pub resources: Resources<'a>,
105 pub media_box: Option<Rectangle<i32>>,
108}
109
110impl Serialize for Page<'_> {
111 fn write(&self, f: &mut Formatter) -> io::Result<()> {
112 f.pdf_dict()
113 .field("Type", &PdfName("Page"))?
114 .field("Parent", &self.parent)?
115 .opt_field("MediaBox", &self.media_box)?
116 .field("Resources", &self.resources)?
117 .field("Contents", &self.contents)?
118 .finish()
119 }
120}
121
122pub enum Resource<T> {
124 Ref(ObjRef),
126 Immediate(T),
128}
129
130impl<T: Serialize> Serialize for Resource<T> {
131 fn write(&self, f: &mut Formatter) -> io::Result<()> {
132 match self {
133 Self::Ref(r) => r.write(f),
134 Self::Immediate(value) => value.write(f),
135 }
136 }
137}
138
139pub struct Type3Font<'a> {
141 pub name: Option<PdfName<'a>>,
143 pub font_bbox: Rectangle<i32>,
145 pub font_matrix: Matrix<f32>,
147 pub first_char: u8,
149 pub last_char: u8,
151 pub encoding: Resource<Encoding<'a>>,
153 pub char_procs: Dict<ObjRef>,
155 pub widths: &'a [u32],
157}
158
159pub enum Font<'a> {
161 Type3(Type3Font<'a>),
163}
164
165impl Serialize for Font<'_> {
166 fn write(&self, f: &mut Formatter) -> io::Result<()> {
167 let mut dict = f.pdf_dict();
168 dict.field("Type", &PdfName("Font"))?;
169 match self {
170 Self::Type3(font) => {
171 dict.field("Subtype", &PdfName("Type3"))?
172 .opt_field("BaseFont", &font.name)?
173 .field("FontBBox", &font.font_bbox)?
174 .field("FontMatrix", &font.font_matrix)?
175 .field("FirstChar", &font.first_char)?
176 .field("LastChar", &font.last_char)?
177 .field("Encoding", &font.encoding)?
178 .field("CharProcs", &font.char_procs)?
179 .arr_field("Widths", &font.widths)?;
180 }
181 }
182 dict.finish()?;
183 Ok(())
184 }
185}
186
187pub struct CharProc<'a>(pub Cow<'a, [u8]>);
189
190impl<'a> Serialize for CharProc<'a> {
191 fn write(&self, f: &mut Formatter) -> io::Result<()> {
192 f.pdf_dict()
193 .field("Length", &self.0.len())?
194 .field("Filter", &PdfName("ASCII85Decode"))?
195 .finish()?;
196 let mut buf = Vec::new();
197 ascii_85_encode(self.0.as_ref(), &mut buf)?;
198 buf.push(10);
199 f.pdf_stream(&buf)?;
200 Ok(())
201 }
202}
203
204pub enum XObject {
206 Image {},
208}
209
210impl Serialize for XObject {
211 fn write(&self, _f: &mut Formatter) -> io::Result<()> {
212 todo!()
213 }
214}
215
216pub type DictResource<T> = Dict<Resource<T>>;
218pub type ResDictRes<T> = Resource<Dict<Resource<T>>>;
220
221pub struct Resources<'a> {
223 pub font: ResDictRes<Font<'a>>,
225 pub x_object: ResDictRes<XObject>,
227 pub proc_set: &'a [ProcSet],
229}
230
231impl Serialize for Resources<'_> {
232 fn write(&self, f: &mut Formatter) -> io::Result<()> {
233 f.pdf_dict()
234 .dict_res_field("Font", &self.font)?
235 .dict_res_field("XObject", &self.x_object)?
236 .arr_field("ProcSet", &self.proc_set)?
237 .finish()
238 }
239}
240
241pub struct Pages {
243 pub kids: Vec<ObjRef>,
245}
246
247impl Serialize for Pages {
248 fn write(&self, f: &mut Formatter) -> io::Result<()> {
249 f.pdf_dict()
250 .field("Type", &PdfName("Pages"))?
251 .field("Count", &self.kids.len())?
252 .field("Kids", &self.kids)?
253 .finish()
254 }
255}
256
257pub struct Stream {
259 pub data: Vec<u8>,
261}
262
263impl Serialize for Stream {
264 fn write(&self, f: &mut Formatter) -> io::Result<()> {
265 f.pdf_dict().field("Length", &self.data.len())?.finish()?;
266 f.pdf_stream(&self.data)?;
267 Ok(())
268 }
269}
270
271pub enum PdfVersion {
273 V1_0,
275 V1_1,
277 V1_2,
279 V1_3,
281 V1_4,
283 V1_5,
285 V1_6,
287 V1_7,
289}
290
291impl Serialize for PdfVersion {
292 fn write(&self, f: &mut Formatter) -> io::Result<()> {
293 match self {
294 Self::V1_0 => PdfName("1.0").write(f),
295 Self::V1_1 => PdfName("1.1").write(f),
296 Self::V1_2 => PdfName("1.2").write(f),
297 Self::V1_3 => PdfName("1.3").write(f),
298 Self::V1_4 => PdfName("1.4").write(f),
299 Self::V1_5 => PdfName("1.5").write(f),
300 Self::V1_6 => PdfName("1.6").write(f),
301 Self::V1_7 => PdfName("1.7").write(f),
302 }
303 }
304}
305
306pub struct Catalog {
308 pub version: Option<PdfVersion>,
310 pub pages: ObjRef,
313 pub page_labels: Option<ObjRef>,
315 pub outline: Option<ObjRef>,
317}
318
319impl Serialize for Catalog {
320 fn write(&self, f: &mut Formatter) -> io::Result<()> {
321 f.pdf_dict()
322 .field("Type", &PdfName("Catalog"))?
323 .opt_field("Version", &self.version)?
324 .field("Pages", &self.pages)?
325 .opt_field("PageLabels", &self.page_labels)?
326 .opt_field("Outlines", &self.outline)?
327 .finish()
328 }
329}
330
331pub struct Trailer {
333 pub size: usize,
335 pub info: Option<ObjRef>,
337 pub root: ObjRef,
339}
340
341impl Serialize for Trailer {
342 fn write(&self, f: &mut Formatter) -> io::Result<()> {
343 f.pdf_dict()
344 .field("Size", &self.size)?
345 .opt_field("Info", &self.info)?
346 .field("Root", &self.root)?
347 .finish()
348 }
349}