1use std::convert::TryFrom;
2use std::marker::PhantomData;
3use std::mem::ManuallyDrop;
4use std::num::NonZeroI32;
5
6use super::*;
7
8pub trait Primitive {
10 fn write(self, buf: &mut Buf);
12}
13
14impl<T: Primitive> Primitive for &T
15where
16 T: Copy,
17{
18 #[inline]
19 fn write(self, buf: &mut Buf) {
20 (*self).write(buf);
21 }
22}
23
24impl Primitive for bool {
25 #[inline]
26 fn write(self, buf: &mut Buf) {
27 if self {
28 buf.extend(b"true");
29 } else {
30 buf.extend(b"false");
31 }
32 }
33}
34
35impl Primitive for i32 {
36 #[inline]
37 fn write(self, buf: &mut Buf) {
38 buf.push_int(self);
39 }
40}
41
42impl Primitive for f32 {
43 #[inline]
44 fn write(self, buf: &mut Buf) {
45 buf.push_float(self);
46 }
47}
48
49#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
53pub struct Str<'a>(pub &'a [u8]);
54
55impl Str<'_> {
56 fn is_balanced(self) -> bool {
58 let mut depth = 0;
59 for &byte in self.0 {
60 match byte {
61 b'(' => depth += 1,
62 b')' if depth > 0 => depth -= 1,
63 b')' => return false,
64 _ => {}
65 }
66 }
67 depth == 0
68 }
69}
70
71impl Primitive for Str<'_> {
72 fn write(self, buf: &mut Buf) {
73 buf.limits.register_str_len(self.0.len());
74
75 if self.0.iter().all(|b| b.is_ascii()) {
81 buf.reserve(self.0.len());
82 buf.inner.push(b'(');
83
84 let mut balanced = None;
85 for &byte in self.0 {
86 match byte {
87 b'(' | b')' => {
88 if !*balanced
89 .get_or_insert_with(|| byte != b')' && self.is_balanced())
90 {
91 buf.push(b'\\');
92 }
93 buf.push(byte);
94 }
95 b'\\' => buf.extend(br"\\"),
96 b' '..=b'~' => buf.push(byte),
97 b'\n' => buf.extend(br"\n"),
98 b'\r' => buf.extend(br"\r"),
99 b'\t' => buf.extend(br"\t"),
100 b'\x08' => buf.extend(br"\b"),
101 b'\x0c' => buf.extend(br"\f"),
102 _ => {
103 buf.push(b'\\');
104 buf.push_octal(byte);
105 }
106 }
107 }
108
109 buf.push(b')');
110 } else {
111 buf.reserve(2 + 2 * self.0.len());
112 buf.push(b'<');
113
114 for &byte in self.0 {
115 buf.push_hex(byte);
116 }
117
118 buf.push(b'>');
119 }
120 }
121}
122
123#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
128pub struct TextStr<'a>(pub &'a str);
129
130impl Primitive for TextStr<'_> {
131 fn write(self, buf: &mut Buf) {
132 buf.limits.register_str_len(self.0.len());
133
134 if self.0.bytes().all(|b| matches!(b, 32..=126)) {
136 Str(self.0.as_bytes()).write(buf);
137 } else {
138 buf.reserve(6 + 4 * self.0.len());
139 buf.push(b'<');
140 buf.push_hex(254);
141 buf.push_hex(255);
142 for value in self.0.encode_utf16() {
143 buf.push_hex_u16(value);
144 }
145 buf.push(b'>');
146 }
147 }
148}
149
150#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
154pub struct Name<'a>(pub &'a [u8]);
155
156impl Primitive for Name<'_> {
157 fn write(self, buf: &mut Buf) {
158 buf.limits.register_name_len(self.0.len());
159
160 buf.reserve(1 + self.0.len());
161 buf.push(b'/');
162 for &byte in self.0 {
163 if byte != b'#' && matches!(byte, b'!'..=b'~') && is_regular_character(byte) {
167 buf.push(byte);
168 } else {
169 buf.push(b'#');
170 buf.push_hex(byte);
171 }
172 }
173 }
174}
175
176fn is_regular_character(byte: u8) -> bool {
178 !matches!(
179 byte,
180 b'\0'
181 | b'\t'
182 | b'\n'
183 | b'\x0C'
184 | b'\r'
185 | b' '
186 | b'('
187 | b')'
188 | b'<'
189 | b'>'
190 | b'['
191 | b']'
192 | b'{'
193 | b'}'
194 | b'/'
195 | b'%'
196 )
197}
198
199#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
201pub struct Null;
202
203impl Primitive for Null {
204 #[inline]
205 fn write(self, buf: &mut Buf) {
206 buf.extend(b"null");
207 }
208}
209
210#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
212pub struct Ref(NonZeroI32);
213
214impl Ref {
215 #[inline]
221 #[track_caller]
222 pub const fn new(id: i32) -> Ref {
223 let option = if id > 0 { NonZeroI32::new(id) } else { None };
224 match option {
225 Some(val) => Self(val),
226 None => panic!("indirect reference out of valid range"),
227 }
228 }
229
230 #[inline]
232 pub const fn get(self) -> i32 {
233 self.0.get()
234 }
235
236 #[inline]
238 pub const fn next(self) -> Self {
239 Self::new(self.get() + 1)
240 }
241
242 #[inline]
245 pub fn bump(&mut self) -> Self {
246 let prev = *self;
247 *self = self.next();
248 prev
249 }
250}
251
252impl Primitive for Ref {
253 #[inline]
254 fn write(self, buf: &mut Buf) {
255 buf.push_int(self.0.get());
256 buf.extend(b" 0 R");
257 }
258}
259
260#[derive(Debug, Copy, Clone, PartialEq)]
262pub struct Rect {
263 pub x1: f32,
265 pub y1: f32,
267 pub x2: f32,
269 pub y2: f32,
271}
272
273impl Rect {
274 #[inline]
276 pub fn new(x1: f32, y1: f32, x2: f32, y2: f32) -> Self {
277 Self { x1, y1, x2, y2 }
278 }
279
280 #[inline]
283 pub fn to_quad_points(self) -> [f32; 8] {
284 [self.x1, self.y1, self.x2, self.y1, self.x2, self.y2, self.x1, self.y2]
285 }
286}
287
288impl Primitive for Rect {
289 #[inline]
290 fn write(self, buf: &mut Buf) {
291 buf.push(b'[');
292 buf.push_val(self.x1);
293 buf.push(b' ');
294 buf.push_val(self.y1);
295 buf.push(b' ');
296 buf.push_val(self.x2);
297 buf.push(b' ');
298 buf.push_val(self.y2);
299 buf.push(b']');
300
301 buf.limits.register_array_len(4);
302 }
303}
304
305#[derive(Debug, Copy, Clone, Eq, PartialEq)]
313pub struct Date {
314 year: u16,
316 month: Option<u8>,
318 day: Option<u8>,
320 hour: Option<u8>,
322 minute: Option<u8>,
324 second: Option<u8>,
326 utc_offset_hour: Option<i8>,
328 utc_offset_minute: u8,
331}
332
333impl Date {
334 #[inline]
337 pub fn new(year: u16) -> Self {
338 Self {
339 year: year.min(9999),
340 month: None,
341 day: None,
342 hour: None,
343 minute: None,
344 second: None,
345 utc_offset_hour: None,
346 utc_offset_minute: 0,
347 }
348 }
349
350 #[inline]
352 pub fn month(mut self, month: u8) -> Self {
353 self.month = Some(month.clamp(1, 12));
354 self
355 }
356
357 #[inline]
359 pub fn day(mut self, day: u8) -> Self {
360 self.day = Some(day.clamp(1, 31));
361 self
362 }
363
364 #[inline]
366 pub fn hour(mut self, hour: u8) -> Self {
367 self.hour = Some(hour.min(23));
368 self
369 }
370
371 #[inline]
373 pub fn minute(mut self, minute: u8) -> Self {
374 self.minute = Some(minute.min(59));
375 self
376 }
377
378 #[inline]
380 pub fn second(mut self, second: u8) -> Self {
381 self.second = Some(second.min(59));
382 self
383 }
384
385 #[inline]
389 pub fn utc_offset_hour(mut self, hour: i8) -> Self {
390 self.utc_offset_hour = Some(hour.clamp(-23, 23));
391 self
392 }
393
394 #[inline]
397 pub fn utc_offset_minute(mut self, minute: u8) -> Self {
398 self.utc_offset_minute = minute.min(59);
399 self
400 }
401}
402
403impl Primitive for Date {
404 fn write(self, buf: &mut Buf) {
405 buf.extend(b"(D:");
406
407 (|| {
408 write!(buf.inner, "{:04}", self.year).unwrap();
409 write!(buf.inner, "{:02}", self.month?).unwrap();
410 write!(buf.inner, "{:02}", self.day?).unwrap();
411 write!(buf.inner, "{:02}", self.hour?).unwrap();
412 write!(buf.inner, "{:02}", self.minute?).unwrap();
413 write!(buf.inner, "{:02}", self.second?).unwrap();
414 let utc_offset_hour = self.utc_offset_hour?;
415 if utc_offset_hour == 0 && self.utc_offset_minute == 0 {
416 buf.push(b'Z');
417 } else {
418 write!(
419 buf.inner,
420 "{:+03}'{:02}",
421 utc_offset_hour, self.utc_offset_minute
422 )
423 .unwrap();
424 }
425 Some(())
426 })();
427
428 buf.push(b')');
429 }
430}
431
432#[must_use = "not consuming this leaves the writer in an inconsistent state"]
434pub struct Obj<'a> {
435 buf: &'a mut Buf,
436 indirect: bool,
437 indent: u8,
438}
439
440impl<'a> Obj<'a> {
441 #[inline]
443 pub(crate) fn direct(buf: &'a mut Buf, indent: u8) -> Self {
444 Self { buf, indirect: false, indent }
445 }
446
447 #[inline]
449 pub(crate) fn indirect(buf: &'a mut Buf, id: Ref) -> Self {
450 buf.push_int(id.get());
451 buf.extend(b" 0 obj\n");
452 Self { buf, indirect: true, indent: 0 }
453 }
454
455 #[inline]
457 pub fn primitive<T: Primitive>(self, value: T) {
458 value.write(self.buf);
459 if self.indirect {
460 self.buf.extend(b"\nendobj\n\n");
461 }
462 }
463
464 #[inline]
466 pub fn array(self) -> Array<'a> {
467 self.start()
468 }
469
470 #[inline]
472 pub fn dict(self) -> Dict<'a> {
473 self.start()
474 }
475
476 #[inline]
492 pub fn start<W: Writer<'a>>(self) -> W {
493 W::start(self)
494 }
495}
496
497pub trait Writer<'a> {
499 fn start(obj: Obj<'a>) -> Self;
501}
502
503pub trait Rewrite<'a> {
509 type Output: Writer<'a>;
511}
512
513pub struct Array<'a> {
515 buf: &'a mut Buf,
516 indirect: bool,
517 indent: u8,
518 len: i32,
519}
520
521writer!(Array: |obj| {
522 obj.buf.push(b'[');
523 Self {
524 buf: obj.buf,
525 indirect: obj.indirect,
526 indent: obj.indent,
527 len: 0,
528 }
529});
530
531impl<'a> Array<'a> {
532 #[inline]
534 pub fn len(&self) -> i32 {
535 self.len
536 }
537
538 #[inline]
540 pub fn is_empty(&self) -> bool {
541 self.len == 0
542 }
543
544 #[inline]
546 pub fn push(&mut self) -> Obj<'_> {
547 if self.len != 0 {
548 self.buf.push(b' ');
549 }
550 self.len += 1;
551 Obj::direct(self.buf, self.indent)
552 }
553
554 #[inline]
558 pub fn item<T: Primitive>(&mut self, value: T) -> &mut Self {
559 self.push().primitive(value);
560 self
561 }
562
563 #[inline]
565 pub fn items<T: Primitive>(
566 &mut self,
567 values: impl IntoIterator<Item = T>,
568 ) -> &mut Self {
569 for value in values {
570 self.item(value);
571 }
572 self
573 }
574
575 #[inline]
577 pub fn typed<T>(self) -> TypedArray<'a, T> {
578 TypedArray::wrap(self)
579 }
580}
581
582impl Drop for Array<'_> {
583 #[inline]
584 fn drop(&mut self) {
585 self.buf.limits.register_array_len(self.len() as usize);
586 self.buf.push(b']');
587 if self.indirect {
588 self.buf.extend(b"\nendobj\n\n");
589 }
590 }
591}
592
593pub struct TypedArray<'a, T> {
595 array: Array<'a>,
596 phantom: PhantomData<fn() -> T>,
597}
598
599impl<'a, T> Writer<'a> for TypedArray<'a, T> {
600 fn start(obj: Obj<'a>) -> Self {
601 Self { array: obj.array(), phantom: PhantomData }
602 }
603}
604
605impl<'a, T> Rewrite<'a> for TypedArray<'_, T> {
606 type Output = TypedArray<'a, T>;
607}
608
609impl<'a, T> TypedArray<'a, T> {
610 #[inline]
612 pub fn wrap(array: Array<'a>) -> Self {
613 Self { array, phantom: PhantomData }
614 }
615
616 #[inline]
618 pub fn len(&self) -> i32 {
619 self.array.len()
620 }
621
622 #[inline]
624 pub fn is_empty(&self) -> bool {
625 self.len() == 0
626 }
627
628 #[inline]
630 pub fn item(&mut self, value: T) -> &mut Self
631 where
632 T: Primitive,
633 {
634 self.array.item(value);
635 self
636 }
637
638 #[inline]
640 pub fn items(&mut self, values: impl IntoIterator<Item = T>) -> &mut Self
641 where
642 T: Primitive,
643 {
644 self.array.items(values);
645 self
646 }
647
648 #[inline]
652 pub fn push<'b>(&'b mut self) -> <T as Rewrite<'b>>::Output
653 where
654 T: Writer<'a> + Rewrite<'b>,
655 {
656 <T as Rewrite>::Output::start(self.array.push())
657 }
658}
659
660pub struct Dict<'a> {
662 buf: &'a mut Buf,
663 indirect: bool,
664 indent: u8,
665 len: i32,
666}
667
668writer!(Dict: |obj| {
669 obj.buf.extend(b"<<");
670 Self {
671 buf: obj.buf,
672 indirect: obj.indirect,
673 indent: obj.indent.saturating_add(2),
674 len: 0,
675 }
676});
677
678impl<'a> Dict<'a> {
679 #[inline]
681 pub fn len(&self) -> i32 {
682 self.len
683 }
684
685 #[inline]
687 pub fn is_empty(&self) -> bool {
688 self.len == 0
689 }
690
691 #[inline]
693 pub fn insert(&mut self, key: Name) -> Obj<'_> {
694 self.len += 1;
695 self.buf.push(b'\n');
696
697 for _ in 0..self.indent {
698 self.buf.push(b' ');
699 }
700
701 self.buf.push_val(key);
702 self.buf.push(b' ');
703
704 Obj::direct(self.buf, self.indent)
705 }
706
707 #[inline]
711 pub fn pair<T: Primitive>(&mut self, key: Name, value: T) -> &mut Self {
712 self.insert(key).primitive(value);
713 self
714 }
715
716 pub fn pairs<'n, T: Primitive>(
718 &mut self,
719 pairs: impl IntoIterator<Item = (Name<'n>, T)>,
720 ) -> &mut Self {
721 for (key, value) in pairs {
722 self.pair(key, value);
723 }
724 self
725 }
726
727 #[inline]
729 pub fn typed<T>(self) -> TypedDict<'a, T> {
730 TypedDict::wrap(self)
731 }
732}
733
734impl Drop for Dict<'_> {
735 #[inline]
736 fn drop(&mut self) {
737 self.buf.limits.register_dict_entries(self.len as usize);
738
739 if self.len != 0 {
740 self.buf.push(b'\n');
741 for _ in 0..self.indent - 2 {
742 self.buf.push(b' ');
743 }
744 }
745 self.buf.extend(b">>");
746 if self.indirect {
747 self.buf.extend(b"\nendobj\n\n");
748 }
749 }
750}
751
752pub struct TypedDict<'a, T> {
754 dict: Dict<'a>,
755 phantom: PhantomData<fn() -> T>,
756}
757
758impl<'a, T> Writer<'a> for TypedDict<'a, T> {
759 fn start(obj: Obj<'a>) -> Self {
760 Self { dict: obj.dict(), phantom: PhantomData }
761 }
762}
763
764impl<'a, T> Rewrite<'a> for TypedDict<'_, T> {
765 type Output = TypedDict<'a, T>;
766}
767
768impl<'a, T> TypedDict<'a, T> {
769 #[inline]
771 pub fn wrap(dict: Dict<'a>) -> Self {
772 Self { dict, phantom: PhantomData }
773 }
774
775 #[inline]
777 pub fn len(&self) -> i32 {
778 self.dict.len()
779 }
780
781 #[inline]
783 pub fn is_empty(&self) -> bool {
784 self.len() == 0
785 }
786
787 #[inline]
789 pub fn pair(&mut self, key: Name, value: T) -> &mut Self
790 where
791 T: Primitive,
792 {
793 self.dict.pair(key, value);
794 self
795 }
796
797 #[inline]
799 pub fn pairs<'n>(
800 &mut self,
801 pairs: impl IntoIterator<Item = (Name<'n>, T)>,
802 ) -> &mut Self
803 where
804 T: Primitive,
805 {
806 self.dict.pairs(pairs);
807 self
808 }
809
810 #[inline]
814 pub fn insert<'b>(&'b mut self, key: Name) -> <T as Rewrite<'b>>::Output
815 where
816 T: Writer<'a> + Rewrite<'b>,
817 {
818 <T as Rewrite>::Output::start(self.dict.insert(key))
819 }
820}
821
822pub struct Stream<'a> {
824 dict: ManuallyDrop<Dict<'a>>,
825 data: &'a [u8],
826}
827
828impl<'a> Stream<'a> {
829 pub(crate) fn start(obj: Obj<'a>, data: &'a [u8]) -> Self {
834 assert!(obj.indirect);
835
836 let mut dict = obj.dict();
837 dict.pair(
838 Name(b"Length"),
839 i32::try_from(data.len()).unwrap_or_else(|_| {
840 panic!("data length (is `{}`) must be <= i32::MAX", data.len());
841 }),
842 );
843
844 Self { dict: ManuallyDrop::new(dict), data }
845 }
846
847 pub fn filter(&mut self, filter: Filter) -> &mut Self {
849 self.pair(Name(b"Filter"), filter.to_name());
850 self
851 }
852
853 pub fn decode_parms(&mut self) -> DecodeParms<'_> {
859 self.insert(Name(b"DecodeParms")).start()
860 }
861}
862
863impl Drop for Stream<'_> {
864 fn drop(&mut self) {
865 let dict_len = self.dict.len as usize;
866 self.dict.buf.limits.register_dict_entries(dict_len);
867
868 self.dict.buf.extend(b"\n>>");
869 self.dict.buf.extend(b"\nstream\n");
870 self.dict.buf.extend(self.data.as_ref());
871 self.dict.buf.extend(b"\nendstream");
872 self.dict.buf.extend(b"\nendobj\n\n");
873 }
874}
875
876deref!('a, Stream<'a> => Dict<'a>, dict);
877
878#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
880#[allow(missing_docs)]
881pub enum Filter {
882 AsciiHexDecode,
883 Ascii85Decode,
884 LzwDecode,
888 FlateDecode,
889 RunLengthDecode,
890 CcittFaxDecode,
891 Jbig2Decode,
892 DctDecode,
896 JpxDecode,
900 Crypt,
904}
905
906impl Filter {
907 pub(crate) fn to_name(self) -> Name<'static> {
908 match self {
909 Self::AsciiHexDecode => Name(b"ASCIIHexDecode"),
910 Self::Ascii85Decode => Name(b"ASCII85Decode"),
911 Self::LzwDecode => Name(b"LZWDecode"),
912 Self::FlateDecode => Name(b"FlateDecode"),
913 Self::RunLengthDecode => Name(b"RunLengthDecode"),
914 Self::CcittFaxDecode => Name(b"CCITTFaxDecode"),
915 Self::Jbig2Decode => Name(b"JBIG2Decode"),
916 Self::DctDecode => Name(b"DCTDecode"),
917 Self::JpxDecode => Name(b"JPXDecode"),
918 Self::Crypt => Name(b"Crypt"),
919 }
920 }
921}
922
923pub struct DecodeParms<'a> {
927 dict: Dict<'a>,
928}
929
930writer!(DecodeParms: |obj| Self { dict: obj.dict() });
931
932impl DecodeParms<'_> {
934 pub fn predictor(&mut self, predictor: Predictor) -> &mut Self {
938 self.pair(Name(b"Predictor"), predictor.to_i32());
939 self
940 }
941
942 pub fn colors(&mut self, colors: i32) -> &mut Self {
947 if colors <= 0 {
948 panic!("`Colors` must be greater than 0");
949 }
950
951 self.pair(Name(b"Colors"), colors);
952 self
953 }
954
955 pub fn bits_per_component(&mut self, bits: i32) -> &mut Self {
961 if ![1, 2, 4, 8, 16].contains(&bits) {
962 panic!("`BitsPerComponent` must be one of 1, 2, 4, 8, or 16");
963 }
964
965 self.pair(Name(b"BitsPerComponent"), bits);
966 self
967 }
968
969 pub fn columns(&mut self, columns: i32) -> &mut Self {
979 self.pair(Name(b"Columns"), columns);
980 self
981 }
982
983 pub fn early_change(&mut self, early_change: bool) -> &mut Self {
990 self.pair(Name(b"EarlyChange"), if early_change { 1 } else { 0 });
991 self
992 }
993}
994
995impl DecodeParms<'_> {
997 pub fn k(&mut self, k: i32) -> &mut Self {
1001 self.pair(Name(b"K"), k);
1002 self
1003 }
1004
1005 pub fn end_of_line(&mut self, eol: bool) -> &mut Self {
1010 self.pair(Name(b"EndOfLine"), eol);
1011 self
1012 }
1013
1014 pub fn encoded_byte_align(&mut self, encoded_byte_align: bool) -> &mut Self {
1019 self.pair(Name(b"EncodedByteAlign"), encoded_byte_align);
1020 self
1021 }
1022
1023 pub fn rows(&mut self, rows: i32) -> &mut Self {
1027 self.pair(Name(b"Rows"), rows);
1028 self
1029 }
1030
1031 pub fn end_of_block(&mut self, end_of_block: bool) -> &mut Self {
1036 self.pair(Name(b"EndOfBlock"), end_of_block);
1037 self
1038 }
1039
1040 pub fn black_is_1(&mut self, black_is_1: bool) -> &mut Self {
1044 self.pair(Name(b"BlackIs1"), black_is_1);
1045 self
1046 }
1047
1048 pub fn damaged_rows_before_error(&mut self, count: i32) -> &mut Self {
1053 self.pair(Name(b"DamagedRowsBeforeError"), count);
1054 self
1055 }
1056}
1057
1058impl DecodeParms<'_> {
1060 pub fn jbig2_globals(&mut self, globals: Ref) -> &mut Self {
1064 self.pair(Name(b"JBIG2Globals"), globals);
1065 self
1066 }
1067}
1068
1069impl DecodeParms<'_> {
1071 pub fn color_transform(&mut self, color_transform: bool) -> &mut Self {
1079 self.pair(Name(b"ColorTransform"), if color_transform { 1 } else { 0 });
1080 self
1081 }
1082}
1083
1084impl DecodeParms<'_> {
1086 pub fn crypt_type(&mut self) -> &mut Self {
1088 self.pair(Name(b"Type"), Name(b"CryptFilterDecodeParms"));
1089 self
1090 }
1091
1092 pub fn name(&mut self, name: Name) -> &mut Self {
1097 self.pair(Name(b"Name"), name);
1098 self
1099 }
1100}
1101
1102deref!('a, DecodeParms<'a> => Dict<'a>, dict);
1103
1104#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1106#[allow(missing_docs)]
1107pub enum Predictor {
1108 None,
1110 Tiff,
1112 PngNone,
1113 PngSub,
1114 PngUp,
1115 PngAverage,
1116 PngPaeth,
1117 PngOptimum,
1118}
1119
1120impl Predictor {
1121 fn to_i32(self) -> i32 {
1124 match self {
1125 Self::None => 1,
1126 Self::Tiff => 2,
1127 Self::PngNone => 10,
1128 Self::PngSub => 11,
1129 Self::PngUp => 12,
1130 Self::PngAverage => 13,
1131 Self::PngPaeth => 14,
1132 Self::PngOptimum => 15,
1133 }
1134 }
1135}
1136
1137pub struct NameTree<'a, T> {
1147 dict: Dict<'a>,
1148 phantom: PhantomData<T>,
1149}
1150
1151impl<'a, T> Writer<'a> for NameTree<'a, T> {
1152 fn start(obj: Obj<'a>) -> Self {
1153 Self { dict: obj.dict(), phantom: PhantomData }
1154 }
1155}
1156
1157impl<'a, T> Rewrite<'a> for NameTree<'_, T> {
1158 type Output = NameTree<'a, T>;
1159}
1160
1161impl<T> NameTree<'_, T> {
1162 pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1164 self.dict.insert(Name(b"Kids")).array().typed()
1165 }
1166
1167 pub fn names(&mut self) -> NameTreeEntries<'_, T> {
1170 self.dict.insert(Name(b"Names")).start()
1171 }
1172
1173 pub fn limits(&mut self, min: Name, max: Name) -> &mut Self {
1176 self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1177 self
1178 }
1179}
1180
1181pub struct NameTreeEntries<'a, T> {
1187 arr: Array<'a>,
1188 phantom: PhantomData<T>,
1189}
1190
1191impl<'a, T> Writer<'a> for NameTreeEntries<'a, T> {
1192 fn start(obj: Obj<'a>) -> Self {
1193 Self { arr: obj.array(), phantom: PhantomData }
1194 }
1195}
1196
1197impl<'a, T> Rewrite<'a> for NameTreeEntries<'_, T> {
1198 type Output = NameTreeEntries<'a, T>;
1199}
1200
1201impl<T> NameTreeEntries<'_, T>
1202where
1203 T: Primitive,
1204{
1205 pub fn insert(&mut self, key: Str, value: T) -> &mut Self {
1207 self.arr.item(key);
1208 self.arr.item(value);
1209 self
1210 }
1211}
1212
1213pub struct NumberTree<'a, T> {
1223 dict: Dict<'a>,
1224 phantom: PhantomData<T>,
1225}
1226
1227impl<'a, T> Writer<'a> for NumberTree<'a, T> {
1228 fn start(obj: Obj<'a>) -> Self {
1229 Self { dict: obj.dict(), phantom: PhantomData }
1230 }
1231}
1232
1233impl<'a, T> Rewrite<'a> for NumberTree<'_, T> {
1234 type Output = NumberTree<'a, T>;
1235}
1236
1237impl<T> NumberTree<'_, T> {
1238 pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1240 self.dict.insert(Name(b"Kids")).array().typed()
1241 }
1242
1243 pub fn nums(&mut self) -> NumberTreeEntries<'_, T> {
1246 self.dict.insert(Name(b"Nums")).start()
1247 }
1248
1249 pub fn limits(&mut self, min: i32, max: i32) -> &mut Self {
1252 self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1253 self
1254 }
1255}
1256
1257pub struct NumberTreeEntries<'a, T> {
1263 arr: Array<'a>,
1264 phantom: PhantomData<T>,
1265}
1266
1267impl<'a, T> Writer<'a> for NumberTreeEntries<'a, T> {
1268 fn start(obj: Obj<'a>) -> Self {
1269 Self { arr: obj.array(), phantom: PhantomData }
1270 }
1271}
1272
1273impl<'a, T> Rewrite<'a> for NumberTreeEntries<'_, T> {
1274 type Output = NumberTreeEntries<'a, T>;
1275}
1276
1277impl<T> NumberTreeEntries<'_, T>
1278where
1279 T: Primitive,
1280{
1281 pub fn insert(&mut self, key: i32, value: T) -> &mut Self {
1283 self.arr.item(key);
1284 self.arr.item(value);
1285 self
1286 }
1287}
1288
1289pub trait Finish: Sized {
1310 #[inline]
1312 fn finish(self) {}
1313}
1314
1315impl<T> Finish for T {}
1316
1317#[cfg(test)]
1318mod tests {
1319 use super::*;
1320
1321 #[test]
1322 fn test_primitive_objects() {
1323 test_primitive!(true, b"true");
1325 test_primitive!(false, b"false");
1326 test_primitive!(78, b"78");
1327 test_primitive!(4.22, b"4.22");
1328 test_primitive!(1.184e-7, b"0.0000001184");
1329 test_primitive!(4.2e13, b"42000000000000");
1330 test_primitive!(Ref::new(7), b"7 0 R");
1331 test_primitive!(Null, b"null");
1332
1333 test_primitive!(Str(b"Hello, World!"), b"(Hello, World!)");
1335 test_primitive!(Str(b"()"), br"(())");
1336 test_primitive!(Str(b")()"), br"(\)\(\))");
1337 test_primitive!(Str(b"()(())"), br"(()(()))");
1338 test_primitive!(Str(b"(()))"), br"(\(\(\)\)\))");
1339 test_primitive!(Str(b"\\"), br"(\\)");
1340 test_primitive!(Str(b"\n\ta"), br"(\n\ta)");
1341 test_primitive!(Str(br"\n"), br"(\\n)");
1342 test_primitive!(Str(b"a\x14b"), br"(a\024b)");
1343 test_primitive!(Str(b"\xFF\xAA"), b"<FFAA>");
1344 test_primitive!(Str(b"\x0A\x7F\x1F"), br"(\n\177\037)");
1345
1346 test_primitive!(TextStr("Hallo"), b"(Hallo)");
1348 test_primitive!(TextStr("😀!"), b"<FEFFD83DDE000021>");
1349
1350 test_primitive!(Name(b"Filter"), b"/Filter");
1352 test_primitive!(Name(b"A B"), br"/A#20B");
1353 test_primitive!(Name(b"~+c"), br"/~+c");
1354 test_primitive!(Name(b"/A-B"), br"/#2FA-B");
1355 test_primitive!(Name(b"<A>"), br"/#3CA#3E");
1356 test_primitive!(Name(b"#"), br"/#23");
1357 test_primitive!(Name(b"\n"), br"/#0A");
1358 }
1359
1360 #[test]
1361 fn test_dates() {
1362 test_primitive!(Date::new(2021), b"(D:2021)");
1363 test_primitive!(Date::new(2021).month(30), b"(D:202112)");
1364
1365 let date = Date::new(2020).month(3).day(17).hour(1).minute(2).second(3);
1366 test_primitive!(date, b"(D:20200317010203)");
1367 test_primitive!(date.utc_offset_hour(0), b"(D:20200317010203Z)");
1368 test_primitive!(date.utc_offset_hour(4), b"(D:20200317010203+04'00)");
1369 test_primitive!(
1370 date.utc_offset_hour(-17).utc_offset_minute(10),
1371 b"(D:20200317010203-17'10)"
1372 );
1373 }
1374
1375 #[test]
1376 fn test_arrays() {
1377 test_obj!(|obj| obj.array(), b"[]");
1378 test_obj!(|obj| obj.array().item(12).item(Null), b"[12 null]");
1379 test_obj!(|obj| obj.array().typed().items(vec![1, 2, 3]), b"[1 2 3]");
1380 test_obj!(
1381 |obj| {
1382 let mut array = obj.array();
1383 array.push().array().typed().items(vec![1, 2]);
1384 array.item(3);
1385 },
1386 b"[[1 2] 3]",
1387 );
1388 }
1389
1390 #[test]
1391 fn test_dicts() {
1392 test_obj!(|obj| obj.dict(), b"<<>>");
1393 test_obj!(
1394 |obj| obj.dict().pair(Name(b"Quality"), Name(b"Good")),
1395 b"<<\n /Quality /Good\n>>",
1396 );
1397 test_obj!(
1398 |obj| {
1399 obj.dict().pair(Name(b"A"), 1).pair(Name(b"B"), 2);
1400 },
1401 b"<<\n /A 1\n /B 2\n>>",
1402 );
1403 }
1404
1405 #[test]
1406 fn test_streams() {
1407 let mut w = Pdf::new();
1408 w.stream(Ref::new(1), &b"Hi there!"[..]).filter(Filter::Crypt);
1409 test!(
1410 w.finish(),
1411 b"%PDF-1.7\n%\x80\x80\x80\x80\n",
1412 b"1 0 obj",
1413 b"<<\n /Length 9\n /Filter /Crypt\n>>",
1414 b"stream",
1415 b"Hi there!",
1416 b"endstream",
1417 b"endobj\n",
1418 b"xref",
1419 b"0 2",
1420 b"0000000000 65535 f\r",
1421 b"0000000016 00000 n\r",
1422 b"trailer",
1423 b"<<\n /Size 2\n>>",
1424 b"startxref\n94\n%%EOF",
1425 )
1426 }
1427}