pdf/object/
types.rs

1//! Models of PDF types
2
3use 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/// Node in a page tree - type is either `Page` or `PageTree`
15#[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/*
41use std::iter::once;
42use itertools::Either;
43// needs recursive types
44impl PagesNode {
45    pub fn pages<'a>(&'a self, resolve: &'a impl Resolve) -> impl Iterator<Item=Result<PageRc>> + 'a {
46        match self {
47            PagesNode::Tree(ref tree) => Either::Left(Box::new(tree.pages(resolve))),
48            PagesNode::Leaf(ref page) => Either::Right(once(Ok(PageRc(page.clone()))))
49        }
50    }
51}
52*/
53
54/// A `PagesNode::Leaf` wrapped in a `RcRef`
55/// 
56#[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/// A `PagesNode::Tree` wrapped in a `RcRef`
91/// 
92#[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// ViewerPreferences: dict
142// PageLayout: name
143// PageMode: name
144
145    #[pdf(key="Outlines")]
146    pub outlines: Option<Outlines>,
147// Threads: array
148// OpenAction: array or dict
149// AA: dict
150// URI: dict
151// AcroForm: dict
152    #[pdf(key="AcroForm")]
153    pub forms: Option<InteractiveFormDictionary>,
154
155// Metadata: stream
156    #[pdf(key="Metadata")]
157    pub metadata: Option<Ref<Stream<()>>>,
158
159    #[pdf(key="StructTreeRoot")]
160    pub struct_tree_root: Option<StructTreeRoot>,
161
162// MarkInfo: dict
163// Lang: text string
164// SpiderInfo: dict
165// OutputIntents: array
166// PieceInfo: dict
167// OCProperties: dict
168// Perms: dict
169// Legal: dict
170// Requirements: array
171// Collection: dict
172// NeedsRendering: bool
173}
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    /*
226    pub fn update_pages(&mut self, mut offset: u32, page_nr: u32, page: Page) -> Result<()> {
227        for kid in &self.kids {
228            // println!("{}/{} {:?}", offset, page_nr, kid);
229            match *(self.get(*kid)?) {
230                PagesNode::Tree(ref mut t) => {
231                    if offset + t.count < page_nr {
232                        offset += t.count;
233                    } else {
234                        return self.update_pages(t, offset, page_nr, page);
235                    }
236                },
237                PagesNode::Leaf(ref mut p) => {
238                    if offset < page_nr {
239                        offset += 1;
240                    } else {
241                        assert_eq!(offset, page_nr);
242                        let p = self.storage.create(page)?;
243                        self.storage.update(kid.get_inner(), PagesNode::Leaf(p));
244                        return Ok(());
245                    }
246                }
247            }
248            
249        }
250        Err(PdfError::PageNotFound {page_nr: page_nr})
251    }
252    pub fn pages<'a>(&'a self, resolve: &'a impl Resolve) -> impl Iterator<Item=Result<PageRc>> + 'a {
253        self.kids.iter().flat_map(move |&r| {
254            match resolve.get(r) {
255                Ok(node) => Either::Left(node.pages(resolve)),
256                Err(e) => Either::Right(once(Err(e)))
257            }
258        })
259    }
260    */
261}
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    // shading: Option<Shading>,
383    #[pdf(key="XObject")]
384    pub xobjects: HashMap<Name, Ref<XObject>>,
385    // /XObject is a dictionary that map arbitrary names to XObjects
386    #[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?")]
492/// `ExtGState`
493pub 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    // BG
525    // BG2
526    // UCR
527    // UCR2
528    // TR
529    // TR2
530    // HT
531    // FL
532    // SM
533    // SA
534
535    #[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
579/// A variant of XObject
580pub 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    /// Decode everything except for the final image encoding (jpeg, jbig2, jp2k, ...)
620    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                // decode all non image filters
626                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                    // adjust size
665                    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    // TODO
691    #[pdf(other)]
692    pub other: Dictionary
693}
694
695#[derive(Object, Debug, Clone, DataSize, DeepClone, ObjectWrite, Default)]
696#[pdf(Type="XObject?", Subtype="Image")]
697/// A variant of XObject
698pub 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    // Note: only allowed values are 1, 2, 4, 8, 16. Enum?
710    
711    #[pdf(key="Intent")]
712    pub intent: Option<RenderingIntent>,
713    // Note: default: "the current rendering intent in the graphics state" - I don't think this
714    // ought to have a default then
715
716    #[pdf(key="ImageMask", default="false")]
717    pub image_mask: bool,
718
719    // Mask: stream or array
720    #[pdf(key="Mask")]
721    pub mask: Option<Primitive>,
722    //
723    /// Describes how to map image samples into the range of values appropriate for the image’s color space.
724    /// If `image_mask`: either [0 1] or [1 0]. Else, the length must be twice the number of color
725    /// components required by `color_space` (key ColorSpace)
726    // (see Decode arrays page 344)
727    #[pdf(key="Decode")]
728    pub decode: Option<Vec<f32>>,
729
730    #[pdf(key="Interpolate", default="false")]
731    pub interpolate: bool,
732
733    // Alternates: Vec<AlternateImage>
734
735    // SMask (soft mask): stream
736    // SMaskInData: i32
737    ///The integer key of the image’s entry in the structural parent tree
738    #[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    // OPI: dict
748    // Metadata: stream
749    // OC: dict
750    
751    #[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    ///
1099    Intermediate (Vec<Ref<NameTree<T>>>),
1100    ///
1101    Leaf (Vec<(PdfString, T)>)
1102
1103}
1104/// Note: The PDF concept of 'root' node is an intermediate or leaf node which has no 'Limits'
1105/// entry. Hence, `limits`, 
1106#[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        // If no `kids`, try `names`. Else there is an error.
1151        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    // left, top, zoom
1311    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/// There is one `NameDictionary` associated with each PDF file.
1460#[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    /*
1486    #[pdf(key="AlternativePresentations")]
1487    alternate_presentations: NameTree<AlternatePresentation>,
1488    #[pdf(key="Renditions")]
1489    renditions: NameTree<Rendition>,
1490    */
1491}
1492
1493/* Embedded file streams can be associated with the document as a whole through
1494 * the EmbeddedFiles entry (PDF 1.4) in the PDF document’s name dictionary
1495 * (see Section 3.6.3, “Name Dictionary”).
1496 * The associated name tree maps name strings to file specifications that refer
1497 * to embedded file streams through their EF entries.
1498*/
1499
1500#[derive(Object, ObjectWrite, Debug, Clone, DataSize, DeepClone)]
1501pub struct FileSpec {
1502    #[pdf(key="EF")]
1503    pub ef: Option<Files<Ref<Stream<EmbeddedFile>>>>,
1504    /*
1505    #[pdf(key="RF")]
1506    rf: Option<Files<RelatedFilesArray>>,
1507    */
1508}
1509
1510/// Used only as elements in `FileSpec`
1511#[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/// PDF Embedded File Stream.
1539#[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/// ISO 32000-2:2020(E) 7.9.5 Rectangles (Pg 134)
1648/// specifying the lower-left x, lower-left y,
1649/// upper-right x, and upper-right y coordinates
1650/// of the rectangle, in that order. The other two
1651/// corners of the rectangle are then assumed to
1652/// have coordinates (ll x , ur y ) and
1653/// (ur x , ll y ).
1654/// Also see Table 74, key BBox definition Pg 221
1655/// defining top, left, bottom, right labeling
1656#[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// Stuff from chapter 10 of the PDF 1.7 ref
1688
1689#[derive(Object, ObjectWrite, Debug, DataSize)]
1690pub struct MarkInformation { // TODO no /Type
1691    /// indicating whether the document conforms to Tagged PDF conventions
1692    #[pdf(key="Marked", default="false")]
1693    pub marked: bool,
1694    /// Indicating the presence of structure elements that contain user properties attributes
1695    #[pdf(key="UserProperties", default="false")]
1696    pub user_properties: bool, 
1697    /// Indicating the presence of tag suspects
1698    #[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    /// `Pg`: A page object representing a page on which some or all of the content items designated by the K entry are rendered.
1720    #[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}