Skip to main content

pdf_writer/
object.rs

1use std::convert::TryFrom;
2use std::marker::PhantomData;
3use std::mem::ManuallyDrop;
4use std::num::NonZeroI32;
5
6use super::*;
7use crate::chunk::Settings;
8use crate::object::sealed::Sealed;
9
10mod sealed {
11    use crate::Buf;
12
13    pub trait Sealed {
14        /// Whether the primitive object starts with one of the PDF delimiter characters.
15        const STARTS_WITH_DELIMITER: bool;
16
17        /// Write the object into a buffer.
18        fn write(self, buf: &mut Buf);
19    }
20}
21
22/// A primitive PDF object.
23pub trait Primitive: Sealed {}
24
25impl<T: Sealed> Sealed for &T
26where
27    T: Copy,
28{
29    const STARTS_WITH_DELIMITER: bool = T::STARTS_WITH_DELIMITER;
30
31    #[inline]
32    fn write(self, buf: &mut Buf) {
33        (*self).write(buf);
34    }
35}
36
37impl<T: Primitive> Primitive for &T where T: Copy {}
38
39impl Sealed for bool {
40    const STARTS_WITH_DELIMITER: bool = false;
41
42    #[inline]
43    fn write(self, buf: &mut Buf) {
44        if self {
45            buf.extend(b"true");
46        } else {
47            buf.extend(b"false");
48        }
49    }
50}
51
52impl Primitive for bool {}
53
54impl Sealed for i32 {
55    const STARTS_WITH_DELIMITER: bool = false;
56
57    #[inline]
58    fn write(self, buf: &mut Buf) {
59        buf.push_int(self);
60    }
61}
62
63impl Primitive for i32 {}
64
65impl Sealed for f32 {
66    const STARTS_WITH_DELIMITER: bool = false;
67
68    #[inline]
69    fn write(self, buf: &mut Buf) {
70        buf.push_float(self);
71    }
72}
73
74impl Primitive for f32 {}
75
76/// A string object (any byte sequence).
77///
78/// This is written as `(Thing)`.
79#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
80pub struct Str<'a>(pub &'a [u8]);
81
82impl Str<'_> {
83    /// Whether the parentheses in the byte string are balanced.
84    fn is_balanced(self) -> bool {
85        let mut depth = 0;
86        for &byte in self.0 {
87            match byte {
88                b'(' => depth += 1,
89                b')' if depth > 0 => depth -= 1,
90                b')' => return false,
91                _ => {}
92            }
93        }
94        depth == 0
95    }
96}
97
98impl Sealed for Str<'_> {
99    const STARTS_WITH_DELIMITER: bool = true;
100
101    fn write(self, buf: &mut Buf) {
102        buf.limits.register_str_len(self.0.len());
103
104        // We use:
105        // - Literal strings for ASCII with nice escape sequences to make it
106        //   also be represented fully in visible ASCII. We also escape
107        //   parentheses because they are delimiters.
108        // - Hex strings for anything non-ASCII.
109        if self.0.iter().all(|b| b.is_ascii()) {
110            buf.reserve(self.0.len());
111            buf.inner.push(b'(');
112
113            let mut balanced = None;
114            for &byte in self.0 {
115                match byte {
116                    b'(' | b')' => {
117                        if !*balanced
118                            .get_or_insert_with(|| byte != b')' && self.is_balanced())
119                        {
120                            buf.push(b'\\');
121                        }
122                        buf.push(byte);
123                    }
124                    b'\\' => buf.extend(br"\\"),
125                    b' '..=b'~' => buf.push(byte),
126                    b'\n' => buf.extend(br"\n"),
127                    b'\r' => buf.extend(br"\r"),
128                    b'\t' => buf.extend(br"\t"),
129                    b'\x08' => buf.extend(br"\b"),
130                    b'\x0c' => buf.extend(br"\f"),
131                    _ => {
132                        buf.push(b'\\');
133                        buf.push_octal(byte);
134                    }
135                }
136            }
137
138            buf.push(b')');
139        } else {
140            buf.reserve(2 + 2 * self.0.len());
141            buf.push(b'<');
142
143            for &byte in self.0 {
144                buf.push_hex(byte);
145            }
146
147            buf.push(b'>');
148        }
149    }
150}
151
152impl Primitive for Str<'_> {}
153
154/// A unicode text string object.
155///
156/// This is written as a [`Str`] containing either bare ASCII (if possible) or a
157/// byte order mark followed by UTF-16-BE bytes.
158///
159/// The natural language is inherited from the document catalog's
160/// [`/Lang` key](crate::Catalog::lang). If you need to specify another language
161/// or if the string contains multiple natural languages, see
162/// [`TextStrWithLang`].
163#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
164pub struct TextStr<'a>(pub &'a str);
165
166impl Sealed for TextStr<'_> {
167    const STARTS_WITH_DELIMITER: bool = true;
168
169    fn write(self, buf: &mut Buf) {
170        buf.limits.register_str_len(self.0.len());
171
172        // ASCII and PDFDocEncoding match for 32 up to 126.
173        if self.0.bytes().all(|b| matches!(b, 32..=126)) {
174            Str(self.0.as_bytes()).write(buf);
175        } else {
176            buf.reserve(6 + 4 * self.0.len());
177            write_utf16be_text_str_header(buf);
178            for value in self.0.encode_utf16() {
179                buf.push_hex_u16(value);
180            }
181            write_utf16be_text_str_footer(buf);
182        }
183    }
184}
185
186impl Primitive for TextStr<'_> {}
187
188/// An identifier for the natural language in a section of a
189/// [`TextStrWithLang`].
190#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
191pub struct LanguageIdentifier {
192    /// A two-byte ISO 639 language code.
193    lang: [u8; 2],
194    /// A two-byte ISO 3166 country code.
195    region: Option<[u8; 2]>,
196}
197
198impl LanguageIdentifier {
199    /// Create a new language identifier.
200    ///
201    /// Language and region codes are not checked for validity.
202    pub fn new(lang: [u8; 2], region: Option<[u8; 2]>) -> Self {
203        Self { lang, region }
204    }
205
206    /// Create a new language identifier from a language, with an unset region.
207    ///
208    /// The method returns `Some` if the argument has two alphanumeric ASCII
209    /// bytes.
210    pub fn from_lang(lang: &str) -> Option<Self> {
211        let lang = Self::str_to_code(lang)?;
212        Some(Self::new(lang, None))
213    }
214
215    /// Create a new language identifier from a language and a region
216    ///
217    /// The method returns `Some` if both arguments have two alphanumeric ASCII
218    /// bytes.
219    pub fn from_lang_region(lang: &str, region: &str) -> Option<Self> {
220        let lang = Self::str_to_code(lang)?;
221        let region = Self::str_to_code(region)?;
222        Some(Self::new(lang, Some(region)))
223    }
224
225    /// Returns the length of the language identifier. It does not include the
226    /// enclosing escape bytes.
227    fn len(self) -> usize {
228        if self.region.is_some() {
229            4
230        } else {
231            2
232        }
233    }
234
235    fn str_to_code(string: &str) -> Option<[u8; 2]> {
236        if string.chars().all(|c| c.is_ascii_alphanumeric()) {
237            string.as_bytes().try_into().ok()
238        } else {
239            None
240        }
241    }
242}
243
244/// A text string with a natural language specified.
245///
246///
247/// This is written as a string containing either bare ASCII (if possible) or a
248/// byte order mark followed by UTF-16-BE bytes. Both forms are interspersed by
249/// the requisite ASCII language escape sequences.
250///
251/// For a text string with an undefined natural language, see [`TextStr`].
252#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
253pub struct TextStrWithLang<'a, 'b>(pub &'b [(LanguageIdentifier, &'a str)]);
254
255impl<'a, 'b> Sealed for TextStrWithLang<'a, 'b> {
256    const STARTS_WITH_DELIMITER: bool = true;
257
258    fn write(self, buf: &mut Buf) {
259        let mut len = 0;
260        let mut buf_len = 6;
261
262        for (lang, text) in self.0 {
263            // Each language tag is enclosed in two escape characters, plus the
264            // two-letter language code and optional two-letter region code.
265            len += text.len() + lang.len() + 2;
266            // Each hexadecimal character is four bytes long, plus four bytes
267            // for the escape sequence. The language tag is encoded in
268            // hexadecimal, so each byte becomes two hexadecimal characters.
269            buf_len += 4 * text.len() + lang.len() * 2 + 4;
270        }
271
272        buf.limits.register_str_len(len);
273
274        // Escape sequences for languages may only appear in Unicode-encoded
275        // text strings, see clause 7.9.2.2 of ISO 32000-1:2008.
276        buf.reserve(buf_len);
277        write_utf16be_text_str_header(buf);
278
279        for (lang, text) in self.0 {
280            write_utf16be_lang_code(*lang, buf);
281            for value in text.encode_utf16() {
282                buf.push_hex_u16(value);
283            }
284        }
285
286        write_utf16be_text_str_footer(buf);
287    }
288}
289
290impl Primitive for TextStrWithLang<'_, '_> {}
291
292fn write_utf16be_text_str_header(buf: &mut Buf) {
293    buf.push(b'<');
294    buf.push_hex(254);
295    buf.push_hex(255);
296}
297
298fn write_utf16be_text_str_footer(buf: &mut Buf) {
299    buf.push(b'>');
300}
301
302fn write_utf16be_lang_code(lang: LanguageIdentifier, buf: &mut Buf) {
303    // The escape character U+001B encloses the language tag. It must not
304    // otherwise appear in a text string and the spec offers no opportunity to
305    // escape it. In the future, `pdf-writer` may offer a constructor for
306    // [`TextStrWithLang`] and [`TextStr`] that either checks for it or replaces
307    // it with the object replacement character U+FFFD.
308    buf.push_hex_u16(0x001B);
309    buf.push_hex_u16(u16::from(lang.lang[0]));
310    buf.push_hex_u16(u16::from(lang.lang[1]));
311    if let Some(region) = lang.region {
312        buf.push_hex_u16(u16::from(region[0]));
313        buf.push_hex_u16(u16::from(region[1]));
314    }
315    buf.push_hex_u16(0x001B);
316}
317
318/// A trait for types that can be used everywhere a text string is expected.
319/// This includes both [`TextStr`] and [`TextStrWithLang`].
320///
321/// Methods that accept an implementor of this trait expect strings in natural
322/// language for which a language specification makes sense, often for use in
323/// the UI or with AT.
324pub trait TextStrLike: Primitive {}
325
326impl<'a> TextStrLike for TextStr<'a> {}
327impl<'a, 'b> TextStrLike for TextStrWithLang<'a, 'b> {}
328
329/// A name object.
330///
331/// Written as `/Thing`.
332#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
333pub struct Name<'a>(pub &'a [u8]);
334
335impl Sealed for Name<'_> {
336    const STARTS_WITH_DELIMITER: bool = true;
337
338    fn write(self, buf: &mut Buf) {
339        buf.limits.register_name_len(self.0.len());
340
341        buf.reserve(1 + self.0.len());
342        buf.push(b'/');
343        for &byte in self.0 {
344            // - Number sign shall use hexadecimal escape
345            // - Regular characters within the range exlacamation mark .. tilde
346            //   can be written directly
347            if byte != b'#' && matches!(byte, b'!'..=b'~') && is_regular_character(byte) {
348                buf.push(byte);
349            } else {
350                buf.push(b'#');
351                buf.push_hex(byte);
352            }
353        }
354    }
355}
356
357impl Primitive for Name<'_> {}
358
359/// Regular characters are a PDF concept.
360fn is_regular_character(byte: u8) -> bool {
361    !matches!(
362        byte,
363        b'\0'
364            | b'\t'
365            | b'\n'
366            | b'\x0C'
367            | b'\r'
368            | b' '
369            | b'('
370            | b')'
371            | b'<'
372            | b'>'
373            | b'['
374            | b']'
375            | b'{'
376            | b'}'
377            | b'/'
378            | b'%'
379    )
380}
381
382#[inline]
383pub(crate) fn is_delimiter_character(byte: u8) -> bool {
384    matches!(byte, b'(' | b')' | b'<' | b'>' | b'[' | b']' | b'/' | b'%')
385}
386
387/// The null object.
388#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
389pub struct Null;
390
391impl Sealed for Null {
392    const STARTS_WITH_DELIMITER: bool = false;
393
394    #[inline]
395    fn write(self, buf: &mut Buf) {
396        buf.extend(b"null");
397    }
398}
399
400impl Primitive for Null {}
401
402/// A reference to an indirect object.
403#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
404pub struct Ref(NonZeroI32);
405
406impl Ref {
407    /// Create a new indirect reference.
408    ///
409    /// The provided value must be greater than zero.
410    ///
411    /// Panics if `id` is out of the valid range.
412    #[inline]
413    #[track_caller]
414    pub const fn new(id: i32) -> Ref {
415        let option = if id > 0 { NonZeroI32::new(id) } else { None };
416        match option {
417            Some(val) => Self(val),
418            None => panic!("indirect reference out of valid range"),
419        }
420    }
421
422    /// Return the underlying number as a primitive type.
423    #[inline]
424    pub const fn get(self) -> i32 {
425        self.0.get()
426    }
427
428    /// The next consecutive ID.
429    #[inline]
430    pub const fn next(self) -> Self {
431        Self::new(self.get() + 1)
432    }
433
434    /// Increase this ID by one and return the old one. Useful to turn this ID
435    /// into a bump allocator of sorts.
436    #[inline]
437    pub fn bump(&mut self) -> Self {
438        let prev = *self;
439        *self = self.next();
440        prev
441    }
442}
443
444impl Sealed for Ref {
445    const STARTS_WITH_DELIMITER: bool = false;
446
447    #[inline]
448    fn write(self, buf: &mut Buf) {
449        buf.push_int(self.0.get());
450        buf.extend(b" 0 R");
451    }
452}
453
454impl Primitive for Ref {}
455
456/// A rectangle, specified by two opposite corners.
457#[derive(Debug, Copy, Clone, PartialEq)]
458pub struct Rect {
459    /// The x-coordinate of the first (typically, lower-left) corner.
460    pub x1: f32,
461    /// The y-coordinate of the first (typically, lower-left) corner.
462    pub y1: f32,
463    /// The x-coordinate of the second (typically, upper-right) corner.
464    pub x2: f32,
465    /// The y-coordinate of the second (typically, upper-right) corner.
466    pub y2: f32,
467}
468
469impl Rect {
470    /// Create a new rectangle from four coordinate values.
471    #[inline]
472    pub fn new(x1: f32, y1: f32, x2: f32, y2: f32) -> Self {
473        Self { x1, y1, x2, y2 }
474    }
475
476    /// Convert this rectangle into 8 floats describing the four corners of the
477    /// rectangle in counterclockwise order.
478    #[inline]
479    pub fn to_quad_points(self) -> [f32; 8] {
480        [self.x1, self.y1, self.x2, self.y1, self.x2, self.y2, self.x1, self.y2]
481    }
482}
483
484impl Sealed for Rect {
485    const STARTS_WITH_DELIMITER: bool = true;
486
487    #[inline]
488    fn write(self, buf: &mut Buf) {
489        buf.push(b'[');
490        buf.push_val(self.x1);
491        buf.push(b' ');
492        buf.push_val(self.y1);
493        buf.push(b' ');
494        buf.push_val(self.x2);
495        buf.push(b' ');
496        buf.push_val(self.y2);
497        buf.push(b']');
498
499        buf.limits.register_array_len(4);
500    }
501}
502
503impl Primitive for Rect {}
504
505/// A date, written as a text string.
506///
507/// A field is only respected if all superior fields are supplied. For example,
508/// to set the minute, the hour, day, etc. have to be set. Similarly, in order
509/// for the time zone information to be written, all time information (including
510/// seconds) must be written. `utc_offset_minute` is optional if supplying time
511/// zone info. It must only be used to specify sub-hour time zone offsets.
512#[derive(Debug, Copy, Clone, Eq, PartialEq)]
513pub struct Date {
514    /// The year (0-9999).
515    year: u16,
516    /// The month (0-11).
517    month: Option<u8>,
518    /// The month (0-30).
519    day: Option<u8>,
520    /// The hour (0-23).
521    hour: Option<u8>,
522    /// The minute (0-59).
523    minute: Option<u8>,
524    /// The second (0-59).
525    second: Option<u8>,
526    /// The hour offset from UTC (-23 through 23).
527    utc_offset_hour: Option<i8>,
528    /// The minute offset from UTC (0-59). Will carry over the sign from
529    /// `utc_offset_hour`.
530    utc_offset_minute: u8,
531}
532
533impl Date {
534    /// Create a new, minimal date. The year will be clamped within the range
535    /// 0-9999.
536    #[inline]
537    pub fn new(year: u16) -> Self {
538        Self {
539            year: year.min(9999),
540            month: None,
541            day: None,
542            hour: None,
543            minute: None,
544            second: None,
545            utc_offset_hour: None,
546            utc_offset_minute: 0,
547        }
548    }
549
550    /// Add the month field. It will be clamped within the range 1-12.
551    #[inline]
552    pub fn month(mut self, month: u8) -> Self {
553        self.month = Some(month.clamp(1, 12));
554        self
555    }
556
557    /// Add the day field. It will be clamped within the range 1-31.
558    #[inline]
559    pub fn day(mut self, day: u8) -> Self {
560        self.day = Some(day.clamp(1, 31));
561        self
562    }
563
564    /// Add the hour field. It will be clamped within the range 0-23.
565    #[inline]
566    pub fn hour(mut self, hour: u8) -> Self {
567        self.hour = Some(hour.min(23));
568        self
569    }
570
571    /// Add the minute field. It will be clamped within the range 0-59.
572    #[inline]
573    pub fn minute(mut self, minute: u8) -> Self {
574        self.minute = Some(minute.min(59));
575        self
576    }
577
578    /// Add the second field. It will be clamped within the range 0-59.
579    #[inline]
580    pub fn second(mut self, second: u8) -> Self {
581        self.second = Some(second.min(59));
582        self
583    }
584
585    /// Add the offset from UTC in hours. If not specified, the time will be
586    /// assumed to be local to the viewer's time zone. It will be clamped within
587    /// the range -23-23.
588    #[inline]
589    pub fn utc_offset_hour(mut self, hour: i8) -> Self {
590        self.utc_offset_hour = Some(hour.clamp(-23, 23));
591        self
592    }
593
594    /// Add the offset from UTC in minutes. This will have the same sign as set in
595    /// [`Self::utc_offset_hour`]. It will be clamped within the range 0-59.
596    #[inline]
597    pub fn utc_offset_minute(mut self, minute: u8) -> Self {
598        self.utc_offset_minute = minute.min(59);
599        self
600    }
601}
602
603impl Sealed for Date {
604    const STARTS_WITH_DELIMITER: bool = true;
605
606    fn write(self, buf: &mut Buf) {
607        buf.extend(b"(D:");
608
609        (|| {
610            write!(buf.inner, "{:04}", self.year).unwrap();
611            write!(buf.inner, "{:02}", self.month?).unwrap();
612            write!(buf.inner, "{:02}", self.day?).unwrap();
613            write!(buf.inner, "{:02}", self.hour?).unwrap();
614            write!(buf.inner, "{:02}", self.minute?).unwrap();
615            write!(buf.inner, "{:02}", self.second?).unwrap();
616            let utc_offset_hour = self.utc_offset_hour?;
617            if utc_offset_hour == 0 && self.utc_offset_minute == 0 {
618                buf.push(b'Z');
619            } else {
620                write!(
621                    buf.inner,
622                    "{:+03}'{:02}",
623                    utc_offset_hour, self.utc_offset_minute
624                )
625                .unwrap();
626            }
627            Some(())
628        })();
629
630        buf.push(b')');
631    }
632}
633
634impl Primitive for Date {}
635
636/// Writer for an arbitrary object.
637#[must_use = "not consuming this leaves the writer in an inconsistent state"]
638pub struct Obj<'a> {
639    buf: &'a mut Buf,
640    indirect: bool,
641    indent: u8,
642    settings: Settings,
643    needs_padding: bool,
644}
645
646impl<'a> Obj<'a> {
647    /// Start a new direct object.
648    #[inline]
649    pub(crate) fn direct(
650        buf: &'a mut Buf,
651        indent: u8,
652        settings: Settings,
653        needs_padding: bool,
654    ) -> Self {
655        Self {
656            buf,
657            indirect: false,
658            indent,
659            settings,
660            needs_padding,
661        }
662    }
663
664    /// Start a new indirect object.
665    #[inline]
666    pub(crate) fn indirect(buf: &'a mut Buf, id: Ref, settings: Settings) -> Self {
667        buf.push_int(id.get());
668        buf.extend(b" 0 obj\n");
669        Self {
670            buf,
671            indirect: true,
672            indent: 0,
673            settings,
674            needs_padding: false,
675        }
676    }
677
678    /// Write a primitive object.
679    #[inline]
680    pub fn primitive<T: Primitive>(self, value: T) {
681        // Usually, we need to separate different PDF objects by a whitespace.
682        // The key to the optimizations applied here are explained in 7.2.3 in
683        // the PDF reference:
684        //
685        // > The delimiter characters (, ), <, >, [, ], /, and % are special.
686        // > They delimit syntactic entities such as arrays, names, and
687        // > comments. Any of these delimiters terminates the entity preceding
688        // > it and is not included in the entity.
689        //
690        // Therefore, if either the previous byte is a delimiter character or
691        // the current token starts with one, we don't need to add a whitespace
692        // for padding.
693
694        let ends_with_delimiter =
695            self.buf.last().copied().is_some_and(is_delimiter_character);
696
697        if self.needs_padding && !T::STARTS_WITH_DELIMITER && !ends_with_delimiter {
698            self.buf.extend(b" ");
699        }
700
701        value.write(self.buf);
702
703        if self.indirect {
704            self.buf.extend(b"\nendobj\n");
705
706            if self.settings.pretty {
707                self.buf.extend(b"\n");
708            }
709        }
710    }
711
712    // Note: Arrays and dictionaries always start with a delimiter, so we don't
713    // need to do any case distinction, unlike in `primitive`.
714
715    /// Start writing an array.
716    #[inline]
717    pub fn array(self) -> Array<'a> {
718        self.start()
719    }
720
721    /// Start writing a dictionary.
722    #[inline]
723    pub fn dict(self) -> Dict<'a> {
724        self.start()
725    }
726
727    /// Start writing with an arbitrary writer.
728    ///
729    /// For example, using this, you could write a Type 1 font directly into
730    /// a page's resource directionary.
731    /// ```
732    /// use pdf_writer::{Pdf, Ref, Name, writers::Type1Font};
733    ///
734    /// let mut pdf = Pdf::new();
735    /// pdf.page(Ref::new(1))
736    ///     .resources()
737    ///     .fonts()
738    ///     .insert(Name(b"F1"))
739    ///     .start::<Type1Font>()
740    ///     .base_font(Name(b"Helvetica"));
741    /// ```
742    #[inline]
743    pub fn start<W: Writer<'a>>(self) -> W {
744        W::start(self)
745    }
746}
747
748/// A writer for a specific type of PDF object.
749pub trait Writer<'a> {
750    /// Start writing the object.
751    fn start(obj: Obj<'a>) -> Self;
752}
753
754/// Rewrites a writer's lifetime.
755///
756/// This is a workaround to ignore the `'b` lifetime in a
757/// `TypedArray<'a, SomeWriter<'b>>` because that lifetime is meaningless. What
758/// we actually want is each item's `SomeWriter` to borrow from the array itself.
759pub trait Rewrite<'a> {
760    /// The writer with the rewritten lifetime.
761    type Output: Writer<'a>;
762}
763
764/// Writer for an array.
765pub struct Array<'a> {
766    buf: &'a mut Buf,
767    indirect: bool,
768    indent: u8,
769    settings: Settings,
770    len: i32,
771}
772
773writer!(Array: |obj| {
774    obj.buf.push(b'[');
775    Self {
776        buf: obj.buf,
777        indirect: obj.indirect,
778        indent: obj.indent,
779        settings: obj.settings,
780        len: 0,
781    }
782});
783
784impl<'a> Array<'a> {
785    /// The number of written items.
786    #[inline]
787    pub fn len(&self) -> i32 {
788        self.len
789    }
790
791    /// Whether no items have been written so far.
792    #[inline]
793    pub fn is_empty(&self) -> bool {
794        self.len == 0
795    }
796
797    /// Start writing an arbitrary item.
798    #[inline]
799    pub fn push(&mut self) -> Obj<'_> {
800        let needs_padding = if self.len != 0 {
801            if self.settings.pretty {
802                self.buf.push(b' ');
803                false
804            } else {
805                true
806            }
807        } else {
808            false
809        };
810
811        self.len += 1;
812
813        Obj::direct(self.buf, self.indent, self.settings, needs_padding)
814    }
815
816    /// Write an item with a primitive value.
817    ///
818    /// This is a shorthand for `array.push().primitive(value)`.
819    #[inline]
820    pub fn item<T: Primitive>(&mut self, value: T) -> &mut Self {
821        self.push().primitive(value);
822        self
823    }
824
825    /// Write a sequence of items with primitive values.
826    #[inline]
827    pub fn items<T: Primitive>(
828        &mut self,
829        values: impl IntoIterator<Item = T>,
830    ) -> &mut Self {
831        for value in values {
832            self.item(value);
833        }
834        self
835    }
836
837    /// Convert into a typed version.
838    #[inline]
839    pub fn typed<T>(self) -> TypedArray<'a, T> {
840        TypedArray::wrap(self)
841    }
842}
843
844impl Drop for Array<'_> {
845    #[inline]
846    fn drop(&mut self) {
847        self.buf.limits.register_array_len(self.len() as usize);
848        self.buf.push(b']');
849        if self.indirect {
850            self.buf.extend(b"\nendobj\n");
851
852            if self.settings.pretty {
853                self.buf.extend(b"\n");
854            }
855        }
856    }
857}
858
859/// Writer for an array of items of a fixed type.
860pub struct TypedArray<'a, T> {
861    array: Array<'a>,
862    phantom: PhantomData<fn() -> T>,
863}
864
865impl<'a, T> Writer<'a> for TypedArray<'a, T> {
866    fn start(obj: Obj<'a>) -> Self {
867        Self { array: obj.array(), phantom: PhantomData }
868    }
869}
870
871impl<'a, T> Rewrite<'a> for TypedArray<'_, T> {
872    type Output = TypedArray<'a, T>;
873}
874
875impl<'a, T> TypedArray<'a, T> {
876    /// Wrap an array to make it type-safe.
877    #[inline]
878    pub fn wrap(array: Array<'a>) -> Self {
879        Self { array, phantom: PhantomData }
880    }
881
882    /// The number of written items.
883    #[inline]
884    pub fn len(&self) -> i32 {
885        self.array.len()
886    }
887
888    /// Whether no items have been written so far.
889    #[inline]
890    pub fn is_empty(&self) -> bool {
891        self.len() == 0
892    }
893
894    /// Write an item.
895    #[inline]
896    pub fn item(&mut self, value: T) -> &mut Self
897    where
898        T: Primitive,
899    {
900        self.array.item(value);
901        self
902    }
903
904    /// Write a sequence of items.
905    #[inline]
906    pub fn items(&mut self, values: impl IntoIterator<Item = T>) -> &mut Self
907    where
908        T: Primitive,
909    {
910        self.array.items(values);
911        self
912    }
913
914    /// Start writing an item with the typed writer.
915    ///
916    /// Returns `T` but with its lifetime rewritten from `'a` to `'b`.
917    #[inline]
918    pub fn push<'b>(&'b mut self) -> <T as Rewrite<'b>>::Output
919    where
920        T: Writer<'a> + Rewrite<'b>,
921    {
922        <T as Rewrite>::Output::start(self.array.push())
923    }
924}
925
926/// Writer for a dictionary.
927pub struct Dict<'a> {
928    buf: &'a mut Buf,
929    indirect: bool,
930    indent: u8,
931    settings: Settings,
932    len: i32,
933}
934
935writer!(Dict: |obj| {
936    obj.buf.extend(b"<<");
937    Self {
938        buf: obj.buf,
939        indirect: obj.indirect,
940        indent: obj.indent.saturating_add(2),
941        settings: obj.settings,
942        len: 0,
943    }
944});
945
946impl<'a> Dict<'a> {
947    /// The number of written pairs.
948    #[inline]
949    pub fn len(&self) -> i32 {
950        self.len
951    }
952
953    /// Whether no pairs have been written so far.
954    #[inline]
955    pub fn is_empty(&self) -> bool {
956        self.len == 0
957    }
958
959    /// Start writing a pair with an arbitrary value.
960    #[inline]
961    pub fn insert(&mut self, key: Name) -> Obj<'_> {
962        self.len += 1;
963
964        // Keys always start with a delimiter since they are names, so we never need
965        // padding unless `pretty` is activated.
966        if self.settings.pretty {
967            self.buf.push(b'\n');
968
969            for _ in 0..self.indent {
970                self.buf.push(b' ');
971            }
972        }
973
974        self.buf.push_val(key);
975
976        let needs_padding = if self.settings.pretty {
977            self.buf.push(b' ');
978            false
979        } else {
980            true
981        };
982
983        Obj::direct(self.buf, self.indent, self.settings, needs_padding)
984    }
985
986    /// Write a pair with a primitive value.
987    ///
988    /// This is a shorthand for `dict.insert(key).primitive(value)`.
989    #[inline]
990    pub fn pair<T: Primitive>(&mut self, key: Name, value: T) -> &mut Self {
991        self.insert(key).primitive(value);
992        self
993    }
994
995    /// Write a sequence of pairs with primitive values.
996    pub fn pairs<'n, T: Primitive>(
997        &mut self,
998        pairs: impl IntoIterator<Item = (Name<'n>, T)>,
999    ) -> &mut Self {
1000        for (key, value) in pairs {
1001            self.pair(key, value);
1002        }
1003        self
1004    }
1005
1006    /// Convert into a typed version.
1007    #[inline]
1008    pub fn typed<T>(self) -> TypedDict<'a, T> {
1009        TypedDict::wrap(self)
1010    }
1011}
1012
1013impl Drop for Dict<'_> {
1014    #[inline]
1015    fn drop(&mut self) {
1016        self.buf.limits.register_dict_entries(self.len as usize);
1017
1018        if self.len != 0 && self.settings.pretty {
1019            self.buf.push(b'\n');
1020            for _ in 0..self.indent - 2 {
1021                self.buf.push(b' ');
1022            }
1023        }
1024
1025        self.buf.extend(b">>");
1026
1027        if self.indirect {
1028            self.buf.extend(b"\nendobj\n");
1029
1030            if self.settings.pretty {
1031                self.buf.extend(b"\n");
1032            }
1033        }
1034    }
1035}
1036
1037/// Writer for a dictionary mapping to a fixed type.
1038pub struct TypedDict<'a, T> {
1039    dict: Dict<'a>,
1040    phantom: PhantomData<fn() -> T>,
1041}
1042
1043impl<'a, T> Writer<'a> for TypedDict<'a, T> {
1044    fn start(obj: Obj<'a>) -> Self {
1045        Self { dict: obj.dict(), phantom: PhantomData }
1046    }
1047}
1048
1049impl<'a, T> Rewrite<'a> for TypedDict<'_, T> {
1050    type Output = TypedDict<'a, T>;
1051}
1052
1053impl<'a, T> TypedDict<'a, T> {
1054    /// Wrap a dictionary to make it type-safe.
1055    #[inline]
1056    pub fn wrap(dict: Dict<'a>) -> Self {
1057        Self { dict, phantom: PhantomData }
1058    }
1059
1060    /// The number of written pairs.
1061    #[inline]
1062    pub fn len(&self) -> i32 {
1063        self.dict.len()
1064    }
1065
1066    /// Whether no pairs have been written so far.
1067    #[inline]
1068    pub fn is_empty(&self) -> bool {
1069        self.len() == 0
1070    }
1071
1072    /// Write a key-value pair.
1073    #[inline]
1074    pub fn pair(&mut self, key: Name, value: T) -> &mut Self
1075    where
1076        T: Primitive,
1077    {
1078        self.dict.pair(key, value);
1079        self
1080    }
1081
1082    /// Write a sequence of key-value pairs.
1083    #[inline]
1084    pub fn pairs<'n>(
1085        &mut self,
1086        pairs: impl IntoIterator<Item = (Name<'n>, T)>,
1087    ) -> &mut Self
1088    where
1089        T: Primitive,
1090    {
1091        self.dict.pairs(pairs);
1092        self
1093    }
1094
1095    /// Start writing a pair with the typed writer.
1096    ///
1097    /// Returns `T` but with its lifetime rewritten from `'a` to `'b`.
1098    #[inline]
1099    pub fn insert<'b>(&'b mut self, key: Name) -> <T as Rewrite<'b>>::Output
1100    where
1101        T: Writer<'a> + Rewrite<'b>,
1102    {
1103        <T as Rewrite>::Output::start(self.dict.insert(key))
1104    }
1105}
1106
1107/// Writer for an indirect stream object.
1108pub struct Stream<'a> {
1109    dict: ManuallyDrop<Dict<'a>>,
1110    data: &'a [u8],
1111}
1112
1113impl<'a> Stream<'a> {
1114    /// Start writing a stream.
1115    ///
1116    /// Panics if the object writer is not indirect or the stream length exceeds
1117    /// `i32::MAX`.
1118    pub(crate) fn start(obj: Obj<'a>, data: &'a [u8]) -> Self {
1119        assert!(obj.indirect);
1120
1121        let mut dict = obj.dict();
1122        dict.pair(
1123            Name(b"Length"),
1124            i32::try_from(data.len()).unwrap_or_else(|_| {
1125                panic!("data length (is `{}`) must be <= i32::MAX", data.len());
1126            }),
1127        );
1128
1129        Self { dict: ManuallyDrop::new(dict), data }
1130    }
1131
1132    /// Write the `/Filter` attribute.
1133    pub fn filter(&mut self, filter: Filter) -> &mut Self {
1134        self.pair(Name(b"Filter"), filter.to_name());
1135        self
1136    }
1137
1138    /// Start writing the `/DecodeParms` attribute.
1139    ///
1140    /// This is a dictionary that specifies parameters to be used in decoding
1141    /// the stream data using the filter specified by the
1142    /// [`/Filter`](Self::filter) attribute.
1143    pub fn decode_parms(&mut self) -> DecodeParms<'_> {
1144        self.insert(Name(b"DecodeParms")).start()
1145    }
1146}
1147
1148impl Drop for Stream<'_> {
1149    fn drop(&mut self) {
1150        let dict_len = self.dict.len as usize;
1151        self.dict.buf.limits.register_dict_entries(dict_len);
1152
1153        if self.dict.settings.pretty {
1154            self.dict.buf.extend(b"\n");
1155        }
1156
1157        self.dict.buf.extend(b">>");
1158        self.dict.buf.extend(b"\nstream\n");
1159        self.dict.buf.extend(self.data.as_ref());
1160        self.dict.buf.extend(b"\nendstream");
1161        self.dict.buf.extend(b"\nendobj\n");
1162
1163        if self.dict.settings.pretty {
1164            self.dict.buf.extend(b"\n");
1165        }
1166    }
1167}
1168
1169deref!('a, Stream<'a> => Dict<'a>, dict);
1170
1171/// A compression filter for a stream.
1172#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
1173#[allow(missing_docs)]
1174pub enum Filter {
1175    AsciiHexDecode,
1176    Ascii85Decode,
1177    /// Lempel-Ziv-Welch (LZW) compression.
1178    ///
1179    /// Note that this filter is forbidden in PDF/A.
1180    LzwDecode,
1181    FlateDecode,
1182    RunLengthDecode,
1183    CcittFaxDecode,
1184    Jbig2Decode,
1185    /// Decodes JPEG/JFIF files with a SOF0, SOF1, or (PDF 1.3+) SOF2 marker.
1186    ///
1187    /// See ISO 32000-1:2008, Section 7.4.8 and Adobe Technical Note #5116.
1188    DctDecode,
1189    /// Decodes JPEG2000 files with a JPX baseline marker.
1190    ///
1191    /// Note that additional restrictions are imposed by PDF/A and PDF/X.
1192    JpxDecode,
1193    /// Encrypt the stream.
1194    ///
1195    /// Note that this filter is restricted in PDF/A.
1196    Crypt,
1197}
1198
1199impl Filter {
1200    pub(crate) fn to_name(self) -> Name<'static> {
1201        match self {
1202            Self::AsciiHexDecode => Name(b"ASCIIHexDecode"),
1203            Self::Ascii85Decode => Name(b"ASCII85Decode"),
1204            Self::LzwDecode => Name(b"LZWDecode"),
1205            Self::FlateDecode => Name(b"FlateDecode"),
1206            Self::RunLengthDecode => Name(b"RunLengthDecode"),
1207            Self::CcittFaxDecode => Name(b"CCITTFaxDecode"),
1208            Self::Jbig2Decode => Name(b"JBIG2Decode"),
1209            Self::DctDecode => Name(b"DCTDecode"),
1210            Self::JpxDecode => Name(b"JPXDecode"),
1211            Self::Crypt => Name(b"Crypt"),
1212        }
1213    }
1214}
1215
1216/// Writer for an _filter decode parameters dictionary_.
1217///
1218/// This struct is created by [`Stream::decode_parms`].
1219pub struct DecodeParms<'a> {
1220    dict: Dict<'a>,
1221}
1222
1223writer!(DecodeParms: |obj| Self { dict: obj.dict() });
1224
1225/// Properties for `FlateDecode` and `LzwDecode`.
1226impl DecodeParms<'_> {
1227    /// Write the `/Predictor` attribute for `FlateDecode` and `LzwDecode`.
1228    ///
1229    /// No predictor is used by default.
1230    pub fn predictor(&mut self, predictor: Predictor) -> &mut Self {
1231        self.pair(Name(b"Predictor"), predictor.to_i32());
1232        self
1233    }
1234
1235    /// Write the `/Colors` attribute for `FlateDecode` and `LzwDecode`.
1236    ///
1237    /// Must be greater than 0. [`/Predictor`](Self::predictor) must be set.
1238    /// Defaults to 1.
1239    pub fn colors(&mut self, colors: i32) -> &mut Self {
1240        if colors <= 0 {
1241            panic!("`Colors` must be greater than 0");
1242        }
1243
1244        self.pair(Name(b"Colors"), colors);
1245        self
1246    }
1247
1248    /// Write the `/BitsPerComponent` attribute for `FlateDecode` and
1249    /// `LzwDecode`.
1250    ///
1251    /// Must be one of 1, 2, 4, 8, or 16. [`/Predictor`](Self::predictor) must
1252    /// be set. Defaults to 8.
1253    pub fn bits_per_component(&mut self, bits: i32) -> &mut Self {
1254        if ![1, 2, 4, 8, 16].contains(&bits) {
1255            panic!("`BitsPerComponent` must be one of 1, 2, 4, 8, or 16");
1256        }
1257
1258        self.pair(Name(b"BitsPerComponent"), bits);
1259        self
1260    }
1261
1262    /// Write the `/Columns` attribute for `FlateDecode` and `LzwDecode` or
1263    /// `CcittFaxDecode`.
1264    ///
1265    /// When used with `FlateDecode` and `LzwDecode`, it indicates the number of
1266    /// samples in each row. In that case, [`/Predictor`](Self::predictor) must
1267    /// be set and the default is 1.
1268    ///
1269    /// When used with `CcittFaxDecode` it denominates the width of the image in
1270    /// pixels and defaults to 1728.
1271    pub fn columns(&mut self, columns: i32) -> &mut Self {
1272        self.pair(Name(b"Columns"), columns);
1273        self
1274    }
1275
1276    /// Write the `/EarlyChange` attribute for `LzwDecode`.
1277    ///
1278    /// If `true` (1), the code length increases one code earlier, if `false`
1279    /// (0), length change is postponed as long as possible.
1280    ///
1281    /// Defaults to 1.
1282    pub fn early_change(&mut self, early_change: bool) -> &mut Self {
1283        self.pair(Name(b"EarlyChange"), if early_change { 1 } else { 0 });
1284        self
1285    }
1286}
1287
1288/// Properties for `CcittFaxDecode`. Also see [`Self::columns`].
1289impl DecodeParms<'_> {
1290    /// Write the `/K` attribute for `CcittFaxDecode`.
1291    ///
1292    /// Defaults to 0.
1293    pub fn k(&mut self, k: i32) -> &mut Self {
1294        self.pair(Name(b"K"), k);
1295        self
1296    }
1297
1298    /// Write the `/EndOfLine` attribute for `CcittFaxDecode`.
1299    ///
1300    /// Whether the EOL bit pattern is present in the encoding. Defaults to
1301    /// `false`.
1302    pub fn end_of_line(&mut self, eol: bool) -> &mut Self {
1303        self.pair(Name(b"EndOfLine"), eol);
1304        self
1305    }
1306
1307    /// Write the `/EncodedByteAlign` attribute for `CcittFaxDecode`.
1308    ///
1309    /// Whether to expect zero bits before each encoded line. Defaults to
1310    /// `false`.
1311    pub fn encoded_byte_align(&mut self, encoded_byte_align: bool) -> &mut Self {
1312        self.pair(Name(b"EncodedByteAlign"), encoded_byte_align);
1313        self
1314    }
1315
1316    /// Write the `/Rows` attribute for `CcittFaxDecode`.
1317    ///
1318    /// The image's height. Defaults to 0.
1319    pub fn rows(&mut self, rows: i32) -> &mut Self {
1320        self.pair(Name(b"Rows"), rows);
1321        self
1322    }
1323
1324    /// Write the `/EndOfBlock` attribute for `CcittFaxDecode`.
1325    ///
1326    /// Whether to expect an EOB code at the end of the data. Defaults to
1327    /// `true`.
1328    pub fn end_of_block(&mut self, end_of_block: bool) -> &mut Self {
1329        self.pair(Name(b"EndOfBlock"), end_of_block);
1330        self
1331    }
1332
1333    /// Write the `/BlackIs1` attribute for `CcittFaxDecode`.
1334    ///
1335    /// Whether to invert the bits in the image. Defaults to `false`.
1336    pub fn black_is_1(&mut self, black_is_1: bool) -> &mut Self {
1337        self.pair(Name(b"BlackIs1"), black_is_1);
1338        self
1339    }
1340
1341    /// Write the `/DamagedRowsBeforeError` attribute for `CcittFaxDecode`.
1342    ///
1343    /// How many damaged rows are allowed before an error is raised. Defaults to
1344    /// 0.
1345    pub fn damaged_rows_before_error(&mut self, count: i32) -> &mut Self {
1346        self.pair(Name(b"DamagedRowsBeforeError"), count);
1347        self
1348    }
1349}
1350
1351/// Properties for `Jbig2Decode`.
1352impl DecodeParms<'_> {
1353    /// Write the `/JBIG2Globals` attribute for `Jbig2Decode`.
1354    ///
1355    /// A reference to a stream containing global segments.
1356    pub fn jbig2_globals(&mut self, globals: Ref) -> &mut Self {
1357        self.pair(Name(b"JBIG2Globals"), globals);
1358        self
1359    }
1360}
1361
1362/// Properties for `JpxDecode`.
1363impl DecodeParms<'_> {
1364    /// Write the `/ColorTransform` attribute for `JpxDecode`.
1365    ///
1366    /// How to handle color data. If `true` (1), images with three color
1367    /// channels shall be decoded from the YCbCr space and images with four
1368    /// color channels are decoded from YCbCrK. If `false` (0), no
1369    /// transformation is applied. The default depends on the `APP14` marker in
1370    /// the data stream.
1371    pub fn color_transform(&mut self, color_transform: bool) -> &mut Self {
1372        self.pair(Name(b"ColorTransform"), if color_transform { 1 } else { 0 });
1373        self
1374    }
1375}
1376
1377/// Properties for `Crypt`.
1378impl DecodeParms<'_> {
1379    /// Write the `/Type` attribute for `Crypt` as `CryptFilterDecodeParms`.
1380    pub fn crypt_type(&mut self) -> &mut Self {
1381        self.pair(Name(b"Type"), Name(b"CryptFilterDecodeParms"));
1382        self
1383    }
1384
1385    /// Write the `/Name` attribute for `Crypt`.
1386    ///
1387    /// The name of the crypt filter corresponding to a `CF` entry of the
1388    /// encryption dictionary.
1389    pub fn name(&mut self, name: Name) -> &mut Self {
1390        self.pair(Name(b"Name"), name);
1391        self
1392    }
1393}
1394
1395deref!('a, DecodeParms<'a> => Dict<'a>, dict);
1396
1397/// Which kind of predictor to use for a `FlateDecode` or `LzwDecode` stream.
1398#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Hash)]
1399#[allow(missing_docs)]
1400pub enum Predictor {
1401    /// No prediction.
1402    #[default]
1403    None,
1404    /// TIFF Predictor 2.
1405    Tiff,
1406    PngNone,
1407    PngSub,
1408    PngUp,
1409    PngAverage,
1410    PngPaeth,
1411    PngOptimum,
1412}
1413
1414impl Predictor {
1415    /// Convert the predictor to its integer representation according to ISO
1416    /// 32000-2:2020, Table E.
1417    fn to_i32(self) -> i32 {
1418        match self {
1419            Self::None => 1,
1420            Self::Tiff => 2,
1421            Self::PngNone => 10,
1422            Self::PngSub => 11,
1423            Self::PngUp => 12,
1424            Self::PngAverage => 13,
1425            Self::PngPaeth => 14,
1426            Self::PngOptimum => 15,
1427        }
1428    }
1429}
1430
1431/// Writer for a _name tree node_.
1432///
1433/// Name trees associate a large number of names with PDF objects. They are
1434/// lexically ordered search trees. Root nodes may directly contain all leafs,
1435/// however, this might degrade performance for very large numbers of
1436/// name-object pairs.
1437///
1438/// For each node, either the `/Kids` or `/Names` attribute must be set, but
1439/// never both.
1440pub struct NameTree<'a, T> {
1441    dict: Dict<'a>,
1442    phantom: PhantomData<T>,
1443}
1444
1445impl<'a, T> Writer<'a> for NameTree<'a, T> {
1446    fn start(obj: Obj<'a>) -> Self {
1447        Self { dict: obj.dict(), phantom: PhantomData }
1448    }
1449}
1450
1451impl<'a, T> Rewrite<'a> for NameTree<'_, T> {
1452    type Output = NameTree<'a, T>;
1453}
1454
1455impl<T> NameTree<'_, T> {
1456    /// Start writing the `/Kids` attribute with the children of this node.
1457    pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1458        self.dict.insert(Name(b"Kids")).array().typed()
1459    }
1460
1461    /// Start writing the `/Names` attribute to set the immediate name-to-object
1462    /// mappings of this node.
1463    pub fn names(&mut self) -> NameTreeEntries<'_, T> {
1464        self.dict.insert(Name(b"Names")).start()
1465    }
1466
1467    /// Write the `/Limits` array to set the range of names in this node. This
1468    /// is required for every node except the root node.
1469    pub fn limits(&mut self, min: Name, max: Name) -> &mut Self {
1470        self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1471        self
1472    }
1473}
1474
1475/// Writer for a _name tree names_ array.
1476///
1477/// The children must be added in ascending lexical order. Their minimum and
1478/// maximum keys must not exceed the `/Limits` property of the parent [`NameTree`]
1479/// node. This struct is created by [`NameTree::names`].
1480pub struct NameTreeEntries<'a, T> {
1481    arr: Array<'a>,
1482    phantom: PhantomData<T>,
1483}
1484
1485impl<'a, T> Writer<'a> for NameTreeEntries<'a, T> {
1486    fn start(obj: Obj<'a>) -> Self {
1487        Self { arr: obj.array(), phantom: PhantomData }
1488    }
1489}
1490
1491impl<'a, T> Rewrite<'a> for NameTreeEntries<'_, T> {
1492    type Output = NameTreeEntries<'a, T>;
1493}
1494
1495impl<T> NameTreeEntries<'_, T>
1496where
1497    T: Primitive,
1498{
1499    /// Insert a name-value pair.
1500    pub fn insert(&mut self, key: Str, value: T) -> &mut Self {
1501        self.arr.item(key);
1502        self.arr.item(value);
1503        self
1504    }
1505}
1506
1507/// Writer for a _number tree node_.
1508///
1509/// Number trees associate a many integers with PDF objects. They are search
1510/// trees in ascending order. Root nodes may directly contain all leafs,
1511/// however, this might degrade performance for very large numbers of
1512/// integer-object pairs.
1513///
1514/// For each node, either the `/Kids` or `/Nums` attribute must be set, but
1515/// never both.
1516pub struct NumberTree<'a, T> {
1517    dict: Dict<'a>,
1518    phantom: PhantomData<T>,
1519}
1520
1521impl<'a, T> Writer<'a> for NumberTree<'a, T> {
1522    fn start(obj: Obj<'a>) -> Self {
1523        Self { dict: obj.dict(), phantom: PhantomData }
1524    }
1525}
1526
1527impl<'a, T> Rewrite<'a> for NumberTree<'_, T> {
1528    type Output = NumberTree<'a, T>;
1529}
1530
1531impl<T> NumberTree<'_, T> {
1532    /// Start writing the `/Kids` attribute with the children of this node.
1533    pub fn kids(&mut self) -> TypedArray<'_, Ref> {
1534        self.dict.insert(Name(b"Kids")).array().typed()
1535    }
1536
1537    /// Start writing the `/Nums` attribute to set the immediate
1538    /// number-to-object mappings of this node.
1539    pub fn nums(&mut self) -> NumberTreeEntries<'_, T> {
1540        self.dict.insert(Name(b"Nums")).start()
1541    }
1542
1543    /// Write the `/Limits` array to set the range of numbers in this node. This
1544    /// is required for every node except the root node.
1545    pub fn limits(&mut self, min: i32, max: i32) -> &mut Self {
1546        self.dict.insert(Name(b"Limits")).array().typed().items([min, max]);
1547        self
1548    }
1549}
1550
1551/// Writer for a _number tree numbers_ array.
1552///
1553/// The children must be added in ascending order. Their minimum and
1554/// maximum keys must not exceed the `/Limits` property of the parent [`NumberTree`]
1555/// node. This struct is created by [`NumberTree::nums`].
1556pub struct NumberTreeEntries<'a, T> {
1557    arr: Array<'a>,
1558    phantom: PhantomData<T>,
1559}
1560
1561impl<'a, T> Writer<'a> for NumberTreeEntries<'a, T> {
1562    fn start(obj: Obj<'a>) -> Self {
1563        Self { arr: obj.array(), phantom: PhantomData }
1564    }
1565}
1566
1567impl<'a, T> Rewrite<'a> for NumberTreeEntries<'_, T> {
1568    type Output = NumberTreeEntries<'a, T>;
1569}
1570
1571impl<T> NumberTreeEntries<'_, T>
1572where
1573    T: Primitive,
1574{
1575    /// Insert a number-value pair.
1576    pub fn insert(&mut self, key: i32, value: T) -> &mut Self {
1577        self.arr.item(key);
1578        self.arr.item(value);
1579        self
1580    }
1581}
1582
1583/// Finish objects in postfix-style.
1584///
1585/// In many cases you can use writers in builder-pattern style so that they are
1586/// automatically dropped at the appropriate time. Sometimes though you need to
1587/// bind a writer to a variable and still want to regain access to the
1588/// [`Pdf`] in the same scope. In that case, you need to manually invoke
1589/// the writer's `Drop` implementation. You can of course, just write
1590/// `drop(array)` to finish your array, but you might find it more aesthetically
1591/// pleasing to write `array.finish()`. That's what this trait is for.
1592///
1593/// ```
1594/// # use pdf_writer::{Pdf, Ref, Finish, Name, Str};
1595/// # let mut pdf = Pdf::new();
1596/// let mut array = pdf.indirect(Ref::new(1)).array();
1597/// array.push().dict().pair(Name(b"Key"), Str(b"Value"));
1598/// array.item(2);
1599/// array.finish(); // instead of drop(array)
1600///
1601/// // Do more stuff with `pdf` ...
1602/// ```
1603pub trait Finish: Sized {
1604    /// Does nothing but move `self`, equivalent to [`drop`].
1605    #[inline]
1606    fn finish(self) {}
1607}
1608
1609impl<T> Finish for T {}
1610
1611#[cfg(test)]
1612mod tests {
1613    use super::*;
1614
1615    #[test]
1616    fn test_primitive_objects() {
1617        // Test really simple objects.
1618        test_primitive!(true, b"true");
1619        test_primitive!(false, b"false");
1620        test_primitive!(78, b"78");
1621        test_primitive!(4.22, b"4.22");
1622        test_primitive!(1.184e-7, b"0.0000001184");
1623        test_primitive!(4.2e13, b"42000000000000");
1624        test_primitive!(Ref::new(7), b"7 0 R");
1625        test_primitive!(Null, b"null");
1626
1627        // Test strings.
1628        test_primitive!(Str(b"Hello, World!"), b"(Hello, World!)");
1629        test_primitive!(Str(b"()"), br"(())");
1630        test_primitive!(Str(b")()"), br"(\)\(\))");
1631        test_primitive!(Str(b"()(())"), br"(()(()))");
1632        test_primitive!(Str(b"(()))"), br"(\(\(\)\)\))");
1633        test_primitive!(Str(b"\\"), br"(\\)");
1634        test_primitive!(Str(b"\n\ta"), br"(\n\ta)");
1635        test_primitive!(Str(br"\n"), br"(\\n)");
1636        test_primitive!(Str(b"a\x14b"), br"(a\024b)");
1637        test_primitive!(Str(b"\xFF\xAA"), b"<FFAA>");
1638        test_primitive!(Str(b"\x0A\x7F\x1F"), br"(\n\177\037)");
1639
1640        // Test text strings.
1641        test_primitive!(TextStr("Hallo"), b"(Hallo)");
1642        test_primitive!(TextStr("😀!"), b"<FEFFD83DDE000021>");
1643
1644        // Test names.
1645        test_primitive!(Name(b"Filter"), b"/Filter");
1646        test_primitive!(Name(b"A B"), br"/A#20B");
1647        test_primitive!(Name(b"~+c"), br"/~+c");
1648        test_primitive!(Name(b"/A-B"), br"/#2FA-B");
1649        test_primitive!(Name(b"<A>"), br"/#3CA#3E");
1650        test_primitive!(Name(b"#"), br"/#23");
1651        test_primitive!(Name(b"\n"), br"/#0A");
1652    }
1653
1654    #[test]
1655    fn test_dates() {
1656        test_primitive!(Date::new(2021), b"(D:2021)");
1657        test_primitive!(Date::new(2021).month(30), b"(D:202112)");
1658
1659        let date = Date::new(2020).month(3).day(17).hour(1).minute(2).second(3);
1660        test_primitive!(date, b"(D:20200317010203)");
1661        test_primitive!(date.utc_offset_hour(0), b"(D:20200317010203Z)");
1662        test_primitive!(date.utc_offset_hour(4), b"(D:20200317010203+04'00)");
1663        test_primitive!(
1664            date.utc_offset_hour(-17).utc_offset_minute(10),
1665            b"(D:20200317010203-17'10)"
1666        );
1667    }
1668
1669    #[test]
1670    fn test_arrays() {
1671        test_obj!(|obj| obj.array(), b"[]");
1672        test_obj!(|obj| obj.array().item(12).item(Null), b"[12 null]");
1673        test_obj!(|obj| obj.array().typed().items(vec![1, 2, 3]), b"[1 2 3]");
1674        test_obj!(
1675            |obj| {
1676                let mut array = obj.array();
1677                array.push().array().typed().items(vec![1, 2]);
1678                array.item(3);
1679            },
1680            b"[[1 2] 3]",
1681        );
1682    }
1683
1684    #[test]
1685    fn test_dicts() {
1686        test_obj!(|obj| obj.dict(), b"<<>>");
1687        test_obj!(
1688            |obj| obj.dict().pair(Name(b"Quality"), Name(b"Good")),
1689            b"<<\n  /Quality /Good\n>>",
1690        );
1691        test_obj!(
1692            |obj| {
1693                obj.dict().pair(Name(b"A"), 1).pair(Name(b"B"), 2);
1694            },
1695            b"<<\n  /A 1\n  /B 2\n>>",
1696        );
1697    }
1698
1699    #[test]
1700    fn test_streams() {
1701        let mut w = Pdf::new();
1702        w.stream(Ref::new(1), &b"Hi there!"[..]).filter(Filter::Crypt);
1703        test!(
1704            w.finish(),
1705            b"%PDF-1.7\n%\x80\x80\x80\x80\n",
1706            b"1 0 obj",
1707            b"<<\n  /Length 9\n  /Filter /Crypt\n>>",
1708            b"stream",
1709            b"Hi there!",
1710            b"endstream",
1711            b"endobj\n",
1712            b"xref",
1713            b"0 2",
1714            b"0000000000 65535 f\r",
1715            b"0000000016 00000 n\r",
1716            b"trailer",
1717            b"<<\n  /Size 2\n>>",
1718            b"startxref\n94\n%%EOF",
1719        )
1720    }
1721
1722    #[test]
1723    fn test_arrays_no_pretty() {
1724        test_obj_no_pretty!(|obj| obj.array(), b"[]");
1725        test_obj_no_pretty!(
1726            |obj| {
1727                let mut arr = obj.array();
1728
1729                arr.item(12)
1730                    .item(Name(b"Hi"))
1731                    .item(Name(b"Hi2"))
1732                    .item(false)
1733                    .item(TextStr("A string"));
1734
1735                arr.push().dict().pair(Name(b"Test1"), 23);
1736
1737                arr.item(Null).item(23.40);
1738
1739                arr
1740            },
1741            b"[12/Hi/Hi2 false(A string)<</Test1 23>>null 23.4]"
1742        );
1743    }
1744
1745    #[test]
1746    fn test_dicts_no_pretty() {
1747        test_obj_no_pretty!(|obj| obj.dict(), b"<<>>");
1748        test_obj_no_pretty!(
1749            |obj| {
1750                let mut dict = obj.dict();
1751                dict.pair(Name(b"Key1"), 12)
1752                     .pair(Name(b"Key2"), Name(b"Hi"))
1753                     .pair(Name(b"Key3"), false)
1754                     .pair(Name(b"Key4"), TextStr("A string"));
1755                dict.insert(Name(b"Key5")).array().item(23).item(Name(b"Value"));
1756                dict.pair(Name(b"Key6"), Null)
1757                     .pair(Name(b"Key7"), 23.40)
1758            },
1759            b"<</Key1 12/Key2/Hi/Key3 false/Key4(A string)/Key5[23/Value]/Key6 null/Key7 23.4>>"
1760        );
1761    }
1762}