1use std::io::{Cursor, Write};
2use std::num::NonZeroU16;
3
4use super::*;
5use crate::color::SeparationInfo;
6use crate::object::TextStrLike;
7
8pub struct Catalog<'a> {
12 dict: Dict<'a>,
13}
14
15writer!(Catalog: |obj| {
16 let mut dict = obj.dict();
17 dict.pair(Name(b"Type"), Name(b"Catalog"));
18 Self { dict }
19});
20
21impl Catalog<'_> {
22 pub fn pages(&mut self, id: Ref) -> &mut Self {
24 self.pair(Name(b"Pages"), id);
25 self
26 }
27
28 pub fn page_layout(&mut self, layout: PageLayout) -> &mut Self {
31 self.pair(Name(b"PageLayout"), layout.to_name());
32 self
33 }
34
35 pub fn page_labels(&mut self) -> NumberTree<'_, Ref> {
37 self.insert(Name(b"PageLabels")).start()
38 }
39
40 pub fn page_mode(&mut self, mode: PageMode) -> &mut Self {
43 self.pair(Name(b"PageMode"), mode.to_name());
44 self
45 }
46
47 pub fn viewer_preferences(&mut self) -> ViewerPreferences<'_> {
49 self.insert(Name(b"ViewerPreferences")).start()
50 }
51
52 pub fn names(&mut self) -> Names<'_> {
54 self.insert(Name(b"Names")).start()
55 }
56
57 pub fn destinations(&mut self, id: Ref) -> &mut Self {
60 self.pair(Name(b"Dests"), id);
61 self
62 }
63
64 pub fn outlines(&mut self, id: Ref) -> &mut Self {
67 self.pair(Name(b"Outlines"), id);
68 self
69 }
70
71 pub fn struct_tree_root(&mut self) -> StructTreeRoot<'_> {
76 self.insert(Name(b"StructTreeRoot")).start()
77 }
78
79 pub fn mark_info(&mut self) -> MarkInfo<'_> {
84 self.insert(Name(b"MarkInfo")).start()
85 }
86
87 pub fn lang(&mut self, lang: TextStr) -> &mut Self {
92 self.pair(Name(b"Lang"), lang);
93 self
94 }
95
96 pub fn version(&mut self, major: u8, minor: u8) -> &mut Self {
99 self.pair(Name(b"Version"), Name(format!("{major}.{minor}").as_bytes()));
100 self
101 }
102
103 pub fn additional_actions(&mut self) -> AdditionalActions<'_> {
108 self.insert(Name(b"AA")).start()
109 }
110
111 pub fn form(&mut self) -> Form<'_> {
114 self.insert(Name(b"AcroForm")).start()
115 }
116
117 pub fn metadata(&mut self, id: Ref) -> &mut Self {
122 self.pair(Name(b"Metadata"), id);
123 self
124 }
125
126 pub fn extensions(&mut self) -> TypedDict<'_, DeveloperExtension<'_>> {
132 self.insert(Name(b"Extensions")).dict().typed()
133 }
134
135 pub fn separation_info(&mut self) -> SeparationInfo<'_> {
139 self.insert(Name(b"SeparationInfo")).start()
140 }
141
142 pub fn output_intents(&mut self) -> TypedArray<'_, OutputIntent<'_>> {
150 self.insert(Name(b"OutputIntents")).array().typed()
151 }
152
153 pub fn associated_files(&mut self) -> TypedArray<'_, FileSpec<'_>> {
156 self.insert(Name(b"AF")).array().typed()
157 }
158}
159
160deref!('a, Catalog<'a> => Dict<'a>, dict);
161
162#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
164pub enum PageLayout {
165 #[default]
167 SinglePage,
168 OneColumn,
170 TwoColumnLeft,
173 TwoColumnRight,
176 TwoPageLeft,
179 TwoPageRight,
182}
183
184impl PageLayout {
185 pub(crate) fn to_name(self) -> Name<'static> {
186 match self {
187 Self::SinglePage => Name(b"SinglePage"),
188 Self::OneColumn => Name(b"OneColumn"),
189 Self::TwoColumnLeft => Name(b"TwoColumnLeft"),
190 Self::TwoColumnRight => Name(b"TwoColumnRight"),
191 Self::TwoPageLeft => Name(b"TwoPageLeft"),
192 Self::TwoPageRight => Name(b"TwoPageRight"),
193 }
194 }
195}
196
197#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
200pub enum PageMode {
201 #[default]
204 UseNone,
205 UseOutlines,
207 UseThumbs,
209 FullScreen,
211 UseOC,
213 UseAttachments,
215}
216
217impl PageMode {
218 pub(crate) fn to_name(self) -> Name<'static> {
219 match self {
220 Self::UseNone => Name(b"UseNone"),
221 Self::UseOutlines => Name(b"UseOutlines"),
222 Self::UseThumbs => Name(b"UseThumbs"),
223 Self::FullScreen => Name(b"FullScreen"),
224 Self::UseOC => Name(b"UseOC"),
225 Self::UseAttachments => Name(b"UseAttachments"),
226 }
227 }
228}
229
230pub struct DeveloperExtension<'a> {
234 dict: Dict<'a>,
235}
236
237writer!(DeveloperExtension: |obj| {
238 let mut dict = obj.dict();
239 dict.pair(Name(b"Type"), Name(b"DeveloperExtensions"));
240 Self { dict }
241});
242
243impl DeveloperExtension<'_> {
244 pub fn base_version(&mut self, major: u8, minor: u8) -> &mut Self {
247 self.pair(Name(b"BaseVersion"), Name(format!("{major}.{minor}").as_bytes()));
248 self
249 }
250
251 pub fn extension_level(&mut self, level: i32) -> &mut Self {
254 self.pair(Name(b"ExtensionLevel"), level);
255 self
256 }
257}
258
259deref!('a, DeveloperExtension<'a> => Dict<'a>, dict);
260
261pub struct ViewerPreferences<'a> {
265 dict: Dict<'a>,
266}
267
268writer!(ViewerPreferences: |obj| Self { dict: obj.dict() });
269
270impl ViewerPreferences<'_> {
271 pub fn hide_toolbar(&mut self, hide: bool) -> &mut Self {
274 self.pair(Name(b"HideToolbar"), hide);
275 self
276 }
277
278 pub fn hide_menubar(&mut self, hide: bool) -> &mut Self {
281 self.pair(Name(b"HideMenubar"), hide);
282 self
283 }
284
285 pub fn fit_window(&mut self, fit: bool) -> &mut Self {
288 self.pair(Name(b"FitWindow"), fit);
289 self
290 }
291
292 pub fn center_window(&mut self, center: bool) -> &mut Self {
295 self.pair(Name(b"CenterWindow"), center);
296 self
297 }
298
299 pub fn display_doc_title(&mut self, display: bool) -> &mut Self {
303 self.pair(Name(b"DisplayDocTitle"), display);
304 self
305 }
306
307 pub fn non_full_screen_page_mode(&mut self, mode: PageMode) -> &mut Self {
314 assert!(mode != PageMode::FullScreen, "mode must not full screen");
315 self.pair(Name(b"NonFullScreenPageMode"), mode.to_name());
316 self
317 }
318
319 pub fn direction(&mut self, dir: Direction) -> &mut Self {
322 self.pair(Name(b"Direction"), dir.to_name());
323 self
324 }
325}
326
327deref!('a, ViewerPreferences<'a> => Dict<'a>, dict);
328
329pub struct StructTreeRoot<'a> {
333 dict: Dict<'a>,
334}
335
336writer!(StructTreeRoot: |obj| {
337 let mut dict = obj.dict();
338 dict.pair(Name(b"Type"), Name(b"StructTreeRoot"));
339 Self { dict }
340});
341
342impl StructTreeRoot<'_> {
343 pub fn child(&mut self, id: Ref) -> &mut Self {
346 self.dict.pair(Name(b"K"), id);
347 self
348 }
349
350 pub fn children(&mut self) -> TypedArray<'_, Ref> {
353 self.dict.insert(Name(b"K")).array().typed()
354 }
355
356 pub fn id_tree(&mut self) -> NameTree<'_, Ref> {
360 self.dict.insert(Name(b"IDTree")).start()
361 }
362
363 pub fn parent_tree(&mut self) -> NumberTree<'_, Ref> {
367 self.dict.insert(Name(b"ParentTree")).start()
368 }
369
370 pub fn parent_tree_next_key(&mut self, key: i32) -> &mut Self {
373 self.dict.pair(Name(b"ParentTreeNextKey"), key);
374 self
375 }
376
377 pub fn role_map(&mut self) -> RoleMap<'_> {
384 self.dict.insert(Name(b"RoleMap")).start()
385 }
386
387 pub fn class_map(&mut self) -> ClassMap<'_> {
391 self.dict.insert(Name(b"ClassMap")).start()
392 }
393
394 pub fn namespaces(&mut self) -> TypedArray<'_, Ref> {
399 self.dict.insert(Name(b"Namespaces")).array().typed()
400 }
401
402 pub fn pronunciation_lexicon(&mut self) -> TypedArray<'_, Ref> {
409 self.dict.insert(Name(b"PronunciationLexicon")).array().typed()
410 }
411
412 pub fn associated_files(&mut self) -> TypedArray<'_, FileSpec<'_>> {
415 self.dict.insert(Name(b"AF")).array().typed()
416 }
417}
418
419deref!('a, StructTreeRoot<'a> => Dict<'a>, dict);
420
421pub struct StructElement<'a> {
423 dict: Dict<'a>,
424}
425
426writer!(StructElement: |obj| {
427 let mut dict = obj.dict();
428 dict.pair(Name(b"Type"), Name(b"StructElem"));
429 Self { dict }
430});
431
432impl StructElement<'_> {
433 pub fn kind(&mut self, role: StructRole) -> &mut Self {
438 self.dict.pair(Name(b"S"), role.to_name());
439 self
440 }
441
442 pub fn kind_2(&mut self, role: StructRole2, pdf_2_ns: Ref) -> &mut Self {
451 self.dict.pair(Name(b"S"), role.to_name(&mut [0; 6]));
452 self.namespace(pdf_2_ns)
453 }
454
455 pub fn custom_kind(&mut self, name: Name) -> &mut Self {
465 self.dict.pair(Name(b"S"), name);
466 self
467 }
468
469 pub fn parent(&mut self, parent: Ref) -> &mut Self {
472 self.dict.pair(Name(b"P"), parent);
473 self
474 }
475
476 pub fn id(&mut self, id: Str) -> &mut Self {
479 self.dict.pair(Name(b"ID"), id);
480 self
481 }
482
483 pub fn refs(&mut self, refs: impl IntoIterator<Item = Ref>) -> &mut Self {
489 self.dict.insert(Name(b"Ref")).array().typed().items(refs);
490 self
491 }
492
493 pub fn page(&mut self, page: Ref) -> &mut Self {
496 self.dict.pair(Name(b"Pg"), page);
497 self
498 }
499
500 pub fn child(&mut self, id: Ref) -> &mut Self {
503 self.dict.pair(Name(b"K"), id);
504 self
505 }
506
507 pub fn marked_content_child(&mut self) -> MarkedRef<'_> {
510 self.dict.insert(Name(b"K")).start()
511 }
512
513 pub fn object_child(&mut self) -> ObjectRef<'_> {
516 self.dict.insert(Name(b"K")).start()
517 }
518
519 pub fn children(&mut self) -> StructChildren<'_> {
522 self.dict.insert(Name(b"K")).start()
523 }
524
525 pub fn attributes(&mut self) -> TypedArray<'_, Attributes<'_>> {
528 self.dict.insert(Name(b"A")).array().typed()
529 }
530
531 pub fn attribute_class(&mut self) -> TypedArray<'_, Name<'_>> {
534 self.dict.insert(Name(b"C")).array().typed()
535 }
536
537 pub fn revision(&mut self, revision: i32) -> &mut Self {
539 self.dict.pair(Name(b"R"), revision);
540 self
541 }
542
543 pub fn title(&mut self, title: impl TextStrLike) -> &mut Self {
545 self.dict.pair(Name(b"T"), title);
546 self
547 }
548
549 pub fn lang(&mut self, lang: TextStr) -> &mut Self {
551 self.dict.pair(Name(b"Lang"), lang);
552 self
553 }
554
555 pub fn alt(&mut self, alt: impl TextStrLike) -> &mut Self {
558 self.dict.pair(Name(b"Alt"), alt);
559 self
560 }
561
562 pub fn expanded(&mut self, expanded: impl TextStrLike) -> &mut Self {
565 self.dict.pair(Name(b"E"), expanded);
566 self
567 }
568
569 pub fn actual_text(&mut self, actual_text: impl TextStrLike) -> &mut Self {
572 self.dict.pair(Name(b"ActualText"), actual_text);
573 self
574 }
575
576 pub fn associated_files(&mut self) -> TypedArray<'_, FileSpec<'_>> {
579 self.insert(Name(b"AF")).array().typed()
580 }
581
582 pub fn namespace(&mut self, ns: Ref) -> &mut Self {
585 self.dict.pair(Name(b"NS"), ns);
586 self
587 }
588
589 pub fn phonetic_alphabet(&mut self, alphabet: PhoneticAlphabet) -> &mut Self {
592 self.dict.pair(Name(b"PhoneticAlphabet"), alphabet.to_name());
593 self
594 }
595
596 pub fn phoneme(&mut self, phoneme: TextStr) -> &mut Self {
599 self.dict.pair(Name(b"Phoneme"), phoneme);
600 self
601 }
602}
603
604deref!('a, StructElement<'a> => Dict<'a>, dict);
605
606pub struct StructChildren<'a> {
610 arr: Array<'a>,
611}
612
613writer!(StructChildren: |obj| Self { arr: obj.array() });
614
615impl StructChildren<'_> {
616 pub fn struct_element(&mut self, id: Ref) -> &mut Self {
618 self.arr.item(id);
619 self
620 }
621
622 pub fn marked_content_id(&mut self, id: i32) -> &mut Self {
624 self.arr.item(id);
625 self
626 }
627
628 pub fn marked_content_ref(&mut self) -> MarkedRef<'_> {
630 self.arr.push().start()
631 }
632
633 pub fn object_ref(&mut self) -> ObjectRef<'_> {
635 self.arr.push().start()
636 }
637}
638
639deref!('a, StructChildren<'a> => Array<'a>, arr);
640
641pub struct MarkedRef<'a> {
646 dict: Dict<'a>,
647}
648
649writer!(MarkedRef: |obj| {
650 let mut dict = obj.dict();
651 dict.pair(Name(b"Type"), Name(b"MCR"));
652 Self { dict }
653});
654
655impl MarkedRef<'_> {
656 pub fn page(&mut self, page: Ref) -> &mut Self {
659 self.dict.pair(Name(b"Pg"), page);
660 self
661 }
662
663 pub fn stream(&mut self, stream: Ref) -> &mut Self {
668 self.dict.pair(Name(b"Stm"), stream);
669 self
670 }
671
672 pub fn stream_owner(&mut self, owner: Ref) -> &mut Self {
675 self.dict.pair(Name(b"StmOwn"), owner);
676 self
677 }
678
679 pub fn marked_content_id(&mut self, id: i32) -> &mut Self {
682 self.dict.pair(Name(b"MCID"), id);
683 self
684 }
685}
686
687deref!('a, MarkedRef<'a> => Dict<'a>, dict);
688
689pub struct ObjectRef<'a> {
693 dict: Dict<'a>,
694}
695
696writer!(ObjectRef: |obj| {
697 let mut dict = obj.dict();
698 dict.pair(Name(b"Type"), Name(b"OBJR"));
699 Self { dict }
700});
701
702impl ObjectRef<'_> {
703 pub fn page(&mut self, page: Ref) -> &mut Self {
706 self.dict.pair(Name(b"Pg"), page);
707 self
708 }
709
710 pub fn object(&mut self, obj: Ref) -> &mut Self {
712 self.dict.pair(Name(b"Obj"), obj);
713 self
714 }
715}
716
717deref!('a, ObjectRef<'a> => Dict<'a>, dict);
718
719pub struct RoleMap<'a> {
726 dict: TypedDict<'a, Name<'a>>,
727}
728
729writer!(RoleMap: |obj| Self { dict: obj.dict().typed() });
730
731impl RoleMap<'_> {
732 pub fn insert(&mut self, name: Name, role: StructRole) -> &mut Self {
734 self.dict.pair(name, role.to_name());
735 self
736 }
737}
738
739deref!('a, RoleMap<'a> => TypedDict<'a, Name<'a>>, dict);
740
741pub struct ClassMap<'a> {
745 dict: Dict<'a>,
746}
747
748writer!(ClassMap: |obj| Self { dict: obj.dict() });
749
750impl ClassMap<'_> {
751 pub fn single(&mut self, name: Name) -> Attributes<'_> {
753 self.dict.insert(name).start()
754 }
755
756 pub fn multiple(&mut self, name: Name) -> TypedArray<'_, Attributes<'_>> {
758 self.dict.insert(name).array().typed()
759 }
760}
761
762deref!('a, ClassMap<'a> => Dict<'a>, dict);
763
764#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
771pub enum StructRole {
772 Document,
774 Part,
776 Art,
778 Sect,
780 Div,
782 BlockQuote,
784 Caption,
786 TOC,
788 TOCI,
790 Index,
792 NonStruct,
794 Private,
796 P,
798 StructuredHeading,
800 H1,
802 H2,
804 H3,
806 H4,
808 H5,
810 H6,
812 L,
814 LI,
816 Lbl,
818 LBody,
820 Table,
822 TR,
824 TH,
826 TD,
828 THead,
830 TBody,
832 TFoot,
834 Span,
836 Quote,
838 Note,
840 Reference,
842 BibEntry,
844 Code,
846 Link,
848 Annot,
851 Ruby,
853 Warichu,
855 RB,
857 RT,
859 RP,
861 WT,
863 WP,
865 Figure,
867 Formula,
869 Form,
871}
872
873impl StructRole {
874 pub fn to_name(self) -> Name<'static> {
876 match self {
877 Self::Document => Name(b"Document"),
878 Self::Part => Name(b"Part"),
879 Self::Art => Name(b"Art"),
880 Self::Sect => Name(b"Sect"),
881 Self::Div => Name(b"Div"),
882 Self::BlockQuote => Name(b"BlockQuote"),
883 Self::Caption => Name(b"Caption"),
884 Self::TOC => Name(b"TOC"),
885 Self::TOCI => Name(b"TOCI"),
886 Self::Index => Name(b"Index"),
887 Self::NonStruct => Name(b"NonStruct"),
888 Self::Private => Name(b"Private"),
889 Self::P => Name(b"P"),
890 Self::StructuredHeading => Name(b"H"),
891 Self::H1 => Name(b"H1"),
892 Self::H2 => Name(b"H2"),
893 Self::H3 => Name(b"H3"),
894 Self::H4 => Name(b"H4"),
895 Self::H5 => Name(b"H5"),
896 Self::H6 => Name(b"H6"),
897 Self::L => Name(b"L"),
898 Self::LI => Name(b"LI"),
899 Self::Lbl => Name(b"Lbl"),
900 Self::LBody => Name(b"LBody"),
901 Self::Table => Name(b"Table"),
902 Self::TR => Name(b"TR"),
903 Self::TH => Name(b"TH"),
904 Self::TD => Name(b"TD"),
905 Self::THead => Name(b"THead"),
906 Self::TBody => Name(b"TBody"),
907 Self::TFoot => Name(b"TFoot"),
908 Self::Span => Name(b"Span"),
909 Self::Quote => Name(b"Quote"),
910 Self::Note => Name(b"Note"),
911 Self::Reference => Name(b"Reference"),
912 Self::BibEntry => Name(b"BibEntry"),
913 Self::Code => Name(b"Code"),
914 Self::Link => Name(b"Link"),
915 Self::Annot => Name(b"Annot"),
916 Self::Ruby => Name(b"Ruby"),
917 Self::Warichu => Name(b"Warichu"),
918 Self::RB => Name(b"RB"),
919 Self::RT => Name(b"RT"),
920 Self::RP => Name(b"RP"),
921 Self::WT => Name(b"WT"),
922 Self::WP => Name(b"WP"),
923 Self::Figure => Name(b"Figure"),
924 Self::Formula => Name(b"Formula"),
925 Self::Form => Name(b"Form"),
926 }
927 }
928
929 pub fn into_pdf_2_0(self) -> Option<StructRole2> {
932 match self {
933 Self::Document => Some(StructRole2::Document),
934 Self::Part => Some(StructRole2::Part),
935 Self::Art => None,
936 Self::Sect => Some(StructRole2::Sect),
937 Self::Div => Some(StructRole2::Div),
938 Self::BlockQuote => None,
939 Self::Caption => Some(StructRole2::Caption),
940 Self::TOC => None,
941 Self::TOCI => None,
942 Self::Index => None,
943 Self::NonStruct => Some(StructRole2::NonStruct),
944 Self::Private => None,
945 Self::P => Some(StructRole2::P),
946 Self::StructuredHeading => Some(StructRole2::StructuredHeading),
947 Self::H1 => Some(StructRole2::Heading(NonZeroU16::new(1).unwrap())),
948 Self::H2 => Some(StructRole2::Heading(NonZeroU16::new(2).unwrap())),
949 Self::H3 => Some(StructRole2::Heading(NonZeroU16::new(3).unwrap())),
950 Self::H4 => Some(StructRole2::Heading(NonZeroU16::new(4).unwrap())),
951 Self::H5 => Some(StructRole2::Heading(NonZeroU16::new(5).unwrap())),
952 Self::H6 => Some(StructRole2::Heading(NonZeroU16::new(6).unwrap())),
953 Self::L => Some(StructRole2::L),
954 Self::LI => Some(StructRole2::LI),
955 Self::Lbl => Some(StructRole2::Lbl),
956 Self::LBody => Some(StructRole2::LBody),
957 Self::Table => Some(StructRole2::Table),
958 Self::TR => Some(StructRole2::TR),
959 Self::TH => Some(StructRole2::TH),
960 Self::TD => Some(StructRole2::TD),
961 Self::THead => Some(StructRole2::THead),
962 Self::TBody => Some(StructRole2::TBody),
963 Self::TFoot => Some(StructRole2::TFoot),
964 Self::Span => Some(StructRole2::Span),
965 Self::Quote => Some(StructRole2::Em),
966 Self::Note => Some(StructRole2::FENote),
967 Self::Reference => Some(StructRole2::Link),
968 Self::BibEntry => None,
969 Self::Code => Some(StructRole2::Strong),
970 Self::Link => Some(StructRole2::Link),
971 Self::Annot => Some(StructRole2::Annot),
972 Self::Ruby => Some(StructRole2::Ruby),
973 Self::Warichu => Some(StructRole2::Warichu),
974 Self::RB => Some(StructRole2::RB),
975 Self::RT => Some(StructRole2::RT),
976 Self::RP => Some(StructRole2::WP),
977 Self::WT => Some(StructRole2::WT),
978 Self::WP => Some(StructRole2::WP),
979 Self::Figure => Some(StructRole2::Figure),
980 Self::Formula => Some(StructRole2::Formula),
981 Self::Form => Some(StructRole2::Form),
982 }
983 }
984
985 pub fn role_type(self) -> StructRoleType {
987 match self {
988 Self::Document
989 | Self::Part
990 | Self::Art
991 | Self::Sect
992 | Self::Div
993 | Self::BlockQuote
994 | Self::Caption
995 | Self::TOC
996 | Self::TOCI
997 | Self::Index
998 | Self::NonStruct
999 | Self::Private => StructRoleType::Grouping,
1000 Self::P
1001 | Self::StructuredHeading
1002 | Self::H1
1003 | Self::H2
1004 | Self::H3
1005 | Self::H4
1006 | Self::H5
1007 | Self::H6 => {
1008 StructRoleType::BlockLevel(BlockLevelRoleSubtype::ParagraphLike)
1009 }
1010 Self::L | Self::LI | Self::Lbl | Self::LBody => {
1011 StructRoleType::BlockLevel(BlockLevelRoleSubtype::List)
1012 }
1013 Self::Table => StructRoleType::BlockLevel(BlockLevelRoleSubtype::Table),
1014 Self::TR | Self::TH | Self::TD | Self::THead | Self::TBody | Self::TFoot => {
1015 StructRoleType::Table
1016 }
1017 Self::Span
1018 | Self::Quote
1019 | Self::Note
1020 | Self::Reference
1021 | Self::BibEntry
1022 | Self::Code
1023 | Self::Ruby
1024 | Self::Warichu => {
1025 StructRoleType::InlineLevel(InlineLevelRoleSubtype::Generic)
1026 }
1027 Self::Link => StructRoleType::InlineLevel(InlineLevelRoleSubtype::Link),
1028 Self::Annot => {
1029 StructRoleType::InlineLevel(InlineLevelRoleSubtype::Annotation)
1030 }
1031 Self::RB | Self::RT | Self::RP | Self::WT | Self::WP => {
1032 StructRoleType::InlineLevel(InlineLevelRoleSubtype::RubyWarichu)
1033 }
1034 Self::Figure | Self::Formula | Self::Form => StructRoleType::Illustration,
1035 }
1036 }
1037}
1038
1039#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1042pub enum StructRoleType {
1043 Grouping,
1045 BlockLevel(BlockLevelRoleSubtype),
1047 InlineLevel(InlineLevelRoleSubtype),
1049 Illustration,
1051 Table,
1053}
1054
1055#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1058pub enum BlockLevelRoleSubtype {
1059 ParagraphLike,
1061 List,
1063 Table,
1065}
1066
1067#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1070pub enum InlineLevelRoleSubtype {
1071 Generic,
1073 Link,
1075 Annotation,
1077 RubyWarichu,
1079}
1080
1081impl TryFrom<StructRole> for StructRole2 {
1082 type Error = ();
1083
1084 fn try_from(value: StructRole) -> Result<Self, Self::Error> {
1085 value.into_pdf_2_0().ok_or(())
1086 }
1087}
1088
1089#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1095pub enum StructRole2 {
1096 Document,
1098 DocumentFragment,
1100 Part,
1102 Sect,
1104 Div,
1106 Aside,
1109 NonStruct,
1111 P,
1113 Heading(NonZeroU16),
1115 StructuredHeading,
1117 Title,
1119 FENote,
1121 Sub,
1123 Lbl,
1125 Span,
1127 Em,
1129 Strong,
1131 Link,
1133 Annot,
1135 Form,
1137 Ruby,
1139 RB,
1141 RT,
1143 RP,
1145 Warichu,
1147 WT,
1149 WP,
1151 L,
1153 LI,
1155 LBody,
1157 Table,
1159 TR,
1161 TH,
1163 TD,
1165 THead,
1167 TBody,
1169 TFoot,
1171 Caption,
1173 Figure,
1175 Formula,
1177 Artifact,
1179}
1180
1181impl StructRole2 {
1182 pub fn to_name(self, buf: &mut [u8; 6]) -> Name<'_> {
1187 Name(match self {
1188 Self::Document => b"Document",
1189 Self::DocumentFragment => b"DocumentFragment",
1190 Self::Part => b"Part",
1191 Self::Sect => b"Sect",
1192 Self::Div => b"Div",
1193 Self::Aside => b"Aside",
1194 Self::NonStruct => b"NonStruct",
1195 Self::P => b"P",
1196 Self::Heading(level) => {
1197 let mut cursor = Cursor::new(buf.as_mut_slice());
1198 write!(&mut cursor, "H{}", level.get()).unwrap();
1199 let pos = cursor.position() as usize;
1200 &buf[..pos]
1201 }
1202 Self::StructuredHeading => b"H",
1203 Self::Title => b"Title",
1204 Self::FENote => b"FENote",
1205 Self::Sub => b"Sub",
1206 Self::Lbl => b"Lbl",
1207 Self::Span => b"Span",
1208 Self::Em => b"Em",
1209 Self::Strong => b"Strong",
1210 Self::Link => b"Link",
1211 Self::Annot => b"Annot",
1212 Self::Form => b"Form",
1213 Self::Ruby => b"Ruby",
1214 Self::RB => b"RB",
1215 Self::RT => b"RT",
1216 Self::RP => b"RP",
1217 Self::Warichu => b"Warichu",
1218 Self::WT => b"WT",
1219 Self::WP => b"WP",
1220 Self::L => b"L",
1221 Self::LI => b"LI",
1222 Self::LBody => b"LBody",
1223 Self::Table => b"Table",
1224 Self::TR => b"TR",
1225 Self::TH => b"TH",
1226 Self::TD => b"TD",
1227 Self::THead => b"THead",
1228 Self::TBody => b"TBody",
1229 Self::TFoot => b"TFoot",
1230 Self::Caption => b"Caption",
1231 Self::Figure => b"Figure",
1232 Self::Formula => b"Formula",
1233 Self::Artifact => b"Artifact",
1234 })
1235 }
1236
1237 pub fn compatibility_1_7(self, opts: RoleMapOpts) -> StructRole2Compat {
1242 match self {
1243 Self::Document => StructRole2Compat::Compatible(StructRole::Document),
1244 Self::DocumentFragment => StructRole2Compat::RoleMapping(StructRole::Div),
1245 Self::Part => StructRole2Compat::Compatible(StructRole::Part),
1246 Self::Sect => StructRole2Compat::Compatible(StructRole::Sect),
1247 Self::Div => StructRole2Compat::Compatible(StructRole::Div),
1248 Self::Aside => StructRole2Compat::RoleMapping(StructRole::Div),
1249 Self::NonStruct => StructRole2Compat::Compatible(StructRole::NonStruct),
1250 Self::P => StructRole2Compat::Compatible(StructRole::P),
1251 Self::Heading(n) if n.get() == 1 => {
1252 StructRole2Compat::Compatible(StructRole::H1)
1253 }
1254 Self::Heading(n) if n.get() == 2 => {
1255 StructRole2Compat::Compatible(StructRole::H2)
1256 }
1257 Self::Heading(n) if n.get() == 3 => {
1258 StructRole2Compat::Compatible(StructRole::H3)
1259 }
1260 Self::Heading(n) if n.get() == 4 => {
1261 StructRole2Compat::Compatible(StructRole::H4)
1262 }
1263 Self::Heading(n) if n.get() == 5 => {
1264 StructRole2Compat::Compatible(StructRole::H5)
1265 }
1266 Self::Heading(n) if n.get() == 6 => {
1267 StructRole2Compat::Compatible(StructRole::H6)
1268 }
1269 Self::Heading(_) => StructRole2Compat::RoleMapping(
1270 if opts.contains(RoleMapOpts::MAP_HN_TO_H6) {
1271 StructRole::H6
1272 } else {
1273 StructRole::P
1274 },
1275 ),
1276 Self::StructuredHeading => {
1277 StructRole2Compat::Compatible(StructRole::StructuredHeading)
1278 }
1279 Self::Title => StructRole2Compat::RoleMapping(
1280 if opts.contains(RoleMapOpts::MAP_TITLE_TO_H1) {
1281 StructRole::H1
1282 } else {
1283 StructRole::P
1284 },
1285 ),
1286 Self::FENote => StructRole2Compat::RoleMapping(StructRole::Note),
1287 Self::Sub => StructRole2Compat::RoleMapping(
1288 if opts.contains(RoleMapOpts::MAP_SUB_TO_SPAN) {
1289 StructRole::Span
1290 } else {
1291 StructRole::Div
1292 },
1293 ),
1294 Self::Lbl => StructRole2Compat::Compatible(StructRole::Lbl),
1295 Self::Span => StructRole2Compat::Compatible(StructRole::Span),
1296 Self::Em => StructRole2Compat::RoleMapping(StructRole::Span),
1297 Self::Strong => StructRole2Compat::RoleMapping(StructRole::Span),
1298 Self::Link => StructRole2Compat::Compatible(StructRole::Link),
1299 Self::Annot => StructRole2Compat::Compatible(StructRole::Annot),
1300 Self::Form => StructRole2Compat::Compatible(StructRole::Form),
1301 Self::Ruby => StructRole2Compat::Compatible(StructRole::Ruby),
1302 Self::RB => StructRole2Compat::Compatible(StructRole::RB),
1303 Self::RT => StructRole2Compat::Compatible(StructRole::RT),
1304 Self::RP => StructRole2Compat::Compatible(StructRole::RP),
1305 Self::Warichu => StructRole2Compat::Compatible(StructRole::Warichu),
1306 Self::WT => StructRole2Compat::Compatible(StructRole::WT),
1307 Self::WP => StructRole2Compat::Compatible(StructRole::WP),
1308 Self::L => StructRole2Compat::Compatible(StructRole::L),
1309 Self::LI => StructRole2Compat::Compatible(StructRole::LI),
1310 Self::LBody => StructRole2Compat::Compatible(StructRole::LBody),
1311 Self::Table => StructRole2Compat::Compatible(StructRole::Table),
1312 Self::TR => StructRole2Compat::Compatible(StructRole::TR),
1313 Self::TH => StructRole2Compat::Compatible(StructRole::TH),
1314 Self::TD => StructRole2Compat::Compatible(StructRole::TD),
1315 Self::THead => StructRole2Compat::Compatible(StructRole::THead),
1316 Self::TBody => StructRole2Compat::Compatible(StructRole::TBody),
1317 Self::TFoot => StructRole2Compat::Compatible(StructRole::TFoot),
1318 Self::Caption => StructRole2Compat::Compatible(StructRole::Caption),
1319 Self::Figure => StructRole2Compat::Compatible(StructRole::Figure),
1320 Self::Formula => StructRole2Compat::Compatible(StructRole::Formula),
1321 Self::Artifact => StructRole2Compat::RoleMapping(StructRole::Private),
1322 }
1323 }
1324
1325 pub fn role_type(self) -> StructRoleType2 {
1327 match self {
1328 Self::Document | Self::DocumentFragment => StructRoleType2::Document,
1329 Self::Part | Self::Sect | Self::Div | Self::Aside | Self::NonStruct => {
1330 StructRoleType2::Grouping
1331 }
1332 Self::P
1333 | Self::Heading(_)
1334 | Self::StructuredHeading
1335 | Self::Title
1336 | Self::FENote => StructRoleType2::BlockLevel,
1337 Self::Sub => StructRoleType2::SubBlockLevel,
1338 Self::Lbl
1339 | Self::Span
1340 | Self::Em
1341 | Self::Strong
1342 | Self::Link
1343 | Self::Annot
1344 | Self::Form => {
1345 StructRoleType2::InlineLevel(InlineLevelRoleSubtype2::Generic)
1346 }
1347 Self::Ruby
1348 | Self::RB
1349 | Self::RP
1350 | Self::RT
1351 | Self::Warichu
1352 | Self::WT
1353 | Self::WP => {
1354 StructRoleType2::InlineLevel(InlineLevelRoleSubtype2::RubyWarichu)
1355 }
1356 Self::L | Self::LI | Self::LBody => StructRoleType2::List,
1357 Self::Table
1358 | Self::TR
1359 | Self::TH
1360 | Self::TD
1361 | Self::THead
1362 | Self::TBody
1363 | Self::TFoot => StructRoleType2::Table,
1364 Self::Caption => StructRoleType2::Caption,
1365 Self::Figure => StructRoleType2::Figure,
1366 Self::Formula => StructRoleType2::Formula,
1367 Self::Artifact => StructRoleType2::Artifact,
1368 }
1369 }
1370}
1371
1372bitflags::bitflags! {
1373 pub struct RoleMapOpts: u8 {
1375 const MAP_HN_TO_H6 = 1 << 0;
1378 const MAP_TITLE_TO_H1 = 1 << 1;
1381 const MAP_SUB_TO_SPAN = 1 << 2;
1384 }
1385}
1386
1387impl Default for RoleMapOpts {
1388 fn default() -> Self {
1389 Self::empty()
1390 }
1391}
1392
1393#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1395pub enum StructRole2Compat {
1396 Compatible(StructRole),
1398 RoleMapping(StructRole),
1401}
1402
1403impl StructRole2Compat {
1404 pub fn into_pdf_1_7(self) -> Option<StructRole> {
1407 match self {
1408 Self::Compatible(role) => Some(role),
1409 Self::RoleMapping(_) => None,
1410 }
1411 }
1412
1413 pub fn role_mapped_1_7(self) -> Option<StructRole> {
1418 match self {
1419 Self::Compatible(_) => None,
1420 Self::RoleMapping(role) => Some(role),
1421 }
1422 }
1423
1424 pub fn role(self) -> StructRole {
1426 match self {
1427 Self::Compatible(role) => role,
1428 Self::RoleMapping(role) => role,
1429 }
1430 }
1431}
1432
1433impl TryFrom<StructRole2> for StructRole {
1434 type Error = ();
1435
1436 fn try_from(value: StructRole2) -> Result<Self, Self::Error> {
1437 value
1438 .compatibility_1_7(RoleMapOpts::default())
1439 .into_pdf_1_7()
1440 .ok_or(())
1441 }
1442}
1443
1444#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1447pub enum StructRoleType2 {
1448 Document,
1450 Grouping,
1452 BlockLevel,
1454 SubBlockLevel,
1456 InlineLevel(InlineLevelRoleSubtype2),
1458 List,
1460 Table,
1462 Caption,
1464 Figure,
1466 Formula,
1468 Artifact,
1470}
1471
1472#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1475pub enum InlineLevelRoleSubtype2 {
1476 Generic,
1478 RubyWarichu,
1480}
1481
1482#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
1485pub enum PhoneticAlphabet<'a> {
1486 #[default]
1488 Ipa,
1489 XSampa,
1491 Pinyin,
1493 WadeGiles,
1495 Custom(Name<'a>),
1497}
1498
1499impl<'a> PhoneticAlphabet<'a> {
1500 pub(crate) fn to_name(self) -> Name<'a> {
1501 match self {
1502 Self::Ipa => Name(b"ipa"),
1503 Self::XSampa => Name(b"x-sampa"),
1504 Self::Pinyin => Name(b"zh-Latn-pinyin"),
1505 Self::WadeGiles => Name(b"zh-Latn-wadegile"),
1506 Self::Custom(name) => name,
1507 }
1508 }
1509}
1510
1511pub struct Namespace<'a> {
1515 dict: Dict<'a>,
1516}
1517
1518writer!(Namespace: |obj| {
1519 let mut dict = obj.dict();
1520 dict.pair(Name(b"Type"), Name(b"Namespace"));
1521 Self { dict }
1522});
1523
1524impl Namespace<'_> {
1525 pub fn ns(&mut self, identifier: TextStr) -> &mut Self {
1527 self.dict.pair(Name(b"NS"), identifier);
1528 self
1529 }
1530
1531 pub fn schema(&mut self) -> FileSpec<'_> {
1534 self.dict.insert(Name(b"Schema")).start()
1535 }
1536
1537 pub fn role_map_ns(&mut self) -> NamespaceRoleMap<'_> {
1543 self.dict.insert(Name(b"RoleMapNS")).start()
1544 }
1545
1546 pub fn pdf_2_ns(mut self) {
1549 self.ns(TextStr("https://www.iso.org/pdf2/ssn"));
1550 }
1551
1552 pub fn pdf_1_7_ns(mut self) {
1555 self.ns(TextStr("https://www.iso.org/pdf/ssn"));
1556 }
1557
1558 pub fn mathml_3_0_ns(mut self) {
1560 self.ns(TextStr("https://www.w3.org/1998/Math/MathML"));
1561 }
1562}
1563
1564deref!('a, Namespace<'a> => Dict<'a>, dict);
1565
1566pub struct NamespaceRoleMap<'a> {
1570 dict: Dict<'a>,
1571}
1572
1573writer!(NamespaceRoleMap: |obj| {
1574 Self { dict: obj.dict() }
1575});
1576
1577impl NamespaceRoleMap<'_> {
1578 pub fn to_pdf_1_7(&mut self, name: Name, role: StructRole) -> &mut Self {
1581 self.dict.pair(name, role.to_name());
1582 self
1583 }
1584
1585 pub fn to_namespace(&mut self, name: Name, role: Name, ns_ref: Ref) -> &mut Self {
1589 let mut array = self.dict.insert(name).array();
1590 array.item(role);
1591 array.item(ns_ref);
1592 array.finish();
1593 self
1594 }
1595
1596 pub fn to_pdf_2_0(
1603 &mut self,
1604 name: Name,
1605 role: StructRole2,
1606 pdf_2_ns: Ref,
1607 ) -> &mut Self {
1608 self.to_namespace(name, role.to_name(&mut [0; 6]), pdf_2_ns)
1609 }
1610}
1611
1612deref!('a, NamespaceRoleMap<'a> => Dict<'a>, dict);
1613
1614pub struct MarkInfo<'a> {
1618 dict: Dict<'a>,
1619}
1620
1621writer!(MarkInfo: |obj| Self { dict: obj.dict() });
1622
1623impl MarkInfo<'_> {
1624 pub fn marked(&mut self, conformant: bool) -> &mut Self {
1629 self.pair(Name(b"Marked"), conformant);
1630 self
1631 }
1632
1633 pub fn user_properties(&mut self, present: bool) -> &mut Self {
1636 self.pair(Name(b"UserProperties"), present);
1637 self
1638 }
1639
1640 pub fn suspects(&mut self, present: bool) -> &mut Self {
1643 self.pair(Name(b"Suspects"), present);
1644 self
1645 }
1646}
1647
1648deref!('a, MarkInfo<'a> => Dict<'a>, dict);
1649
1650#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
1654pub enum Direction {
1655 #[default]
1657 L2R,
1658 R2L,
1660}
1661
1662impl Direction {
1663 pub(crate) fn to_name(self) -> Name<'static> {
1664 match self {
1665 Self::L2R => Name(b"L2R"),
1666 Self::R2L => Name(b"R2L"),
1667 }
1668 }
1669}
1670
1671pub struct PageLabel<'a> {
1673 dict: Dict<'a>,
1674}
1675
1676writer!(PageLabel: |obj| {
1677 let mut dict = obj.dict();
1678 dict.pair(Name(b"Type"), Name(b"PageLabel"));
1679 Self { dict }
1680});
1681
1682impl PageLabel<'_> {
1683 pub fn style(&mut self, style: NumberingStyle) -> &mut Self {
1688 self.pair(Name(b"S"), style.to_name());
1689 self
1690 }
1691
1692 pub fn prefix(&mut self, prefix: impl TextStrLike) -> &mut Self {
1694 self.pair(Name(b"P"), prefix);
1695 self
1696 }
1697
1698 pub fn offset(&mut self, offset: i32) -> &mut Self {
1702 self.pair(Name(b"St"), offset);
1703 self
1704 }
1705}
1706
1707deref!('a, PageLabel<'a> => Dict<'a>, dict);
1708
1709#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1711pub enum NumberingStyle {
1712 Arabic,
1714 LowerRoman,
1716 UpperRoman,
1718 LowerAlpha,
1720 UpperAlpha,
1722}
1723
1724impl NumberingStyle {
1725 pub(crate) fn to_name(self) -> Name<'static> {
1726 match self {
1727 NumberingStyle::Arabic => Name(b"D"),
1728 NumberingStyle::LowerRoman => Name(b"r"),
1729 NumberingStyle::UpperRoman => Name(b"R"),
1730 NumberingStyle::LowerAlpha => Name(b"a"),
1731 NumberingStyle::UpperAlpha => Name(b"A"),
1732 }
1733 }
1734}
1735
1736pub struct DocumentInfo<'a> {
1740 dict: Dict<'a>,
1741}
1742
1743writer!(DocumentInfo: |obj| Self { dict: obj.dict() });
1744
1745impl DocumentInfo<'_> {
1746 pub fn title(&mut self, title: impl TextStrLike) -> &mut Self {
1748 self.pair(Name(b"Title"), title);
1749 self
1750 }
1751
1752 pub fn author(&mut self, author: impl TextStrLike) -> &mut Self {
1754 self.pair(Name(b"Author"), author);
1755 self
1756 }
1757
1758 pub fn subject(&mut self, subject: impl TextStrLike) -> &mut Self {
1760 self.pair(Name(b"Subject"), subject);
1761 self
1762 }
1763
1764 pub fn keywords(&mut self, keywords: impl TextStrLike) -> &mut Self {
1767 self.pair(Name(b"Keywords"), keywords);
1768 self
1769 }
1770
1771 pub fn creator(&mut self, creator: impl TextStrLike) -> &mut Self {
1774 self.pair(Name(b"Creator"), creator);
1775 self
1776 }
1777
1778 pub fn producer(&mut self, producer: impl TextStrLike) -> &mut Self {
1781 self.pair(Name(b"Producer"), producer);
1782 self
1783 }
1784
1785 pub fn creation_date(&mut self, date: Date) -> &mut Self {
1788 self.pair(Name(b"CreationDate"), date);
1789 self
1790 }
1791
1792 pub fn modified_date(&mut self, date: Date) -> &mut Self {
1797 self.pair(Name(b"ModDate"), date);
1798 self
1799 }
1800
1801 pub fn trapped(&mut self, trapped: TrappingStatus) -> &mut Self {
1804 self.pair(Name(b"Trapped"), trapped.to_name());
1805 self
1806 }
1807}
1808
1809deref!('a, DocumentInfo<'a> => Dict<'a>, dict);
1810
1811#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
1815pub enum TrappingStatus {
1816 Trapped,
1818 NotTrapped,
1820 #[default]
1822 Unknown,
1823}
1824
1825impl TrappingStatus {
1826 pub(crate) fn to_name(self) -> Name<'static> {
1827 match self {
1828 TrappingStatus::Trapped => Name(b"True"),
1829 TrappingStatus::NotTrapped => Name(b"False"),
1830 TrappingStatus::Unknown => Name(b"Unknown"),
1831 }
1832 }
1833}
1834
1835pub struct Pages<'a> {
1839 dict: Dict<'a>,
1840}
1841
1842writer!(Pages: |obj| {
1843 let mut dict = obj.dict();
1844 dict.pair(Name(b"Type"), Name(b"Pages"));
1845 Self { dict }
1846});
1847
1848impl Pages<'_> {
1849 pub fn parent(&mut self, parent: Ref) -> &mut Self {
1851 self.pair(Name(b"Parent"), parent);
1852 self
1853 }
1854
1855 pub fn kids(&mut self, kids: impl IntoIterator<Item = Ref>) -> &mut Self {
1858 self.insert(Name(b"Kids")).array().items(kids);
1859 self
1860 }
1861
1862 pub fn count(&mut self, count: i32) -> &mut Self {
1866 self.pair(Name(b"Count"), count);
1867 self
1868 }
1869
1870 pub fn media_box(&mut self, rect: Rect) -> &mut Self {
1872 self.pair(Name(b"MediaBox"), rect);
1873 self
1874 }
1875
1876 pub fn resources(&mut self) -> Resources<'_> {
1878 self.insert(Name(b"Resources")).start()
1879 }
1880}
1881
1882deref!('a, Pages<'a> => Dict<'a>, dict);
1883
1884pub struct Page<'a> {
1888 dict: Dict<'a>,
1889}
1890
1891writer!(Page: |obj| {
1892 let mut dict = obj.dict();
1893 dict.pair(Name(b"Type"), Name(b"Page"));
1894 Self { dict }
1895});
1896
1897impl Page<'_> {
1898 pub fn parent(&mut self, parent: Ref) -> &mut Self {
1900 self.pair(Name(b"Parent"), parent);
1901 self
1902 }
1903
1904 pub fn last_modified(&mut self, date: Date) -> &mut Self {
1906 self.pair(Name(b"LastModified"), date);
1907 self
1908 }
1909
1910 pub fn media_box(&mut self, rect: Rect) -> &mut Self {
1913 self.pair(Name(b"MediaBox"), rect);
1914 self
1915 }
1916
1917 pub fn crop_box(&mut self, rect: Rect) -> &mut Self {
1920 self.pair(Name(b"CropBox"), rect);
1921 self
1922 }
1923
1924 pub fn bleed_box(&mut self, rect: Rect) -> &mut Self {
1928 self.pair(Name(b"BleedBox"), rect);
1929 self
1930 }
1931
1932 pub fn trim_box(&mut self, rect: Rect) -> &mut Self {
1935 self.pair(Name(b"TrimBox"), rect);
1936 self
1937 }
1938
1939 pub fn art_box(&mut self, rect: Rect) -> &mut Self {
1942 self.pair(Name(b"ArtBox"), rect);
1943 self
1944 }
1945
1946 pub fn resources(&mut self) -> Resources<'_> {
1948 self.insert(Name(b"Resources")).start()
1949 }
1950
1951 pub fn contents(&mut self, id: Ref) -> &mut Self {
1956 self.pair(Name(b"Contents"), id);
1957 self
1958 }
1959
1960 pub fn contents_array(&mut self, ids: impl IntoIterator<Item = Ref>) -> &mut Self {
1962 self.insert(Name(b"Contents")).array().items(ids);
1963 self
1964 }
1965
1966 pub fn rotate(&mut self, degrees: i32) -> &mut Self {
1970 self.pair(Name(b"Rotate"), degrees);
1971 self
1972 }
1973
1974 pub fn group(&mut self) -> Group<'_> {
1980 self.insert(Name(b"Group")).start()
1981 }
1982
1983 pub fn thumbnail(&mut self, id: Ref) -> &mut Self {
1987 self.pair(Name(b"Thumb"), id);
1988 self
1989 }
1990
1991 pub fn duration(&mut self, seconds: f32) -> &mut Self {
1994 self.pair(Name(b"Dur"), seconds);
1995 self
1996 }
1997
1998 pub fn transition(&mut self) -> Transition<'_> {
2001 self.insert(Name(b"Trans")).start()
2002 }
2003
2004 pub fn annotations(&mut self, ids: impl IntoIterator<Item = Ref>) -> &mut Self {
2006 self.insert(Name(b"Annots")).array().items(ids);
2007 self
2008 }
2009
2010 pub fn struct_parents(&mut self, key: i32) -> &mut Self {
2013 self.pair(Name(b"StructParents"), key);
2014 self
2015 }
2016
2017 pub fn tab_order(&mut self, order: TabOrder) -> &mut Self {
2020 self.pair(Name(b"Tabs"), order.to_name());
2021 self
2022 }
2023
2024 pub fn user_unit(&mut self, value: f32) -> &mut Self {
2027 self.pair(Name(b"UserUnit"), value);
2028 self
2029 }
2030
2031 pub fn additional_actions(&mut self) -> AdditionalActions<'_> {
2036 self.insert(Name(b"AA")).start()
2037 }
2038
2039 pub fn metadata(&mut self, id: Ref) -> &mut Self {
2046 self.pair(Name(b"Metadata"), id);
2047 self
2048 }
2049
2050 pub fn associated_files(&mut self) -> TypedArray<'_, FileSpec<'_>> {
2053 self.insert(Name(b"AF")).array().typed()
2054 }
2055}
2056
2057deref!('a, Page<'a> => Dict<'a>, dict);
2058
2059pub struct Outline<'a> {
2063 dict: Dict<'a>,
2064}
2065
2066writer!(Outline: |obj| {
2067 let mut dict = obj.dict();
2068 dict.pair(Name(b"Type"), Name(b"Outlines"));
2069 Self { dict }
2070});
2071
2072impl Outline<'_> {
2073 pub fn first(&mut self, item: Ref) -> &mut Self {
2076 self.pair(Name(b"First"), item);
2077 self
2078 }
2079
2080 pub fn last(&mut self, item: Ref) -> &mut Self {
2083 self.pair(Name(b"Last"), item);
2084 self
2085 }
2086
2087 pub fn count(&mut self, count: i32) -> &mut Self {
2092 assert!(count >= 0, "visible outline count must not be negative");
2093 self.pair(Name(b"Count"), count);
2094 self
2095 }
2096}
2097
2098deref!('a, Outline<'a> => Dict<'a>, dict);
2099
2100pub struct OutlineItem<'a> {
2104 dict: Dict<'a>,
2105}
2106
2107writer!(OutlineItem: |obj| Self { dict: obj.dict() });
2108
2109impl OutlineItem<'_> {
2110 pub fn title(&mut self, title: impl TextStrLike) -> &mut Self {
2112 self.pair(Name(b"Title"), title);
2113 self
2114 }
2115
2116 pub fn parent(&mut self, outline: Ref) -> &mut Self {
2119 self.pair(Name(b"Parent"), outline);
2120 self
2121 }
2122
2123 pub fn prev(&mut self, outline: Ref) -> &mut Self {
2126 self.pair(Name(b"Prev"), outline);
2127 self
2128 }
2129
2130 pub fn next(&mut self, outline: Ref) -> &mut Self {
2133 self.pair(Name(b"Next"), outline);
2134 self
2135 }
2136
2137 pub fn first(&mut self, outline: Ref) -> &mut Self {
2139 self.pair(Name(b"First"), outline);
2140 self
2141 }
2142
2143 pub fn last(&mut self, outline: Ref) -> &mut Self {
2145 self.pair(Name(b"Last"), outline);
2146 self
2147 }
2148
2149 pub fn count(&mut self, items: i32) -> &mut Self {
2154 self.pair(Name(b"Count"), items);
2155 self
2156 }
2157
2158 pub fn dest(&mut self) -> Destination<'_> {
2161 self.insert(Name(b"Dest")).start()
2162 }
2163
2164 pub fn dest_name(&mut self, name: Name) -> &mut Self {
2167 self.pair(Name(b"Dest"), name);
2168 self
2169 }
2170
2171 pub fn color_rgb(&mut self, r: f32, g: f32, b: f32) -> &mut Self {
2174 self.insert(Name(b"C")).array().items([r, g, b]);
2175 self
2176 }
2177
2178 pub fn flags(&mut self, flags: OutlineItemFlags) -> &mut Self {
2180 self.pair(Name(b"F"), flags.bits() as i32);
2181 self
2182 }
2183}
2184
2185deref!('a, OutlineItem<'a> => Dict<'a>, dict);
2186
2187bitflags::bitflags! {
2188 pub struct OutlineItemFlags: u32 {
2190 const ITALIC = 1 << 0;
2192 const BOLD = 1 << 1;
2194 }
2195}
2196
2197pub struct Names<'a> {
2202 dict: Dict<'a>,
2203}
2204
2205writer!(Names: |obj| Self { dict: obj.dict() });
2206
2207impl Names<'_> {
2208 pub fn destinations(&mut self) -> NameTree<'_, Ref> {
2211 self.dict.insert(Name(b"Dests")).start()
2212 }
2213
2214 pub fn appearances(&mut self) -> NameTree<'_, Ref> {
2217 self.dict.insert(Name(b"AP")).start()
2218 }
2219
2220 pub fn javascript(&mut self) -> NameTree<'_, Ref> {
2223 self.dict.insert(Name(b"JavaScript")).start()
2224 }
2225
2226 pub fn pages(&mut self) -> NameTree<'_, Ref> {
2228 self.dict.insert(Name(b"Pages")).start()
2229 }
2230
2231 pub fn templates(&mut self) -> NameTree<'_, Ref> {
2234 self.dict.insert(Name(b"Templates")).start()
2235 }
2236
2237 pub fn capture_ids(&mut self) -> NameTree<'_, Ref> {
2240 self.dict.insert(Name(b"IDS")).start()
2241 }
2242
2243 pub fn capture_urls(&mut self) -> NameTree<'_, Ref> {
2246 self.dict.insert(Name(b"URLS")).start()
2247 }
2248
2249 pub fn embedded_files(&mut self) -> NameTree<'_, Ref> {
2255 self.dict.insert(Name(b"EmbeddedFiles")).start()
2256 }
2257
2258 pub fn alternate_presentations(&mut self) -> NameTree<'_, Ref> {
2263 self.dict.insert(Name(b"AlternatePresentations")).start()
2264 }
2265
2266 pub fn renditions(&mut self) -> NameTree<'_, Ref> {
2269 self.dict.insert(Name(b"Renditions")).start()
2270 }
2271}
2272
2273deref!('a, Names<'a> => Dict<'a>, dict);
2274
2275pub struct Destination<'a> {
2281 array: Array<'a>,
2282}
2283
2284writer!(Destination: |obj| Self { array: obj.array() });
2285
2286impl Destination<'_> {
2287 pub fn page(mut self, page: Ref) -> Self {
2289 self.item(page);
2290 self
2291 }
2292
2293 pub fn xyz(mut self, left: f32, top: f32, zoom: Option<f32>) {
2295 self.item(Name(b"XYZ"));
2296 self.item(left);
2297 self.item(top);
2298 self.item(zoom.unwrap_or_default());
2299 }
2300
2301 pub fn fit(mut self) {
2304 self.item(Name(b"Fit"));
2305 }
2306
2307 pub fn fit_horizontal(mut self, top: f32) {
2310 self.item(Name(b"FitH"));
2311 self.item(top);
2312 }
2313
2314 pub fn fit_vertical(mut self, left: f32) {
2317 self.item(Name(b"FitV"));
2318 self.item(left);
2319 }
2320
2321 pub fn fit_rect(mut self, rect: Rect) {
2324 self.item(Name(b"FitR"));
2325 self.array.items([rect.x1, rect.y1, rect.x2, rect.y2]);
2326 }
2327
2328 pub fn fit_bounding_box(mut self) {
2331 self.item(Name(b"FitB"));
2332 }
2333
2334 pub fn fit_bounding_box_horizontal(mut self, top: f32) {
2337 self.item(Name(b"FitBH"));
2338 self.item(top);
2339 }
2340
2341 pub fn fit_bounding_box_vertical(mut self, left: f32) {
2344 self.item(Name(b"FitBV"));
2345 self.item(left);
2346 }
2347}
2348
2349deref!('a, Destination<'a> => Array<'a>, array);
2350
2351#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
2353pub enum TabOrder {
2354 RowOrder,
2356 ColumnOrder,
2358 StructureOrder,
2360}
2361
2362impl TabOrder {
2363 pub(crate) fn to_name(self) -> Name<'static> {
2364 match self {
2365 Self::RowOrder => Name(b"R"),
2366 Self::ColumnOrder => Name(b"C"),
2367 Self::StructureOrder => Name(b"S"),
2368 }
2369 }
2370}
2371
2372pub struct Metadata<'a> {
2376 stream: Stream<'a>,
2377}
2378
2379impl<'a> Metadata<'a> {
2380 pub(crate) fn start(mut stream: Stream<'a>) -> Self {
2382 stream.pair(Name(b"Type"), Name(b"Metadata"));
2383 stream.pair(Name(b"Subtype"), Name(b"XML"));
2384 Self { stream }
2385 }
2386}
2387
2388deref!('a, Metadata<'a> => Stream<'a>, stream);
2389
2390#[cfg(test)]
2391mod tests {
2392 use super::*;
2393
2394 #[test]
2395 fn test_max_heading_name() {
2396 let mut buf = [0; 6];
2397 let name = StructRole2::Heading(NonZeroU16::MAX).to_name(&mut buf);
2398 assert_eq!(Name(b"H65535"), name);
2399 }
2400}