1use std::collections::HashMap;
4use datasize::DataSize;
5
6use crate as pdf;
7use crate::content::deep_clone_op;
8use crate::object::*;
9use crate::error::*;
10use crate::content::{Content, FormXObject, Matrix, parse_ops, serialize_ops, Op};
11use crate::font::Font;
12use crate::enc::StreamFilter;
13
14#[derive(Debug, Clone, DataSize)]
16pub enum PagesNode {
17 Tree(PageTree),
18 Leaf(Page),
19}
20
21impl Object for PagesNode {
22 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<PagesNode> {
23 let mut dict = p.resolve(resolve)?.into_dictionary()?;
24 match dict.require("PagesNode", "Type")?.as_name()? {
25 "Page" => Ok(PagesNode::Leaf(t!(Page::from_dict(dict, resolve)))),
26 "Pages" => Ok(PagesNode::Tree(t!(PageTree::from_dict(dict, resolve)))),
27 other => Err(PdfError::WrongDictionaryType {expected: "Page or Pages".into(), found: other.into()}),
28 }
29 }
30}
31impl ObjectWrite for PagesNode {
32 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
33 match *self {
34 PagesNode::Tree(ref t) => t.to_primitive(update),
35 PagesNode::Leaf(ref l) => l.to_primitive(update),
36 }
37 }
38}
39
40#[derive(Debug, Clone, DataSize)]
57pub struct PageRc(RcRef<PagesNode>);
58impl Deref for PageRc {
59 type Target = Page;
60 fn deref(&self) -> &Page {
61 match *self.0 {
62 PagesNode::Leaf(ref page) => page,
63 _ => unreachable!()
64 }
65 }
66}
67impl PageRc {
68 pub fn create(page: Page, update: &mut impl Updater) -> Result<PageRc> {
69 Ok(PageRc(update.create(PagesNode::Leaf(page))?))
70 }
71 pub fn get_ref(&self) -> Ref<PagesNode> {
72 self.0.get_ref()
73 }
74}
75impl Object for PageRc {
76 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<PageRc> {
77 let node = t!(RcRef::from_primitive(p, resolve));
78 match *node {
79 PagesNode::Tree(_) => Err(PdfError::WrongDictionaryType {expected: "Page".into(), found: "Pages".into()}),
80 PagesNode::Leaf(_) => Ok(PageRc(node))
81 }
82 }
83}
84impl ObjectWrite for PageRc {
85 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
86 self.0.to_primitive(update)
87 }
88}
89
90#[derive(Debug, Clone, DataSize)]
93pub struct PagesRc(RcRef<PagesNode>);
94impl Deref for PagesRc {
95 type Target = PageTree;
96 fn deref(&self) -> &PageTree {
97 match *self.0 {
98 PagesNode::Tree(ref tree) => tree,
99 _ => unreachable!()
100 }
101 }
102}
103impl PagesRc {
104 pub fn create(tree: PageTree, update: &mut impl Updater) -> Result<PagesRc> {
105 Ok(PagesRc(update.create(PagesNode::Tree(tree))?))
106 }
107}
108impl Object for PagesRc {
109 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<PagesRc> {
110 let node = t!(RcRef::from_primitive(p, resolve));
111 match *node {
112 PagesNode::Leaf(_) => Err(PdfError::WrongDictionaryType {expected: "Pages".into(), found: "Page".into()}),
113 PagesNode::Tree(_) => Ok(PagesRc(node))
114 }
115 }
116}
117impl ObjectWrite for PagesRc {
118 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
119 self.0.to_primitive(update)
120 }
121}
122
123#[derive(Object, ObjectWrite, Debug, DataSize)]
124#[pdf(Type = "Catalog?")]
125pub struct Catalog {
126 #[pdf(key="Version")]
127 pub version: Option<Name>,
128
129 #[pdf(key="Pages")]
130 pub pages: PagesRc,
131
132 #[pdf(key="PageLabels")]
133 pub page_labels: Option<NumberTree<PageLabel>>,
134
135 #[pdf(key="Names")]
136 pub names: Option<MaybeRef<NameDictionary>>,
137
138 #[pdf(key="Dests")]
139 pub dests: Option<MaybeRef<Dictionary>>,
140
141#[pdf(key="Outlines")]
146 pub outlines: Option<Outlines>,
147#[pdf(key="AcroForm")]
153 pub forms: Option<InteractiveFormDictionary>,
154
155#[pdf(key="Metadata")]
157 pub metadata: Option<Ref<Stream<()>>>,
158
159 #[pdf(key="StructTreeRoot")]
160 pub struct_tree_root: Option<StructTreeRoot>,
161
162}
174
175#[derive(Object, ObjectWrite, Debug, Default, Clone, DataSize)]
176#[pdf(Type = "Pages?")]
177pub struct PageTree {
178 #[pdf(key="Parent")]
179 pub parent: Option<PagesRc>,
180
181 #[pdf(key="Kids")]
182 pub kids: Vec<Ref<PagesNode>>,
183
184 #[pdf(key="Count")]
185 pub count: u32,
186
187 #[pdf(key="Resources")]
188 pub resources: Option<MaybeRef<Resources>>,
189
190 #[pdf(key="MediaBox")]
191 pub media_box: Option<Rectangle>,
192
193 #[pdf(key="CropBox")]
194 pub crop_box: Option<Rectangle>,
195}
196impl PageTree {
197 pub fn page(&self, resolve: &impl Resolve, page_nr: u32) -> Result<PageRc> {
198 self.page_limited(resolve, page_nr, 16)
199 }
200 fn page_limited(&self, resolve: &impl Resolve, page_nr: u32, depth: usize) -> Result<PageRc> {
201 if depth == 0 {
202 bail!("page tree depth exeeded");
203 }
204 let mut pos = 0;
205 for &kid in &self.kids {
206 let node = resolve.get(kid)?;
207 match *node {
208 PagesNode::Tree(ref tree) => {
209 if (pos .. pos + tree.count).contains(&page_nr) {
210 return tree.page_limited(resolve, page_nr - pos, depth - 1);
211 }
212 pos += tree.count;
213 }
214 PagesNode::Leaf(ref _page) => {
215 if pos == page_nr {
216 return Ok(PageRc(node));
217 }
218 pos += 1;
219 }
220 }
221 }
222 Err(PdfError::PageOutOfBounds {page_nr, max: pos})
223 }
224
225 }
262impl SubType<PagesNode> for PageTree {}
263
264#[derive(Object, ObjectWrite, Debug, Clone, DataSize)]
265#[pdf(Type="Page?")]
266pub struct Page {
267 #[pdf(key="Parent")]
268 pub parent: PagesRc,
269
270 #[pdf(key="Resources", indirect)]
271 pub resources: Option<MaybeRef<Resources>>,
272
273 #[pdf(key="MediaBox")]
274 pub media_box: Option<Rectangle>,
275
276 #[pdf(key="CropBox")]
277 pub crop_box: Option<Rectangle>,
278
279 #[pdf(key="TrimBox")]
280 pub trim_box: Option<Rectangle>,
281
282 #[pdf(key="Contents")]
283 pub contents: Option<Content>,
284
285 #[pdf(key="Rotate", default="0")]
286 pub rotate: i32,
287
288 #[pdf(key="Metadata")]
289 pub metadata: Option<Primitive>,
290
291 #[pdf(key="LGIDict")]
292 pub lgi: Option<Primitive>,
293
294 #[pdf(key="VP")]
295 pub vp: Option<Primitive>,
296
297 #[pdf(key="Annots")]
298 pub annotations: Lazy<Vec<MaybeRef<Annot>>>,
299
300 #[pdf(other)]
301 pub other: Dictionary,
302}
303fn inherit<'a, T: 'a, F>(mut parent: &'a PageTree, f: F) -> Result<Option<T>>
304 where F: Fn(&'a PageTree) -> Option<T>
305{
306 loop {
307 match (&parent.parent, f(parent)) {
308 (_, Some(t)) => return Ok(Some(t)),
309 (Some(ref p), None) => parent = p,
310 (None, None) => return Ok(None)
311 }
312 }
313}
314
315impl Page {
316 pub fn new(parent: PagesRc) -> Page {
317 Page {
318 parent,
319 media_box: None,
320 crop_box: None,
321 trim_box: None,
322 resources: None,
323 contents: None,
324 rotate: 0,
325 metadata: None,
326 lgi: None,
327 vp: None,
328 other: Dictionary::new(),
329 annotations: Default::default(),
330 }
331 }
332 pub fn media_box(&self) -> Result<Rectangle> {
333 match self.media_box {
334 Some(b) => Ok(b),
335 None => inherit(&self.parent, |pt| pt.media_box)?
336 .ok_or_else(|| PdfError::MissingEntry { typ: "Page", field: "MediaBox".into() })
337 }
338 }
339 pub fn crop_box(&self) -> Result<Rectangle> {
340 match self.crop_box {
341 Some(b) => Ok(b),
342 None => match inherit(&self.parent, |pt| pt.crop_box)? {
343 Some(b) => Ok(b),
344 None => self.media_box()
345 }
346 }
347 }
348 pub fn resources(&self) -> Result<&MaybeRef<Resources>> {
349 match self.resources {
350 Some(ref r) => Ok(r),
351 None => inherit(&self.parent, |pt| pt.resources.as_ref())?
352 .ok_or_else(|| PdfError::MissingEntry { typ: "Page", field: "Resources".into() })
353 }
354 }
355}
356impl SubType<PagesNode> for Page {}
357
358
359#[derive(Object, DataSize, Debug, ObjectWrite)]
360pub struct PageLabel {
361 #[pdf(key="S")]
362 pub style: Option<Counter>,
363
364 #[pdf(key="P")]
365 pub prefix: Option<PdfString>,
366
367 #[pdf(key="St")]
368 pub start: Option<usize>
369}
370
371#[derive(Object, ObjectWrite, Debug, DataSize, Default, DeepClone, Clone)]
372pub struct Resources {
373 #[pdf(key="ExtGState")]
374 pub graphics_states: HashMap<Name, GraphicsStateParameters>,
375
376 #[pdf(key="ColorSpace")]
377 pub color_spaces: HashMap<Name, ColorSpace>,
378
379 #[pdf(key="Pattern")]
380 pub pattern: HashMap<Name, Ref<Pattern>>,
381
382 #[pdf(key="XObject")]
384 pub xobjects: HashMap<Name, Ref<XObject>>,
385 #[pdf(key="Font")]
387 pub fonts: HashMap<Name, Lazy<Font>>,
388
389 #[pdf(key="Properties")]
390 pub properties: HashMap<Name, MaybeRef<Dictionary>>,
391}
392
393
394#[derive(Debug, Object, ObjectWrite, DataSize, Clone, DeepClone)]
395pub struct PatternDict {
396 #[pdf(key="PaintType")]
397 pub paint_type: Option<i32>,
398
399 #[pdf(key="TilingType")]
400 pub tiling_type: Option<i32>,
401
402 #[pdf(key="BBox")]
403 pub bbox: Rectangle,
404
405 #[pdf(key="XStep")]
406 pub x_step: f32,
407
408 #[pdf(key="YStep")]
409 pub y_step: f32,
410
411 #[pdf(key="Resources")]
412 pub resources: Ref<Resources>,
413
414 #[pdf(key="Matrix")]
415 pub matrix: Option<Matrix>,
416}
417
418#[derive(Debug, DataSize)]
419pub enum Pattern {
420 Dict(PatternDict),
421 Stream(PatternDict, Vec<Op>),
422}
423impl Pattern {
424 pub fn dict(&self) -> &PatternDict {
425 match *self {
426 Pattern::Dict(ref d) => d,
427 Pattern::Stream(ref d, _) => d,
428 }
429 }
430}
431impl Object for Pattern {
432 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
433 let p = p.resolve(resolve)?;
434 match p {
435 Primitive::Dictionary(dict) => Ok(Pattern::Dict(PatternDict::from_dict(dict, resolve)?)),
436 Primitive::Stream(s) => {
437 let stream: Stream<PatternDict> = Stream::from_stream(s, resolve)?;
438 let data = stream.data(resolve)?;
439 let ops = t!(parse_ops(&data, resolve));
440 let dict = stream.info.info;
441 Ok(Pattern::Stream(dict, ops))
442 }
443 p => Err(PdfError::UnexpectedPrimitive { expected: "Dictionary or Stream", found: p.get_debug_name() })
444 }
445 }
446}
447impl ObjectWrite for Pattern {
448 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
449 match self {
450 Pattern::Dict(ref d) => d.to_primitive(update),
451 Pattern::Stream(ref d, ref ops) => {
452 let data = serialize_ops(ops)?;
453 let stream = Stream::new_with_filters(d.clone(), data, vec![]);
454 stream.to_primitive(update)
455 }
456 }
457 }
458}
459impl DeepClone for Pattern {
460 fn deep_clone(&self, cloner: &mut impl Cloner) -> Result<Self> {
461 match *self {
462 Pattern::Dict(ref d) => Ok(Pattern::Dict(d.deep_clone(cloner)?)),
463 Pattern::Stream(ref dict, ref ops) => {
464 let old_resources = cloner.get(dict.resources)?;
465 let mut resources = Resources::default();
466 let ops: Vec<Op> = ops.iter().map(|op| deep_clone_op(op, cloner, &old_resources, &mut resources)).collect::<Result<Vec<_>>>()?;
467 let dict = PatternDict {
468 resources: cloner.create(resources)?.get_ref(),
469 .. *dict
470 };
471 Ok(Pattern::Stream(dict, ops))
472 }
473 }
474 }
475}
476
477#[derive(Object, ObjectWrite, DeepClone, Debug, DataSize, Copy, Clone)]
478pub enum LineCap {
479 Butt = 0,
480 Round = 1,
481 Square = 2
482}
483#[derive(Object, ObjectWrite, DeepClone, Debug, DataSize, Copy, Clone)]
484pub enum LineJoin {
485 Miter = 0,
486 Round = 1,
487 Bevel = 2
488}
489
490#[derive(Object, ObjectWrite, DeepClone, Debug, DataSize, Clone)]
491#[pdf(Type = "ExtGState?")]
492pub struct GraphicsStateParameters {
494 #[pdf(key="LW")]
495 pub line_width: Option<f32>,
496
497 #[pdf(key="LC")]
498 pub line_cap: Option<LineCap>,
499
500 #[pdf(key="LJ")]
501 pub line_join: Option<LineJoin>,
502
503 #[pdf(key="ML")]
504 pub miter_limit: Option<f32>,
505
506 #[pdf(key="D")]
507 pub dash_pattern: Option<Vec<Primitive>>,
508
509 #[pdf(key="RI")]
510 pub rendering_intent: Option<Name>,
511
512 #[pdf(key="OP")]
513 pub overprint: Option<bool>,
514
515 #[pdf(key="op")]
516 pub overprint_fill: Option<bool>,
517
518 #[pdf(key="OPM")]
519 pub overprint_mode: Option<i32>,
520
521 #[pdf(key="Font")]
522 pub font: Option<(Ref<Font>, f32)>,
523
524 #[pdf(key="BM")]
536 pub blend_mode: Option<Primitive>,
537
538 #[pdf(key="SMask")]
539 pub smask: Option<Primitive>,
540
541
542 #[pdf(key="CA")]
543 pub stroke_alpha: Option<f32>,
544
545 #[pdf(key="ca")]
546 pub fill_alpha: Option<f32>,
547
548 #[pdf(key="AIS")]
549 pub alpha_is_shape: Option<bool>,
550
551 #[pdf(key="TK")]
552 pub text_knockout: Option<bool>,
553
554 #[pdf(other)]
555 _other: Dictionary
556}
557
558#[derive(Object, Debug, DataSize, DeepClone)]
559#[pdf(is_stream)]
560pub enum XObject {
561 #[pdf(name="PS")]
562 Postscript (PostScriptXObject),
563 Image (ImageXObject),
564 Form (FormXObject),
565}
566impl ObjectWrite for XObject {
567 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
568 let (subtype, mut stream) = match self {
569 XObject::Postscript(s) => ("PS", s.to_pdf_stream(update)?),
570 XObject::Form(s) => ("Form", s.stream.to_pdf_stream(update)?),
571 XObject::Image(s) => ("Image", s.inner.to_pdf_stream(update)?),
572 };
573 stream.info.insert("Subtype", Name::from(subtype));
574 stream.info.insert("Type", Name::from("XObject"));
575 Ok(stream.into())
576 }
577}
578
579pub type PostScriptXObject = Stream<PostScriptDict>;
581
582#[derive(Debug, DataSize, Clone, DeepClone)]
583pub struct ImageXObject {
584 pub inner: Stream<ImageDict>
585}
586impl Object for ImageXObject {
587 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
588 let s = PdfStream::from_primitive(p, resolve)?;
589 Self::from_stream(s, resolve)
590 }
591}
592impl ObjectWrite for ImageXObject {
593 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
594 self.inner.to_primitive(update)
595 }
596}
597impl Deref for ImageXObject {
598 type Target = ImageDict;
599 fn deref(&self) -> &ImageDict {
600 &self.inner.info
601 }
602}
603
604pub enum ImageFormat {
605 Raw,
606 Jpeg,
607 Jp2k,
608 Jbig2,
609 CittFax,
610 Png
611}
612
613impl ImageXObject {
614 pub fn from_stream(s: PdfStream, resolve: &impl Resolve) -> Result<Self> {
615 let inner = Stream::from_stream(s, resolve)?;
616 Ok(ImageXObject { inner })
617 }
618
619 pub fn raw_image_data(&self, resolve: &impl Resolve) -> Result<(Arc<[u8]>, Option<&StreamFilter>)> {
621 match self.inner.inner_data {
622 StreamData::Generated(_) => Ok((self.inner.data(resolve)?, None)),
623 StreamData::Original(ref file_range, id) => {
624 let filters = self.inner.filters.as_slice();
625 let end = filters.iter().rposition(|f| match f {
627 StreamFilter::ASCIIHexDecode => false,
628 StreamFilter::ASCII85Decode => false,
629 StreamFilter::LZWDecode(_) => false,
630 StreamFilter::RunLengthDecode => false,
631 StreamFilter::Crypt => true,
632 _ => true
633 }).unwrap_or(filters.len());
634
635 let (normal_filters, image_filters) = filters.split_at(end);
636 let data = resolve.get_data_or_decode(id, file_range.clone(), normal_filters)?;
637
638 match image_filters {
639 [] => Ok((data, None)),
640 [StreamFilter::DCTDecode(_)] |
641 [StreamFilter::CCITTFaxDecode(_)] |
642 [StreamFilter::JPXDecode] |
643 [StreamFilter::FlateDecode(_)] |
644 [StreamFilter::JBIG2Decode(_)] => Ok((data, Some(&image_filters[0]))),
645 _ => bail!("??? filters={:?}", image_filters)
646 }
647 }
648 }
649 }
650
651 pub fn image_data(&self, resolve: &impl Resolve) -> Result<Arc<[u8]>> {
652 let (data, filter) = self.raw_image_data(resolve)?;
653 let filter = match filter {
654 Some(f) => f,
655 None => return Ok(data)
656 };
657 let mut data = match filter {
658 StreamFilter::CCITTFaxDecode(ref params) => {
659 if self.inner.info.width != params.columns {
660 bail!("image width mismatch {} != {}", self.inner.info.width, params.columns);
661 }
662 let mut data = fax_decode(&data, params)?;
663 if params.rows == 0 {
664 data.truncate(self.inner.info.height as usize * self.inner.info.width as usize);
666 }
667 data
668 }
669 StreamFilter::DCTDecode(ref p) => dct_decode(&data, p)?,
670 StreamFilter::JPXDecode => jpx_decode(&data)?,
671 StreamFilter::JBIG2Decode(ref p) => {
672 let global_data = p.globals.as_ref().map(|s| s.data(resolve)).transpose()?;
673 jbig2_decode(&data, global_data.as_deref().unwrap_or_default())?
674 },
675 StreamFilter::FlateDecode(ref p) => flate_decode(&data, p)?,
676 _ => unreachable!()
677 };
678 if let Some(ref decode) = self.decode {
679 if decode == &[1.0, 0.0] && self.bits_per_component == Some(1) {
680 data.iter_mut().for_each(|b| *b = !*b);
681 }
682 }
683 Ok(data.into())
684 }
685}
686
687#[derive(Object, Debug, DataSize, DeepClone, ObjectWrite)]
688#[pdf(Type="XObject", Subtype="PS")]
689pub struct PostScriptDict {
690 #[pdf(other)]
692 pub other: Dictionary
693}
694
695#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite, Default)]
696#[pdf(Type="XObject?", Subtype="Image")]
697pub struct ImageDict {
699 #[pdf(key="Width")]
700 pub width: u32,
701 #[pdf(key="Height")]
702 pub height: u32,
703
704 #[pdf(key="ColorSpace")]
705 pub color_space: Option<ColorSpace>,
706
707 #[pdf(key="BitsPerComponent")]
708 pub bits_per_component: Option<i32>,
709 #[pdf(key="Intent")]
712 pub intent: Option<RenderingIntent>,
713 #[pdf(key="ImageMask", default="false")]
717 pub image_mask: bool,
718
719 #[pdf(key="Mask")]
721 pub mask: Option<Primitive>,
722 #[pdf(key="Decode")]
728 pub decode: Option<Vec<f32>>,
729
730 #[pdf(key="Interpolate", default="false")]
731 pub interpolate: bool,
732
733 #[pdf(key="StructParent")]
739 pub struct_parent: Option<i32>,
740
741 #[pdf(key="ID")]
742 pub id: Option<PdfString>,
743
744 #[pdf(key="SMask")]
745 pub smask: Option<Ref<Stream<ImageDict>>>,
746
747 #[pdf(other)]
752 pub other: Dictionary
753}
754
755
756#[derive(Object, Debug, Copy, Clone, DataSize, DeepClone, ObjectWrite)]
757pub enum RenderingIntent {
758 AbsoluteColorimetric,
759 RelativeColorimetric,
760 Saturation,
761 Perceptual,
762}
763impl RenderingIntent {
764 pub fn from_str(s: &str) -> Option<RenderingIntent> {
765 match s {
766 "AbsoluteColorimetric" => Some(RenderingIntent::AbsoluteColorimetric),
767 "RelativeColorimetric" => Some(RenderingIntent::RelativeColorimetric),
768 "Perceptual" => Some(RenderingIntent::Perceptual),
769 "Saturation" => Some(RenderingIntent::Saturation),
770 _ => None
771 }
772 }
773 pub fn to_str(self) -> &'static str {
774 match self {
775 RenderingIntent::AbsoluteColorimetric => "AbsoluteColorimetric",
776 RenderingIntent::RelativeColorimetric => "RelativeColorimetric",
777 RenderingIntent::Perceptual => "Perceptual",
778 RenderingIntent::Saturation => "Saturation",
779 }
780 }
781}
782
783#[derive(Object, Debug, DataSize, DeepClone, ObjectWrite, Clone, Default)]
784#[pdf(Type="XObject?", Subtype="Form")]
785pub struct FormDict {
786 #[pdf(key="FormType", default="1")]
787 pub form_type: i32,
788
789 #[pdf(key="Name")]
790 pub name: Option<Name>,
791
792 #[pdf(key="LastModified")]
793 pub last_modified: Option<PdfString>,
794
795 #[pdf(key="BBox")]
796 pub bbox: Rectangle,
797
798 #[pdf(key="Matrix")]
799 pub matrix: Option<Primitive>,
800
801 #[pdf(key="Resources")]
802 pub resources: Option<MaybeRef<Resources>>,
803
804 #[pdf(key="Group")]
805 pub group: Option<Dictionary>,
806
807 #[pdf(key="Ref")]
808 pub reference: Option<Dictionary>,
809
810 #[pdf(key="Metadata")]
811 pub metadata: Option<Ref<Stream<()>>>,
812
813 #[pdf(key="PieceInfo")]
814 pub piece_info: Option<Dictionary>,
815
816 #[pdf(key="StructParent")]
817 pub struct_parent: Option<i32>,
818
819 #[pdf(key="StructParents")]
820 pub struct_parents: Option<i32>,
821
822 #[pdf(key="OPI")]
823 pub opi: Option<Dictionary>,
824
825 #[pdf(other)]
826 pub other: Dictionary,
827}
828
829
830#[derive(Object, ObjectWrite, Debug, Clone, DataSize)]
831pub struct InteractiveFormDictionary {
832 #[pdf(key="Fields")]
833 pub fields: Vec<RcRef<FieldDictionary>>,
834
835 #[pdf(key="NeedAppearances", default="false")]
836 pub need_appearences: bool,
837
838 #[pdf(key="SigFlags", default="0")]
839 pub sig_flags: u32,
840
841 #[pdf(key="CO")]
842 pub co: Option<Vec<RcRef<FieldDictionary>>>,
843
844 #[pdf(key="DR")]
845 pub dr: Option<MaybeRef<Resources>>,
846
847 #[pdf(key="DA")]
848 pub da: Option<PdfString>,
849
850 #[pdf(key="Q")]
851 pub q: Option<i32>,
852
853 #[pdf(key="XFA")]
854 pub xfa: Option<Primitive>,
855}
856
857#[derive(Object, ObjectWrite, Debug, Copy, Clone, PartialEq, DataSize)]
858pub enum FieldType {
859 #[pdf(name="Btn")]
860 Button,
861 #[pdf(name="Tx")]
862 Text,
863 #[pdf(name="Ch")]
864 Choice,
865 #[pdf(name="Sig")]
866 Signature,
867 #[pdf(name="SigRef")]
868 SignatureReference,
869}
870
871#[derive(Object, ObjectWrite, Debug)]
872#[pdf(Type="SV")]
873pub struct SeedValueDictionary {
874 #[pdf(key="Ff", default="0")]
875 pub flags: u32,
876 #[pdf(key="Filter")]
877 pub filter: Option<Name>,
878 #[pdf(key="SubFilter")]
879 pub sub_filter: Option<Vec<Name>>,
880 #[pdf(key="V")]
881 pub value: Option<Primitive>,
882 #[pdf(key="DigestMethod")]
883 pub digest_method: Vec<PdfString>,
884 #[pdf(other)]
885 pub other: Dictionary
886}
887
888#[derive(Object, ObjectWrite, Debug)]
889#[pdf(Type="Sig?")]
890pub struct SignatureDictionary {
891 #[pdf(key="Filter")]
892 pub filter: Name,
893 #[pdf(key="SubFilter")]
894 pub sub_filter: Name,
895 #[pdf(key="ByteRange")]
896 pub byte_range: Vec<usize>,
897 #[pdf(key="Contents")]
898 pub contents: PdfString,
899 #[pdf(key="Cert")]
900 pub cert: Vec<PdfString>,
901 #[pdf(key="Reference")]
902 pub reference: Option<Primitive>,
903 #[pdf(key="Name")]
904 pub name: Option<PdfString>,
905 #[pdf(key="M")]
906 pub m: Option<PdfString>,
907 #[pdf(key="Location")]
908 pub location: Option<PdfString>,
909 #[pdf(key="Reason")]
910 pub reason: Option<PdfString>,
911 #[pdf(key="ContactInfo")]
912 pub contact_info: Option<PdfString>,
913 #[pdf(key="V")]
914 pub v: i32,
915 #[pdf(key="R")]
916 pub r: i32,
917 #[pdf(key="Prop_Build")]
918 pub prop_build: Dictionary,
919 #[pdf(key="Prop_AuthTime")]
920 pub prop_auth_time: i32,
921 #[pdf(key="Prop_AuthType")]
922 pub prop_auth_type: Name,
923 #[pdf(other)]
924 pub other: Dictionary
925}
926
927#[derive(Object, ObjectWrite, Debug)]
928#[pdf(Type="SigRef?")]
929pub struct SignatureReferenceDictionary {
930 #[pdf(key="TransformMethod")]
931 pub transform_method: Name,
932 #[pdf(key="TransformParams")]
933 pub transform_params: Option<Dictionary>,
934 #[pdf(key="Data")]
935 pub data: Option<Primitive>,
936 #[pdf(key="DigestMethod")]
937 pub digest_method: Option<Name>,
938 #[pdf(other)]
939 pub other: Dictionary
940}
941
942
943#[derive(Object, ObjectWrite, Debug, Clone, DataSize)]
944#[pdf(Type="Annot?")]
945pub struct Annot {
946 #[pdf(key="Subtype")]
947 pub subtype: Name,
948
949 #[pdf(key="Rect")]
950 pub rect: Option<Rectangle>,
951
952 #[pdf(key="Contents")]
953 pub contents: Option<PdfString>,
954
955 #[pdf(key="P")]
956 pub page: Option<PageRc>,
957
958 #[pdf(key="NM")]
959 pub annotation_name: Option<PdfString>,
960
961 #[pdf(key="M")]
962 pub date: Option<Date>,
963
964 #[pdf(key="F", default="0")]
965 pub annot_flags: u32,
966
967 #[pdf(key="AP")]
968 pub appearance_streams: Option<MaybeRef<AppearanceStreams>>,
969
970 #[pdf(key="AS")]
971 pub appearance_state: Option<Name>,
972
973 #[pdf(key="Border")]
974 pub border: Option<Primitive>,
975
976 #[pdf(key="C")]
977 pub color: Option<Primitive>,
978
979 #[pdf(key="InkList")]
980 pub ink_list: Option<Primitive>,
981
982 #[pdf(other)]
983 pub other: Dictionary,
984}
985
986#[derive(Object, ObjectWrite, Debug, DataSize, Clone)]
987pub struct FieldDictionary {
988 #[pdf(key="FT")]
989 pub typ: Option<FieldType>,
990
991 #[pdf(key="Parent")]
992 pub parent: Option<Ref<FieldDictionary>>,
993
994 #[pdf(key="Kids")]
995 pub kids: Vec<Ref<FieldDictionary>>,
996
997 #[pdf(key="T")]
998 pub name: Option<PdfString>,
999
1000 #[pdf(key="TU")]
1001 pub alt_name: Option<PdfString>,
1002
1003 #[pdf(key="TM")]
1004 pub mapping_name: Option<PdfString>,
1005
1006 #[pdf(key="Ff", default="0")]
1007 pub flags: u32,
1008
1009 #[pdf(key="SigFlags", default="0")]
1010 pub sig_flags: u32,
1011
1012 #[pdf(key="V")]
1013 pub value: Primitive,
1014
1015 #[pdf(key="DV")]
1016 pub default_value: Primitive,
1017
1018 #[pdf(key="DR")]
1019 pub default_resources: Option<MaybeRef<Resources>>,
1020
1021 #[pdf(key="AA")]
1022 pub actions: Option<Dictionary>,
1023
1024 #[pdf(key="Rect")]
1025 pub rect: Option<Rectangle>,
1026
1027 #[pdf(key="MaxLen")]
1028 pub max_len: Option<u32>,
1029
1030 #[pdf(key="Subtype")]
1031 pub subtype: Option<Name>,
1032
1033 #[pdf(other)]
1034 pub other: Dictionary
1035}
1036
1037#[derive(Object, ObjectWrite, Debug, DataSize, Clone, DeepClone)]
1038pub struct AppearanceStreams {
1039 #[pdf(key="N")]
1040 pub normal: Ref<AppearanceStreamEntry>,
1041
1042 #[pdf(key="R")]
1043 pub rollover: Option<Ref<AppearanceStreamEntry>>,
1044
1045 #[pdf(key="D")]
1046 pub down: Option<Ref<AppearanceStreamEntry>>,
1047}
1048
1049#[derive(Clone, Debug, DeepClone)]
1050pub enum AppearanceStreamEntry {
1051 Single(FormXObject),
1052 Dict(HashMap<Name, AppearanceStreamEntry>)
1053}
1054impl Object for AppearanceStreamEntry {
1055 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1056 match p.resolve(resolve)? {
1057 p @ Primitive::Dictionary(_) => Object::from_primitive(p, resolve).map(AppearanceStreamEntry::Dict),
1058 p @ Primitive::Stream(_) => Object::from_primitive(p, resolve).map(AppearanceStreamEntry::Single),
1059 p => Err(PdfError::UnexpectedPrimitive {expected: "Dict or Stream", found: p.get_debug_name()})
1060 }
1061 }
1062}
1063impl ObjectWrite for AppearanceStreamEntry {
1064 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1065 match self {
1066 AppearanceStreamEntry::Dict(d) => d.to_primitive(update),
1067 AppearanceStreamEntry::Single(s) => s.to_primitive(update),
1068 }
1069 }
1070}
1071impl DataSize for AppearanceStreamEntry {
1072 const IS_DYNAMIC: bool = true;
1073 const STATIC_HEAP_SIZE: usize = std::mem::size_of::<Self>();
1074 fn estimate_heap_size(&self) -> usize {
1075 match self {
1076 AppearanceStreamEntry::Dict(d) => d.estimate_heap_size(),
1077 AppearanceStreamEntry::Single(s) => s.estimate_heap_size()
1078 }
1079 }
1080}
1081
1082#[derive(Debug, DataSize, Clone, Object, ObjectWrite, DeepClone)]
1083pub enum Counter {
1084 #[pdf(name="D")]
1085 Arabic,
1086 #[pdf(name="r")]
1087 RomanUpper,
1088 #[pdf(name="R")]
1089 RomanLower,
1090 #[pdf(name="a")]
1091 AlphaUpper,
1092 #[pdf(name="A")]
1093 AlphaLower
1094}
1095
1096#[derive(Debug, DataSize)]
1097pub enum NameTreeNode<T> {
1098 Intermediate (Vec<Ref<NameTree<T>>>),
1100 Leaf (Vec<(PdfString, T)>)
1102
1103}
1104#[derive(Debug, DataSize)]
1107pub struct NameTree<T> {
1108 pub limits: Option<(PdfString, PdfString)>,
1109 pub node: NameTreeNode<T>,
1110}
1111impl<T: Object+DataSize> NameTree<T> {
1112 pub fn walk(&self, r: &impl Resolve, callback: &mut dyn FnMut(&PdfString, &T)) -> Result<(), PdfError> {
1113 match self.node {
1114 NameTreeNode::Leaf(ref items) => {
1115 for (name, val) in items {
1116 callback(name, val);
1117 }
1118 }
1119 NameTreeNode::Intermediate(ref items) => {
1120 for &tree_ref in items {
1121 let tree = r.get(tree_ref)?;
1122 tree.walk(r, callback)?;
1123 }
1124 }
1125 }
1126 Ok(())
1127 }
1128}
1129
1130impl<T: Object> Object for NameTree<T> {
1131 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1132 let mut dict = t!(p.resolve(resolve)?.into_dictionary());
1133
1134 let limits = match dict.remove("Limits") {
1135 Some(limits) => {
1136 let limits = limits.resolve(resolve)?.into_array()?;
1137 if limits.len() != 2 {
1138 bail!("Error reading NameTree: 'Limits' is not of length 2");
1139 }
1140 let min = limits[0].clone().into_string()?;
1141 let max = limits[1].clone().into_string()?;
1142
1143 Some((min, max))
1144 }
1145 None => None
1146 };
1147
1148 let kids = dict.remove("Kids");
1149 let names = dict.remove("Names");
1150 Ok(match (kids, names) {
1152 (Some(kids), _) => {
1153 let kids = t!(kids.resolve(resolve)?.into_array()?.iter().map(|kid|
1154 Ref::<NameTree<T>>::from_primitive(kid.clone(), resolve)
1155 ).collect::<Result<Vec<_>>>());
1156 NameTree {
1157 limits,
1158 node: NameTreeNode::Intermediate (kids)
1159 }
1160 }
1161 (None, Some(names)) => {
1162 let names = names.resolve(resolve)?.into_array()?;
1163 let mut new_names = Vec::new();
1164 for pair in names.chunks_exact(2) {
1165 let name = pair[0].clone().resolve(resolve)?.into_string()?;
1166 let value = t!(T::from_primitive(pair[1].clone(), resolve));
1167 new_names.push((name, value));
1168 }
1169 NameTree {
1170 limits,
1171 node: NameTreeNode::Leaf (new_names),
1172 }
1173 }
1174 (None, None) => {
1175 warn!("Neither Kids nor Names present in NameTree node.");
1176 NameTree {
1177 limits,
1178 node: NameTreeNode::Intermediate(vec![])
1179 }
1180 }
1181 })
1182 }
1183}
1184
1185impl<T: ObjectWrite> ObjectWrite for NameTree<T> {
1186 fn to_primitive(&self, _update: &mut impl Updater) -> Result<Primitive> {
1187 todo!("impl ObjectWrite for NameTree")
1188 }
1189}
1190
1191#[derive(DataSize, Debug)]
1192pub struct NumberTree<T> {
1193 pub limits: Option<(i32, i32)>,
1194 pub node: NumberTreeNode<T>,
1195}
1196
1197#[derive(DataSize, Debug)]
1198pub enum NumberTreeNode<T> {
1199 Leaf(Vec<(i32, T)>),
1200 Intermediate(Vec<Ref<NumberTree<T>>>),
1201}
1202impl<T: Object> Object for NumberTree<T> {
1203 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1204 let mut dict = p.resolve(resolve)?.into_dictionary()?;
1205
1206 let limits = match dict.remove("Limits") {
1207 Some(limits) => {
1208 let limits = t!(limits.resolve(resolve)?.into_array());
1209 if limits.len() != 2 {
1210 bail!("Error reading NameTree: 'Limits' is not of length 2");
1211 }
1212 let min = t!(limits[0].as_integer());
1213 let max = t!(limits[1].as_integer());
1214
1215 Some((min, max))
1216 }
1217 None => None
1218 };
1219
1220 let kids = dict.remove("Kids");
1221 let nums = dict.remove("Nums");
1222 match (kids, nums) {
1223 (Some(kids), _) => {
1224 let kids = t!(kids.resolve(resolve)?.into_array()?.iter().map(|kid|
1225 Ref::<NumberTree<T>>::from_primitive(kid.clone(), resolve)
1226 ).collect::<Result<Vec<_>>>());
1227 Ok(NumberTree {
1228 limits,
1229 node: NumberTreeNode::Intermediate (kids)
1230 })
1231 }
1232 (None, Some(nums)) => {
1233 let list = nums.into_array()?;
1234 let mut items = Vec::with_capacity(list.len() / 2);
1235 for (key, item) in list.into_iter().tuples() {
1236 let idx = t!(key.as_integer());
1237 let val = t!(T::from_primitive(item, resolve));
1238 items.push((idx, val));
1239 }
1240 Ok(NumberTree {
1241 limits,
1242 node: NumberTreeNode::Leaf(items)
1243 })
1244 }
1245 (None, None) => {
1246 warn!("Neither Kids nor Names present in NumberTree node.");
1247 Ok(NumberTree {
1248 limits,
1249 node: NumberTreeNode::Intermediate(vec![])
1250 })
1251 }
1252 }
1253 }
1254}
1255impl<T: ObjectWrite> ObjectWrite for NumberTree<T> {
1256 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1257 let mut dict = Dictionary::new();
1258 if let Some(limits) = self.limits {
1259 dict.insert("Limits", vec![limits.0.into(), limits.1.into()]);
1260 }
1261 match self.node {
1262 NumberTreeNode::Leaf(ref items) => {
1263 let mut nums = Vec::with_capacity(items.len() * 2);
1264 for &(idx, ref label) in items {
1265 nums.push(idx.into());
1266 nums.push(label.to_primitive(update)?);
1267 }
1268 dict.insert("Nums", nums);
1269 }
1270 NumberTreeNode::Intermediate(ref kids) => {
1271 dict.insert("Kids", kids.iter().map(|r| r.get_inner().into()).collect_vec());
1272 }
1273 }
1274 Ok(dict.into())
1275 }
1276}
1277impl<T: Object+DataSize> NumberTree<T> {
1278 pub fn walk(&self, r: &impl Resolve, callback: &mut dyn FnMut(i32, &T)) -> Result<(), PdfError> {
1279 match self.node {
1280 NumberTreeNode::Leaf(ref items) => {
1281 for &(idx, ref val) in items {
1282 callback(idx, val);
1283 }
1284 }
1285 NumberTreeNode::Intermediate(ref items) => {
1286 for &tree_ref in items {
1287 let tree = r.get(tree_ref)?;
1288 tree.walk(r, callback)?;
1289 }
1290 }
1291 }
1292 Ok(())
1293 }
1294}
1295
1296#[derive(Object, ObjectWrite, Clone, DeepClone, Debug)]
1297pub struct LageLabel {
1298 #[pdf(key="S")]
1299 style: Option<Counter>,
1300
1301 #[pdf(key="P")]
1302 prefix: Option<PdfString>,
1303
1304 #[pdf(key="St")]
1305 start: Option<i32>,
1306}
1307
1308#[derive(Debug, Clone, DataSize)]
1309pub enum DestView {
1310 XYZ { left: Option<f32>, top: Option<f32>, zoom: f32 },
1312 Fit,
1313 FitH { top: f32 },
1314 FitV { left: f32 },
1315 FitR(Rectangle),
1316 FitB,
1317 FitBH { top: f32 }
1318}
1319
1320#[derive(Debug, Clone, DataSize)]
1321pub enum MaybeNamedDest {
1322 Named(PdfString),
1323 Direct(Dest),
1324}
1325
1326#[derive(Debug, Clone, DataSize)]
1327pub struct Dest {
1328 pub page: Option<Ref<Page>>,
1329 pub view: DestView
1330}
1331impl Object for Dest {
1332 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1333 let p = match p {
1334 Primitive::Reference(r) => resolve.resolve(r)?,
1335 p => p
1336 };
1337 let p = match p {
1338 Primitive::Dictionary(mut dict) => dict.require("Dest", "D")?,
1339 p => p
1340 };
1341 let array = t!(p.as_array(), p);
1342 Dest::from_array(array, resolve)
1343 }
1344}
1345impl Dest {
1346 fn from_array(array: &[Primitive], resolve: &impl Resolve) -> Result<Self> {
1347 let page = Object::from_primitive(try_opt!(array.get(0)).clone(), resolve)?;
1348 let kind = try_opt!(array.get(1));
1349 let view = match kind.as_name()? {
1350 "XYZ" => DestView::XYZ {
1351 left: match *try_opt!(array.get(2)) {
1352 Primitive::Null => None,
1353 Primitive::Integer(n) => Some(n as f32),
1354 Primitive::Number(f) => Some(f),
1355 ref p => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1356 },
1357 top: match *try_opt!(array.get(3)) {
1358 Primitive::Null => None,
1359 Primitive::Integer(n) => Some(n as f32),
1360 Primitive::Number(f) => Some(f),
1361 ref p => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1362 },
1363 zoom: match array.get(4) {
1364 Some(Primitive::Null) => 0.0,
1365 Some(&Primitive::Integer(n)) => n as f32,
1366 Some(&Primitive::Number(f)) => f,
1367 Some(p) => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1368 None => 0.0,
1369 },
1370 },
1371 "Fit" => DestView::Fit,
1372 "FitH" => DestView::FitH {
1373 top: try_opt!(array.get(2)).as_number()?
1374 },
1375 "FitV" => DestView::FitV {
1376 left: try_opt!(array.get(2)).as_number()?
1377 },
1378 "FitR" => DestView::FitR(Rectangle {
1379 left: try_opt!(array.get(2)).as_number()?,
1380 bottom: try_opt!(array.get(3)).as_number()?,
1381 right: try_opt!(array.get(4)).as_number()?,
1382 top: try_opt!(array.get(5)).as_number()?,
1383 }),
1384 "FitB" => DestView::FitB,
1385 "FitBH" => DestView::FitBH {
1386 top: try_opt!(array.get(2)).as_number()?
1387 },
1388 name => return Err(PdfError::UnknownVariant { id: "Dest", name: name.into() })
1389 };
1390 Ok(Dest {
1391 page,
1392 view
1393 })
1394 }
1395}
1396impl Object for MaybeNamedDest {
1397 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1398 let p = match p {
1399 Primitive::Reference(r) => resolve.resolve(r)?,
1400 p => p
1401 };
1402 let p = match p {
1403 Primitive::Dictionary(mut dict) => dict.require("Dest", "D")?,
1404 Primitive::String(s) => return Ok(MaybeNamedDest::Named(s)),
1405 p => p
1406 };
1407 let array = t!(p.as_array(), p);
1408 Dest::from_array(array, resolve).map(MaybeNamedDest::Direct)
1409 }
1410}
1411impl ObjectWrite for MaybeNamedDest {
1412 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1413 match self {
1414 MaybeNamedDest::Named(s) => Ok(Primitive::String(s.clone())),
1415 MaybeNamedDest::Direct(d) => d.to_primitive(update)
1416 }
1417 }
1418}
1419impl ObjectWrite for Dest {
1420 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1421 let mut arr = vec![self.page.to_primitive(update)?];
1422 match self.view {
1423 DestView::XYZ { left, top, zoom } => {
1424 arr.push(Primitive::Name("XYZ".into()));
1425 arr.push(left.to_primitive(update)?);
1426 arr.push(top.to_primitive(update)?);
1427 arr.push(Primitive::Number(zoom));
1428 }
1429 DestView::Fit => {
1430 arr.push(Primitive::Name("Fit".into()));
1431 }
1432 DestView::FitH { top } => {
1433 arr.push(Primitive::Name("FitH".into()));
1434 arr.push(Primitive::Number(top));
1435 }
1436 DestView::FitV { left } => {
1437 arr.push(Primitive::Name("FitV".into()));
1438 arr.push(Primitive::Number(left));
1439 }
1440 DestView::FitR(rect) => {
1441 arr.push(Primitive::Name("FitR".into()));
1442 arr.push(Primitive::Number(rect.left));
1443 arr.push(Primitive::Number(rect.bottom));
1444 arr.push(Primitive::Number(rect.right));
1445 arr.push(Primitive::Number(rect.top));
1446 }
1447 DestView::FitB => {
1448 arr.push(Primitive::Name("FitB".into()));
1449 }
1450 DestView::FitBH { top } => {
1451 arr.push(Primitive::Name("FitBH".into()));
1452 arr.push(Primitive::Number(top));
1453 }
1454 }
1455 Ok(Primitive::Array(arr))
1456 }
1457}
1458
1459#[derive(Object, ObjectWrite, Debug, DataSize)]
1461pub struct NameDictionary {
1462 #[pdf(key="Pages")]
1463 pub pages: Option<NameTree<Primitive>>,
1464
1465 #[pdf(key="Dests")]
1466 pub dests: Option<NameTree<Option<Dest>>>,
1467
1468 #[pdf(key="AP")]
1469 pub ap: Option<NameTree<Primitive>>,
1470
1471 #[pdf(key="JavaScript")]
1472 pub javascript: Option<NameTree<Primitive>>,
1473
1474 #[pdf(key="Templates")]
1475 pub templates: Option<NameTree<Primitive>>,
1476
1477 #[pdf(key="IDS")]
1478 pub ids: Option<NameTree<Primitive>>,
1479
1480 #[pdf(key="URLS")]
1481 pub urls: Option<NameTree<Primitive>>,
1482
1483 #[pdf(key="EmbeddedFiles")]
1484 pub embedded_files: Option<NameTree<FileSpec>>,
1485 }
1492
1493#[derive(Object, ObjectWrite, Debug, Clone, DataSize, DeepClone)]
1501pub struct FileSpec {
1502 #[pdf(key="EF")]
1503 pub ef: Option<Files<Ref<Stream<EmbeddedFile>>>>,
1504 }
1509
1510#[derive(Object, ObjectWrite, Debug, Clone, DeepClone)]
1512pub struct Files<T> {
1513 #[pdf(key="F")]
1514 pub f: Option<T>,
1515 #[pdf(key="UF")]
1516 pub uf: Option<T>,
1517 #[pdf(key="DOS")]
1518 pub dos: Option<T>,
1519 #[pdf(key="Mac")]
1520 pub mac: Option<T>,
1521 #[pdf(key="Unix")]
1522 pub unix: Option<T>,
1523}
1524impl<T: DataSize> DataSize for Files<T> {
1525 const IS_DYNAMIC: bool = T::IS_DYNAMIC;
1526 const STATIC_HEAP_SIZE: usize = 5 * Option::<T>::STATIC_HEAP_SIZE;
1527
1528 fn estimate_heap_size(&self) -> usize {
1529 self.f.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1530 self.uf.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1531 self.dos.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1532 self.mac.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1533 self.unix.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0)
1534 }
1535
1536}
1537
1538#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite)]
1540pub struct EmbeddedFile {
1541 #[pdf(key="Subtype")]
1542 subtype: Option<Name>,
1543
1544 #[pdf(key="Params")]
1545 pub params: Option<EmbeddedFileParamDict>,
1546}
1547
1548#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite)]
1549pub struct EmbeddedFileParamDict {
1550 #[pdf(key="Size")]
1551 pub size: Option<i32>,
1552
1553 #[pdf(key="CreationDate")]
1554 creationdate: Option<Date>,
1555
1556 #[pdf(key="ModDate")]
1557 moddate: Option<Date>,
1558
1559 #[pdf(key="Mac")]
1560 mac: Option<Date>,
1561
1562 #[pdf(key="CheckSum")]
1563 checksum: Option<PdfString>,
1564}
1565
1566#[derive(Object, Debug, Clone, DataSize)]
1567pub struct OutlineItem {
1568 #[pdf(key="Title")]
1569 pub title: Option<PdfString>,
1570
1571 #[pdf(key="Prev")]
1572 pub prev: Option<Ref<OutlineItem>>,
1573
1574 #[pdf(key="Next")]
1575 pub next: Option<Ref<OutlineItem>>,
1576
1577 #[pdf(key="First")]
1578 pub first: Option<Ref<OutlineItem>>,
1579
1580 #[pdf(key="Last")]
1581 pub last: Option<Ref<OutlineItem>>,
1582
1583 #[pdf(key="Count", default="0")]
1584 pub count: i32,
1585
1586 #[pdf(key="Dest")]
1587 pub dest: Option<Primitive>,
1588
1589 #[pdf(key="A")]
1590 pub action: Option<Action>,
1591
1592 #[pdf(key="SE")]
1593 pub se: Option<Dictionary>,
1594
1595 #[pdf(key="C")]
1596 pub color: Option<Vec<f32>>,
1597
1598 #[pdf(key="F")]
1599 pub flags: Option<i32>,
1600}
1601
1602#[derive(Clone, Debug, DataSize)]
1603pub enum Action {
1604 Goto(MaybeNamedDest),
1605 Other(Dictionary)
1606}
1607impl Object for Action {
1608 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1609 let mut d = t!(p.resolve(resolve)?.into_dictionary());
1610 let s = try_opt!(d.get("S")).as_name()?;
1611 match s {
1612 "GoTo" => {
1613 let dest = t!(MaybeNamedDest::from_primitive(try_opt!(d.remove("D")), resolve));
1614 Ok(Action::Goto(dest))
1615 }
1616 _ => Ok(Action::Other(d))
1617 }
1618 }
1619}
1620impl ObjectWrite for Action {
1621 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1622 match self {
1623 Action::Goto(dest) => {
1624 let mut dict = Dictionary::new();
1625 dict.insert("D", dest.to_primitive(update)?);
1626 Ok(Primitive::Dictionary(dict))
1627 }
1628 Action::Other(dict) => Ok(Primitive::Dictionary(dict.clone()))
1629 }
1630 }
1631}
1632
1633#[derive(Object, ObjectWrite, Debug, DataSize)]
1634#[pdf(Type="Outlines?")]
1635pub struct Outlines {
1636 #[pdf(key="Count", default="0")]
1637 pub count: i32,
1638
1639 #[pdf(key="First")]
1640 pub first: Option<Ref<OutlineItem>>,
1641
1642 #[pdf(key="Last")]
1643 pub last: Option<Ref<OutlineItem>>,
1644
1645}
1646
1647#[derive(Debug, Copy, Clone, DataSize, Default)]
1657pub struct Rectangle {
1658 pub left: f32,
1659 pub bottom: f32,
1660 pub right: f32,
1661 pub top: f32,
1662}
1663#[deprecated]
1664pub type Rect = Rectangle;
1665
1666impl Object for Rectangle {
1667 fn from_primitive(p: Primitive, r: &impl Resolve) -> Result<Self> {
1668 let arr = p.resolve(r)?.into_array()?;
1669 if arr.len() != 4 {
1670 bail!("len != 4 {:?}", arr);
1671 }
1672 Ok(Rectangle {
1673 left: arr[0].as_number()?,
1674 bottom: arr[1].as_number()?,
1675 right: arr[2].as_number()?,
1676 top: arr[3].as_number()?
1677 })
1678 }
1679}
1680impl ObjectWrite for Rectangle {
1681 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1682 Primitive::array::<f32, _, _, _>([self.left, self.bottom, self.right, self.top].iter(), update)
1683 }
1684}
1685
1686
1687#[derive(Object, ObjectWrite, Debug, DataSize)]
1690pub struct MarkInformation { #[pdf(key="Marked", default="false")]
1693 pub marked: bool,
1694 #[pdf(key="UserProperties", default="false")]
1696 pub user_properties: bool,
1697 #[pdf(key="Suspects", default="false")]
1699 pub suspects: bool,
1700}
1701
1702#[derive(Object, ObjectWrite, Debug, DataSize)]
1703#[pdf(Type = "StructTreeRoot")]
1704pub struct StructTreeRoot {
1705 #[pdf(key="K")]
1706 pub children: Vec<StructElem>,
1707}
1708#[derive(Object, ObjectWrite, Debug, DataSize)]
1709pub struct StructElem {
1710 #[pdf(key="S")]
1711 pub struct_type: StructType,
1712
1713 #[pdf(key="P")]
1714 pub parent: Ref<StructElem>,
1715
1716 #[pdf(key="ID")]
1717 pub id: Option<PdfString>,
1718
1719 #[pdf(key="Pg")]
1721 pub page: Option<Ref<Page>>,
1722}
1723
1724#[derive(Object, ObjectWrite, Debug, DataSize)]
1725pub enum StructType {
1726 Document,
1727 Part,
1728 Art,
1729 Sect,
1730 Div,
1731 BlockQuote,
1732 Caption,
1733 TOC,
1734 TOCI,
1735 Index,
1736 NonStruct,
1737 Private,
1738 Book,
1739 P,
1740 H,
1741 H1,
1742 H2,
1743 H3,
1744 H4,
1745 H5,
1746 H6,
1747 L,
1748 Ll,
1749 Lbl,
1750 LBody,
1751 Table,
1752 TR,
1753 TH,
1754 TD,
1755 THead,
1756 TBody,
1757 TFoot,
1758 Span,
1759 Quote,
1760 Note,
1761 Reference,
1762 BibEntry,
1763 Code,
1764 Link,
1765 Annot,
1766 Ruby,
1767 RB,
1768 RT,
1769 RP,
1770 Warichu,
1771 WT,
1772 WP,
1773 Figure,
1774 Formula,
1775 Form,
1776 #[pdf(other)]
1777 Other(String),
1778}
1779
1780#[derive(Object, ObjectWrite, Debug, DataSize)]
1781pub enum Trapped {
1782 True,
1783 False,
1784 Unknown,
1785}
1786
1787#[derive(Object, ObjectWrite, Debug, DataSize, Default)]
1788pub struct InfoDict {
1789 #[pdf(key="Title")]
1790 pub title: Option<PdfString>,
1791
1792 #[pdf(key="Author")]
1793 pub author: Option<PdfString>,
1794
1795 #[pdf(key="Subject")]
1796 pub subject: Option<PdfString>,
1797
1798 #[pdf(key="Keywords")]
1799 pub keywords: Option<PdfString>,
1800
1801 #[pdf(key="Creator")]
1802 pub creator: Option<PdfString>,
1803
1804 #[pdf(key="Producer")]
1805 pub producer: Option<PdfString>,
1806
1807 #[pdf(key="CreationDate")]
1808 pub creation_date: Option<Date>,
1809
1810 #[pdf(key="ModDate")]
1811 pub mod_date: Option<Date>,
1812
1813 #[pdf(key="Trapped")]
1814 pub trapped: Option<Trapped>,
1815}
1816
1817#[cfg(test)]
1818mod tests {
1819 use super::*;
1820
1821 #[test]
1822 fn parse_struct_type() {
1823 assert!(matches!(
1824 StructType::from_primitive(Primitive::Name("BibEntry".into()), &NoResolve),
1825 Ok(StructType::BibEntry)
1826 ));
1827
1828 let result =
1829 StructType::from_primitive(Primitive::Name("CustomStructType".into()), &NoResolve);
1830 if let Ok(StructType::Other(name)) = &result {
1831 assert_eq!(name, "CustomStructType");
1832 } else {
1833 panic!("Incorrect result of {:?}", &result);
1834 }
1835 }
1836
1837 #[test]
1838 fn test_field_type() {
1839 assert_eq!(
1840 FieldType::from_primitive(Primitive::Name("Tx".into()), &NoResolve).unwrap(),
1841 FieldType::Text
1842 );
1843 }
1844}