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/// Appearance streams for annotations.
1038/// 
1039/// According to PDF specification, appearance stream dictionaries can be either:
1040/// - Direct objects (embedded in the annotation dictionary)
1041/// - Indirect objects (referenced via object reference)
1042/// 
1043/// The `MaybeRef` type allows handling both cases. This is consistent with
1044/// how the PDF specification defines appearance dictionaries in section 12.5.5.
1045#[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/// An appearance stream entry can be either:
1058/// - A single form XObject (stream), or
1059/// - A dictionary of named appearance streams (for widgets with multiple appearance states)
1060#[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    ///
1110    Intermediate (Vec<Ref<NameTree<T>>>),
1111    ///
1112    Leaf (Vec<(PdfString, T)>)
1113
1114}
1115/// Note: The PDF concept of 'root' node is an intermediate or leaf node which has no 'Limits'
1116/// entry. Hence, `limits`, 
1117#[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        // If no `kids`, try `names`. Else there is an error.
1162        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    // left, top, zoom
1322    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/// There is one `NameDictionary` associated with each PDF file.
1471#[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    /*
1497    #[pdf(key="AlternativePresentations")]
1498    alternate_presentations: NameTree<AlternatePresentation>,
1499    #[pdf(key="Renditions")]
1500    renditions: NameTree<Rendition>,
1501    */
1502}
1503
1504/* Embedded file streams can be associated with the document as a whole through
1505 * the EmbeddedFiles entry (PDF 1.4) in the PDF document’s name dictionary
1506 * (see Section 3.6.3, “Name Dictionary”).
1507 * The associated name tree maps name strings to file specifications that refer
1508 * to embedded file streams through their EF entries.
1509*/
1510
1511#[derive(Object, ObjectWrite, Debug, Clone, DataSize, DeepClone)]
1512pub struct FileSpec {
1513    #[pdf(key="EF")]
1514    pub ef: Option<Files<Ref<Stream<EmbeddedFile>>>>,
1515    /*
1516    #[pdf(key="RF")]
1517    rf: Option<Files<RelatedFilesArray>>,
1518    */
1519}
1520
1521/// Used only as elements in `FileSpec`
1522#[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/// PDF Embedded File Stream.
1550#[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/// ISO 32000-2:2020(E) 7.9.5 Rectangles (Pg 134)
1659/// specifying the lower-left x, lower-left y,
1660/// upper-right x, and upper-right y coordinates
1661/// of the rectangle, in that order. The other two
1662/// corners of the rectangle are then assumed to
1663/// have coordinates (ll x , ur y ) and
1664/// (ur x , ll y ).
1665/// Also see Table 74, key BBox definition Pg 221
1666/// defining top, left, bottom, right labeling
1667#[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// Stuff from chapter 10 of the PDF 1.7 ref
1699
1700#[derive(Object, ObjectWrite, Debug, DataSize)]
1701pub struct MarkInformation { // TODO no /Type
1702    /// indicating whether the document conforms to Tagged PDF conventions
1703    #[pdf(key="Marked", default="false")]
1704    pub marked: bool,
1705    /// Indicating the presence of structure elements that contain user properties attributes
1706    #[pdf(key="UserProperties", default="false")]
1707    pub user_properties: bool, 
1708    /// Indicating the presence of tag suspects
1709    #[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    /// `Pg`: A page object representing a page on which some or all of the content items designated by the K entry are rendered.
1731    #[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}