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)]
1046pub struct AppearanceStreams {
1047 #[pdf(key="N")]
1048 pub normal: MaybeRef<AppearanceStreamEntry>,
1049
1050 #[pdf(key="R")]
1051 pub rollover: Option<MaybeRef<AppearanceStreamEntry>>,
1052
1053 #[pdf(key="D")]
1054 pub down: Option<MaybeRef<AppearanceStreamEntry>>,
1055}
1056
1057#[derive(Clone, Debug, DeepClone)]
1061pub enum AppearanceStreamEntry {
1062 Single(FormXObject),
1063 Dict(HashMap<Name, AppearanceStreamEntry>)
1064}
1065impl Object for AppearanceStreamEntry {
1066 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1067 match p.resolve(resolve)? {
1068 p @ Primitive::Dictionary(_) => Object::from_primitive(p, resolve).map(AppearanceStreamEntry::Dict),
1069 p @ Primitive::Stream(_) => Object::from_primitive(p, resolve).map(AppearanceStreamEntry::Single),
1070 p => Err(PdfError::UnexpectedPrimitive {expected: "Dict or Stream", found: p.get_debug_name()})
1071 }
1072 }
1073}
1074impl ObjectWrite for AppearanceStreamEntry {
1075 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1076 match self {
1077 AppearanceStreamEntry::Dict(d) => d.to_primitive(update),
1078 AppearanceStreamEntry::Single(s) => s.to_primitive(update),
1079 }
1080 }
1081}
1082impl DataSize for AppearanceStreamEntry {
1083 const IS_DYNAMIC: bool = true;
1084 const STATIC_HEAP_SIZE: usize = std::mem::size_of::<Self>();
1085 fn estimate_heap_size(&self) -> usize {
1086 match self {
1087 AppearanceStreamEntry::Dict(d) => d.estimate_heap_size(),
1088 AppearanceStreamEntry::Single(s) => s.estimate_heap_size()
1089 }
1090 }
1091}
1092
1093#[derive(Debug, DataSize, Clone, Object, ObjectWrite, DeepClone)]
1094pub enum Counter {
1095 #[pdf(name="D")]
1096 Arabic,
1097 #[pdf(name="r")]
1098 RomanUpper,
1099 #[pdf(name="R")]
1100 RomanLower,
1101 #[pdf(name="a")]
1102 AlphaUpper,
1103 #[pdf(name="A")]
1104 AlphaLower
1105}
1106
1107#[derive(Debug, DataSize)]
1108pub enum NameTreeNode<T> {
1109 Intermediate (Vec<Ref<NameTree<T>>>),
1111 Leaf (Vec<(PdfString, T)>)
1113
1114}
1115#[derive(Debug, DataSize)]
1118pub struct NameTree<T> {
1119 pub limits: Option<(PdfString, PdfString)>,
1120 pub node: NameTreeNode<T>,
1121}
1122impl<T: Object+DataSize> NameTree<T> {
1123 pub fn walk(&self, r: &impl Resolve, callback: &mut dyn FnMut(&PdfString, &T)) -> Result<(), PdfError> {
1124 match self.node {
1125 NameTreeNode::Leaf(ref items) => {
1126 for (name, val) in items {
1127 callback(name, val);
1128 }
1129 }
1130 NameTreeNode::Intermediate(ref items) => {
1131 for &tree_ref in items {
1132 let tree = r.get(tree_ref)?;
1133 tree.walk(r, callback)?;
1134 }
1135 }
1136 }
1137 Ok(())
1138 }
1139}
1140
1141impl<T: Object> Object for NameTree<T> {
1142 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1143 let mut dict = t!(p.resolve(resolve)?.into_dictionary());
1144
1145 let limits = match dict.remove("Limits") {
1146 Some(limits) => {
1147 let limits = limits.resolve(resolve)?.into_array()?;
1148 if limits.len() != 2 {
1149 bail!("Error reading NameTree: 'Limits' is not of length 2");
1150 }
1151 let min = limits[0].clone().into_string()?;
1152 let max = limits[1].clone().into_string()?;
1153
1154 Some((min, max))
1155 }
1156 None => None
1157 };
1158
1159 let kids = dict.remove("Kids");
1160 let names = dict.remove("Names");
1161 Ok(match (kids, names) {
1163 (Some(kids), _) => {
1164 let kids = t!(kids.resolve(resolve)?.into_array()?.iter().map(|kid|
1165 Ref::<NameTree<T>>::from_primitive(kid.clone(), resolve)
1166 ).collect::<Result<Vec<_>>>());
1167 NameTree {
1168 limits,
1169 node: NameTreeNode::Intermediate (kids)
1170 }
1171 }
1172 (None, Some(names)) => {
1173 let names = names.resolve(resolve)?.into_array()?;
1174 let mut new_names = Vec::new();
1175 for pair in names.chunks_exact(2) {
1176 let name = pair[0].clone().resolve(resolve)?.into_string()?;
1177 let value = t!(T::from_primitive(pair[1].clone(), resolve));
1178 new_names.push((name, value));
1179 }
1180 NameTree {
1181 limits,
1182 node: NameTreeNode::Leaf (new_names),
1183 }
1184 }
1185 (None, None) => {
1186 warn!("Neither Kids nor Names present in NameTree node.");
1187 NameTree {
1188 limits,
1189 node: NameTreeNode::Intermediate(vec![])
1190 }
1191 }
1192 })
1193 }
1194}
1195
1196impl<T: ObjectWrite> ObjectWrite for NameTree<T> {
1197 fn to_primitive(&self, _update: &mut impl Updater) -> Result<Primitive> {
1198 todo!("impl ObjectWrite for NameTree")
1199 }
1200}
1201
1202#[derive(DataSize, Debug)]
1203pub struct NumberTree<T> {
1204 pub limits: Option<(i32, i32)>,
1205 pub node: NumberTreeNode<T>,
1206}
1207
1208#[derive(DataSize, Debug)]
1209pub enum NumberTreeNode<T> {
1210 Leaf(Vec<(i32, T)>),
1211 Intermediate(Vec<Ref<NumberTree<T>>>),
1212}
1213impl<T: Object> Object for NumberTree<T> {
1214 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1215 let mut dict = p.resolve(resolve)?.into_dictionary()?;
1216
1217 let limits = match dict.remove("Limits") {
1218 Some(limits) => {
1219 let limits = t!(limits.resolve(resolve)?.into_array());
1220 if limits.len() != 2 {
1221 bail!("Error reading NameTree: 'Limits' is not of length 2");
1222 }
1223 let min = t!(limits[0].as_integer());
1224 let max = t!(limits[1].as_integer());
1225
1226 Some((min, max))
1227 }
1228 None => None
1229 };
1230
1231 let kids = dict.remove("Kids");
1232 let nums = dict.remove("Nums");
1233 match (kids, nums) {
1234 (Some(kids), _) => {
1235 let kids = t!(kids.resolve(resolve)?.into_array()?.iter().map(|kid|
1236 Ref::<NumberTree<T>>::from_primitive(kid.clone(), resolve)
1237 ).collect::<Result<Vec<_>>>());
1238 Ok(NumberTree {
1239 limits,
1240 node: NumberTreeNode::Intermediate (kids)
1241 })
1242 }
1243 (None, Some(nums)) => {
1244 let list = nums.into_array()?;
1245 let mut items = Vec::with_capacity(list.len() / 2);
1246 for (key, item) in list.into_iter().tuples() {
1247 let idx = t!(key.as_integer());
1248 let val = t!(T::from_primitive(item, resolve));
1249 items.push((idx, val));
1250 }
1251 Ok(NumberTree {
1252 limits,
1253 node: NumberTreeNode::Leaf(items)
1254 })
1255 }
1256 (None, None) => {
1257 warn!("Neither Kids nor Names present in NumberTree node.");
1258 Ok(NumberTree {
1259 limits,
1260 node: NumberTreeNode::Intermediate(vec![])
1261 })
1262 }
1263 }
1264 }
1265}
1266impl<T: ObjectWrite> ObjectWrite for NumberTree<T> {
1267 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1268 let mut dict = Dictionary::new();
1269 if let Some(limits) = self.limits {
1270 dict.insert("Limits", vec![limits.0.into(), limits.1.into()]);
1271 }
1272 match self.node {
1273 NumberTreeNode::Leaf(ref items) => {
1274 let mut nums = Vec::with_capacity(items.len() * 2);
1275 for &(idx, ref label) in items {
1276 nums.push(idx.into());
1277 nums.push(label.to_primitive(update)?);
1278 }
1279 dict.insert("Nums", nums);
1280 }
1281 NumberTreeNode::Intermediate(ref kids) => {
1282 dict.insert("Kids", kids.iter().map(|r| r.get_inner().into()).collect_vec());
1283 }
1284 }
1285 Ok(dict.into())
1286 }
1287}
1288impl<T: Object+DataSize> NumberTree<T> {
1289 pub fn walk(&self, r: &impl Resolve, callback: &mut dyn FnMut(i32, &T)) -> Result<(), PdfError> {
1290 match self.node {
1291 NumberTreeNode::Leaf(ref items) => {
1292 for &(idx, ref val) in items {
1293 callback(idx, val);
1294 }
1295 }
1296 NumberTreeNode::Intermediate(ref items) => {
1297 for &tree_ref in items {
1298 let tree = r.get(tree_ref)?;
1299 tree.walk(r, callback)?;
1300 }
1301 }
1302 }
1303 Ok(())
1304 }
1305}
1306
1307#[derive(Object, ObjectWrite, Clone, DeepClone, Debug)]
1308pub struct LageLabel {
1309 #[pdf(key="S")]
1310 style: Option<Counter>,
1311
1312 #[pdf(key="P")]
1313 prefix: Option<PdfString>,
1314
1315 #[pdf(key="St")]
1316 start: Option<i32>,
1317}
1318
1319#[derive(Debug, Clone, DataSize)]
1320pub enum DestView {
1321 XYZ { left: Option<f32>, top: Option<f32>, zoom: f32 },
1323 Fit,
1324 FitH { top: f32 },
1325 FitV { left: f32 },
1326 FitR(Rectangle),
1327 FitB,
1328 FitBH { top: f32 }
1329}
1330
1331#[derive(Debug, Clone, DataSize)]
1332pub enum MaybeNamedDest {
1333 Named(PdfString),
1334 Direct(Dest),
1335}
1336
1337#[derive(Debug, Clone, DataSize)]
1338pub struct Dest {
1339 pub page: Option<Ref<Page>>,
1340 pub view: DestView
1341}
1342impl Object for Dest {
1343 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1344 let p = match p {
1345 Primitive::Reference(r) => resolve.resolve(r)?,
1346 p => p
1347 };
1348 let p = match p {
1349 Primitive::Dictionary(mut dict) => dict.require("Dest", "D")?,
1350 p => p
1351 };
1352 let array = t!(p.as_array(), p);
1353 Dest::from_array(array, resolve)
1354 }
1355}
1356impl Dest {
1357 fn from_array(array: &[Primitive], resolve: &impl Resolve) -> Result<Self> {
1358 let page = Object::from_primitive(try_opt!(array.get(0)).clone(), resolve)?;
1359 let kind = try_opt!(array.get(1));
1360 let view = match kind.as_name()? {
1361 "XYZ" => DestView::XYZ {
1362 left: match *try_opt!(array.get(2)) {
1363 Primitive::Null => None,
1364 Primitive::Integer(n) => Some(n as f32),
1365 Primitive::Number(f) => Some(f),
1366 ref p => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1367 },
1368 top: match *try_opt!(array.get(3)) {
1369 Primitive::Null => None,
1370 Primitive::Integer(n) => Some(n as f32),
1371 Primitive::Number(f) => Some(f),
1372 ref p => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1373 },
1374 zoom: match array.get(4) {
1375 Some(Primitive::Null) => 0.0,
1376 Some(&Primitive::Integer(n)) => n as f32,
1377 Some(&Primitive::Number(f)) => f,
1378 Some(p) => return Err(PdfError::UnexpectedPrimitive { expected: "Number | Integer | Null", found: p.get_debug_name() }),
1379 None => 0.0,
1380 },
1381 },
1382 "Fit" => DestView::Fit,
1383 "FitH" => DestView::FitH {
1384 top: try_opt!(array.get(2)).as_number()?
1385 },
1386 "FitV" => DestView::FitV {
1387 left: try_opt!(array.get(2)).as_number()?
1388 },
1389 "FitR" => DestView::FitR(Rectangle {
1390 left: try_opt!(array.get(2)).as_number()?,
1391 bottom: try_opt!(array.get(3)).as_number()?,
1392 right: try_opt!(array.get(4)).as_number()?,
1393 top: try_opt!(array.get(5)).as_number()?,
1394 }),
1395 "FitB" => DestView::FitB,
1396 "FitBH" => DestView::FitBH {
1397 top: try_opt!(array.get(2)).as_number()?
1398 },
1399 name => return Err(PdfError::UnknownVariant { id: "Dest", name: name.into() })
1400 };
1401 Ok(Dest {
1402 page,
1403 view
1404 })
1405 }
1406}
1407impl Object for MaybeNamedDest {
1408 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1409 let p = match p {
1410 Primitive::Reference(r) => resolve.resolve(r)?,
1411 p => p
1412 };
1413 let p = match p {
1414 Primitive::Dictionary(mut dict) => dict.require("Dest", "D")?,
1415 Primitive::String(s) => return Ok(MaybeNamedDest::Named(s)),
1416 p => p
1417 };
1418 let array = t!(p.as_array(), p);
1419 Dest::from_array(array, resolve).map(MaybeNamedDest::Direct)
1420 }
1421}
1422impl ObjectWrite for MaybeNamedDest {
1423 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1424 match self {
1425 MaybeNamedDest::Named(s) => Ok(Primitive::String(s.clone())),
1426 MaybeNamedDest::Direct(d) => d.to_primitive(update)
1427 }
1428 }
1429}
1430impl ObjectWrite for Dest {
1431 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1432 let mut arr = vec![self.page.to_primitive(update)?];
1433 match self.view {
1434 DestView::XYZ { left, top, zoom } => {
1435 arr.push(Primitive::Name("XYZ".into()));
1436 arr.push(left.to_primitive(update)?);
1437 arr.push(top.to_primitive(update)?);
1438 arr.push(Primitive::Number(zoom));
1439 }
1440 DestView::Fit => {
1441 arr.push(Primitive::Name("Fit".into()));
1442 }
1443 DestView::FitH { top } => {
1444 arr.push(Primitive::Name("FitH".into()));
1445 arr.push(Primitive::Number(top));
1446 }
1447 DestView::FitV { left } => {
1448 arr.push(Primitive::Name("FitV".into()));
1449 arr.push(Primitive::Number(left));
1450 }
1451 DestView::FitR(rect) => {
1452 arr.push(Primitive::Name("FitR".into()));
1453 arr.push(Primitive::Number(rect.left));
1454 arr.push(Primitive::Number(rect.bottom));
1455 arr.push(Primitive::Number(rect.right));
1456 arr.push(Primitive::Number(rect.top));
1457 }
1458 DestView::FitB => {
1459 arr.push(Primitive::Name("FitB".into()));
1460 }
1461 DestView::FitBH { top } => {
1462 arr.push(Primitive::Name("FitBH".into()));
1463 arr.push(Primitive::Number(top));
1464 }
1465 }
1466 Ok(Primitive::Array(arr))
1467 }
1468}
1469
1470#[derive(Object, ObjectWrite, Debug, DataSize)]
1472pub struct NameDictionary {
1473 #[pdf(key="Pages")]
1474 pub pages: Option<NameTree<Primitive>>,
1475
1476 #[pdf(key="Dests")]
1477 pub dests: Option<NameTree<Option<Dest>>>,
1478
1479 #[pdf(key="AP")]
1480 pub ap: Option<NameTree<Primitive>>,
1481
1482 #[pdf(key="JavaScript")]
1483 pub javascript: Option<NameTree<Primitive>>,
1484
1485 #[pdf(key="Templates")]
1486 pub templates: Option<NameTree<Primitive>>,
1487
1488 #[pdf(key="IDS")]
1489 pub ids: Option<NameTree<Primitive>>,
1490
1491 #[pdf(key="URLS")]
1492 pub urls: Option<NameTree<Primitive>>,
1493
1494 #[pdf(key="EmbeddedFiles")]
1495 pub embedded_files: Option<NameTree<FileSpec>>,
1496 }
1503
1504#[derive(Object, ObjectWrite, Debug, Clone, DataSize, DeepClone)]
1512pub struct FileSpec {
1513 #[pdf(key="EF")]
1514 pub ef: Option<Files<Ref<Stream<EmbeddedFile>>>>,
1515 }
1520
1521#[derive(Object, ObjectWrite, Debug, Clone, DeepClone)]
1523pub struct Files<T> {
1524 #[pdf(key="F")]
1525 pub f: Option<T>,
1526 #[pdf(key="UF")]
1527 pub uf: Option<T>,
1528 #[pdf(key="DOS")]
1529 pub dos: Option<T>,
1530 #[pdf(key="Mac")]
1531 pub mac: Option<T>,
1532 #[pdf(key="Unix")]
1533 pub unix: Option<T>,
1534}
1535impl<T: DataSize> DataSize for Files<T> {
1536 const IS_DYNAMIC: bool = T::IS_DYNAMIC;
1537 const STATIC_HEAP_SIZE: usize = 5 * Option::<T>::STATIC_HEAP_SIZE;
1538
1539 fn estimate_heap_size(&self) -> usize {
1540 self.f.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1541 self.uf.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1542 self.dos.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1543 self.mac.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0) +
1544 self.unix.as_ref().map(|t| t.estimate_heap_size()).unwrap_or(0)
1545 }
1546
1547}
1548
1549#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite)]
1551pub struct EmbeddedFile {
1552 #[pdf(key="Subtype")]
1553 subtype: Option<Name>,
1554
1555 #[pdf(key="Params")]
1556 pub params: Option<EmbeddedFileParamDict>,
1557}
1558
1559#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite)]
1560pub struct EmbeddedFileParamDict {
1561 #[pdf(key="Size")]
1562 pub size: Option<i32>,
1563
1564 #[pdf(key="CreationDate")]
1565 creationdate: Option<Date>,
1566
1567 #[pdf(key="ModDate")]
1568 moddate: Option<Date>,
1569
1570 #[pdf(key="Mac")]
1571 mac: Option<Date>,
1572
1573 #[pdf(key="CheckSum")]
1574 checksum: Option<PdfString>,
1575}
1576
1577#[derive(Object, Debug, Clone, DataSize)]
1578pub struct OutlineItem {
1579 #[pdf(key="Title")]
1580 pub title: Option<PdfString>,
1581
1582 #[pdf(key="Prev")]
1583 pub prev: Option<Ref<OutlineItem>>,
1584
1585 #[pdf(key="Next")]
1586 pub next: Option<Ref<OutlineItem>>,
1587
1588 #[pdf(key="First")]
1589 pub first: Option<Ref<OutlineItem>>,
1590
1591 #[pdf(key="Last")]
1592 pub last: Option<Ref<OutlineItem>>,
1593
1594 #[pdf(key="Count", default="0")]
1595 pub count: i32,
1596
1597 #[pdf(key="Dest")]
1598 pub dest: Option<Primitive>,
1599
1600 #[pdf(key="A")]
1601 pub action: Option<Action>,
1602
1603 #[pdf(key="SE")]
1604 pub se: Option<Dictionary>,
1605
1606 #[pdf(key="C")]
1607 pub color: Option<Vec<f32>>,
1608
1609 #[pdf(key="F")]
1610 pub flags: Option<i32>,
1611}
1612
1613#[derive(Clone, Debug, DataSize)]
1614pub enum Action {
1615 Goto(MaybeNamedDest),
1616 Other(Dictionary)
1617}
1618impl Object for Action {
1619 fn from_primitive(p: Primitive, resolve: &impl Resolve) -> Result<Self> {
1620 let mut d = t!(p.resolve(resolve)?.into_dictionary());
1621 let s = try_opt!(d.get("S")).as_name()?;
1622 match s {
1623 "GoTo" => {
1624 let dest = t!(MaybeNamedDest::from_primitive(try_opt!(d.remove("D")), resolve));
1625 Ok(Action::Goto(dest))
1626 }
1627 _ => Ok(Action::Other(d))
1628 }
1629 }
1630}
1631impl ObjectWrite for Action {
1632 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1633 match self {
1634 Action::Goto(dest) => {
1635 let mut dict = Dictionary::new();
1636 dict.insert("D", dest.to_primitive(update)?);
1637 Ok(Primitive::Dictionary(dict))
1638 }
1639 Action::Other(dict) => Ok(Primitive::Dictionary(dict.clone()))
1640 }
1641 }
1642}
1643
1644#[derive(Object, ObjectWrite, Debug, DataSize)]
1645#[pdf(Type="Outlines?")]
1646pub struct Outlines {
1647 #[pdf(key="Count", default="0")]
1648 pub count: i32,
1649
1650 #[pdf(key="First")]
1651 pub first: Option<Ref<OutlineItem>>,
1652
1653 #[pdf(key="Last")]
1654 pub last: Option<Ref<OutlineItem>>,
1655
1656}
1657
1658#[derive(Debug, Copy, Clone, DataSize, Default)]
1668pub struct Rectangle {
1669 pub left: f32,
1670 pub bottom: f32,
1671 pub right: f32,
1672 pub top: f32,
1673}
1674#[deprecated]
1675pub type Rect = Rectangle;
1676
1677impl Object for Rectangle {
1678 fn from_primitive(p: Primitive, r: &impl Resolve) -> Result<Self> {
1679 let arr = p.resolve(r)?.into_array()?;
1680 if arr.len() != 4 {
1681 bail!("len != 4 {:?}", arr);
1682 }
1683 Ok(Rectangle {
1684 left: arr[0].as_number()?,
1685 bottom: arr[1].as_number()?,
1686 right: arr[2].as_number()?,
1687 top: arr[3].as_number()?
1688 })
1689 }
1690}
1691impl ObjectWrite for Rectangle {
1692 fn to_primitive(&self, update: &mut impl Updater) -> Result<Primitive> {
1693 Primitive::array::<f32, _, _, _>([self.left, self.bottom, self.right, self.top].iter(), update)
1694 }
1695}
1696
1697
1698#[derive(Object, ObjectWrite, Debug, DataSize)]
1701pub struct MarkInformation { #[pdf(key="Marked", default="false")]
1704 pub marked: bool,
1705 #[pdf(key="UserProperties", default="false")]
1707 pub user_properties: bool,
1708 #[pdf(key="Suspects", default="false")]
1710 pub suspects: bool,
1711}
1712
1713#[derive(Object, ObjectWrite, Debug, DataSize)]
1714#[pdf(Type = "StructTreeRoot")]
1715pub struct StructTreeRoot {
1716 #[pdf(key="K")]
1717 pub children: Vec<StructElem>,
1718}
1719#[derive(Object, ObjectWrite, Debug, DataSize)]
1720pub struct StructElem {
1721 #[pdf(key="S")]
1722 pub struct_type: StructType,
1723
1724 #[pdf(key="P")]
1725 pub parent: Ref<StructElem>,
1726
1727 #[pdf(key="ID")]
1728 pub id: Option<PdfString>,
1729
1730 #[pdf(key="Pg")]
1732 pub page: Option<Ref<Page>>,
1733}
1734
1735#[derive(Object, ObjectWrite, Debug, DataSize)]
1736pub enum StructType {
1737 Document,
1738 Part,
1739 Art,
1740 Sect,
1741 Div,
1742 BlockQuote,
1743 Caption,
1744 TOC,
1745 TOCI,
1746 Index,
1747 NonStruct,
1748 Private,
1749 Book,
1750 P,
1751 H,
1752 H1,
1753 H2,
1754 H3,
1755 H4,
1756 H5,
1757 H6,
1758 L,
1759 Ll,
1760 Lbl,
1761 LBody,
1762 Table,
1763 TR,
1764 TH,
1765 TD,
1766 THead,
1767 TBody,
1768 TFoot,
1769 Span,
1770 Quote,
1771 Note,
1772 Reference,
1773 BibEntry,
1774 Code,
1775 Link,
1776 Annot,
1777 Ruby,
1778 RB,
1779 RT,
1780 RP,
1781 Warichu,
1782 WT,
1783 WP,
1784 Figure,
1785 Formula,
1786 Form,
1787 #[pdf(other)]
1788 Other(String),
1789}
1790
1791#[derive(Object, ObjectWrite, Debug, DataSize)]
1792pub enum Trapped {
1793 True,
1794 False,
1795 Unknown,
1796}
1797
1798#[derive(Object, ObjectWrite, Debug, DataSize, Default)]
1799pub struct InfoDict {
1800 #[pdf(key="Title")]
1801 pub title: Option<PdfString>,
1802
1803 #[pdf(key="Author")]
1804 pub author: Option<PdfString>,
1805
1806 #[pdf(key="Subject")]
1807 pub subject: Option<PdfString>,
1808
1809 #[pdf(key="Keywords")]
1810 pub keywords: Option<PdfString>,
1811
1812 #[pdf(key="Creator")]
1813 pub creator: Option<PdfString>,
1814
1815 #[pdf(key="Producer")]
1816 pub producer: Option<PdfString>,
1817
1818 #[pdf(key="CreationDate")]
1819 pub creation_date: Option<Date>,
1820
1821 #[pdf(key="ModDate")]
1822 pub mod_date: Option<Date>,
1823
1824 #[pdf(key="Trapped")]
1825 pub trapped: Option<Trapped>,
1826}
1827
1828#[cfg(test)]
1829mod tests {
1830 use super::*;
1831
1832 #[test]
1833 fn parse_struct_type() {
1834 assert!(matches!(
1835 StructType::from_primitive(Primitive::Name("BibEntry".into()), &NoResolve),
1836 Ok(StructType::BibEntry)
1837 ));
1838
1839 let result =
1840 StructType::from_primitive(Primitive::Name("CustomStructType".into()), &NoResolve);
1841 if let Ok(StructType::Other(name)) = &result {
1842 assert_eq!(name, "CustomStructType");
1843 } else {
1844 panic!("Incorrect result of {:?}", &result);
1845 }
1846 }
1847
1848 #[test]
1849 fn test_field_type() {
1850 assert_eq!(
1851 FieldType::from_primitive(Primitive::Name("Tx".into()), &NoResolve).unwrap(),
1852 FieldType::Text
1853 );
1854 }
1855}