pdf_create/
write.rs

1//! Methods to produce a binary file
2
3use std::io::{self, Write};
4
5use chrono::{DateTime, Local};
6
7use crate::{common::{Dict, ObjRef, PdfString}, low, util::ByteCounter};
8
9/// API to serialize a dict
10#[must_use]
11pub struct PdfDict<'a, 'b> {
12    first: bool,
13    f: &'b mut Formatter<'a>,
14}
15
16impl<'a, 'b> PdfDict<'a, 'b> {
17    fn check_first(&mut self) -> io::Result<()> {
18        if self.first {
19            if self.f.indent > 0 {
20                writeln!(self.f.inner)?;
21            }
22            self.f.indent()?;
23            writeln!(self.f.inner, "<<")?;
24            self.first = false;
25        }
26        Ok(())
27    }
28
29    /// Write a field
30    pub fn field(&mut self, name: &str, value: &dyn Serialize) -> io::Result<&mut Self> {
31        self.check_first()?;
32        self.f.indent += 2;
33        self.f.indent()?;
34        self.f.needs_space = write_name(name, &mut self.f.inner)?;
35        value.write(&mut self.f)?;
36        writeln!(self.f.inner)?;
37        self.f.indent -= 2;
38        Ok(self)
39    }
40
41    /// Write an optional field, if it is not `None`
42    pub fn opt_field<X: Serialize>(
43        &mut self,
44        name: &str,
45        field: &Option<X>,
46    ) -> io::Result<&mut Self> {
47        if let Some(value) = field {
48            self.field(name, value)
49        } else {
50            Ok(self)
51        }
52    }
53
54    /// Write a dict-valued field if it is not empty
55    pub fn dict_field<X: Serialize>(
56        &mut self,
57        name: &str,
58        dict: &Dict<X>,
59    ) -> io::Result<&mut Self> {
60        if dict.is_empty() {
61            Ok(self)
62        } else {
63            self.field(name, dict)
64        }
65    }
66
67    /// Write a dict-valued field wrapped in a resource
68    pub fn dict_res_field<X: Serialize>(
69        &mut self,
70        name: &str,
71        res: &low::Resource<Dict<X>>,
72    ) -> io::Result<&mut Self> {
73        match res {
74            low::Resource::Ref(r) => self.field(name, r),
75            low::Resource::Immediate(dict) => self.dict_field(name, dict),
76        }
77    }
78
79    /// Write a slice-valued field
80    pub fn arr_field<X: Serialize>(&mut self, name: &str, array: &[X]) -> io::Result<&mut Self> {
81        self.check_first()?;
82        self.f.indent += 2;
83        self.f.indent()?;
84        write_name(name, &mut self.f.inner)?;
85
86        self.f.pdf_arr().entries(array)?.finish()?;
87
88        writeln!(self.f.inner)?;
89        self.f.indent -= 2;
90        Ok(self)
91    }
92
93    /// Close the dict
94    pub fn finish(&mut self) -> io::Result<()> {
95        if self.first {
96            write!(self.f.inner, "<< >>")?;
97            self.f.needs_space = false;
98        } else {
99            self.f.indent()?;
100            write!(self.f.inner, ">>")?;
101            if self.f.indent == 0 {
102                writeln!(self.f.inner)?;
103            }
104        }
105        Ok(())
106    }
107}
108
109/// API to serialize an array
110#[must_use]
111pub struct PdfArr<'a, 'b> {
112    first: bool,
113    f: &'b mut Formatter<'a>,
114}
115
116impl<'a, 'b> PdfArr<'a, 'b> {
117    fn check_first(&mut self) -> io::Result<()> {
118        if self.first {
119            write!(self.f.inner, "[")?;
120            self.first = false;
121            self.f.needs_space = false;
122        }
123        Ok(())
124    }
125
126    /// Write the next entry
127    pub fn entry(&mut self, value: &dyn Serialize) -> io::Result<&mut Self> {
128        self.check_first()?;
129        value.write(&mut self.f)?;
130        Ok(self)
131    }
132
133    /// Write entries from an iterator
134    pub fn entries<X: Serialize>(
135        &mut self,
136        i: impl IntoIterator<Item = X>,
137    ) -> io::Result<&mut Self> {
138        for entry in i.into_iter() {
139            self.entry(&entry)?;
140        }
141        Ok(self)
142    }
143
144    /// Close the array
145    pub fn finish(&mut self) -> io::Result<()> {
146        if self.first {
147            write!(self.f.inner, "[]")?;
148        } else {
149            write!(self.f.inner, "]")?;
150        }
151        Ok(())
152    }
153}
154
155/// Formatter for a PDF document
156pub struct Formatter<'a> {
157    pub(super) inner: ByteCounter<&'a mut dyn Write>,
158    indent: usize,
159    needs_space: bool,
160    pub(super) xref: Vec<Option<(usize, u16, bool)>>,
161}
162
163impl<'a> Formatter<'a> {
164    /// Create a new formatter
165    pub fn new(w: &'a mut dyn Write) -> Self {
166        Self {
167            inner: ByteCounter::new(w),
168            indent: 0,
169            needs_space: false,
170            xref: vec![Some((0, 65535, true))],
171        }
172    }
173
174    /// Start writing a PDF dict
175    pub fn pdf_dict(&mut self) -> PdfDict<'a, '_> {
176        PdfDict {
177            first: true,
178            f: self,
179        }
180    }
181
182    /// Start writing a PDF array
183    pub fn pdf_arr(&mut self) -> PdfArr<'a, '_> {
184        PdfArr {
185            first: true,
186            f: self,
187        }
188    }
189
190    /// Start writing a stream
191    pub fn pdf_stream(&mut self, data: &[u8]) -> io::Result<()> {
192        writeln!(self.inner, "stream")?;
193        self.inner.write_all(data)?;
194        writeln!(self.inner, "endstream")?;
195        Ok(())
196    }
197
198    /// Start writing an object
199    pub fn obj(&mut self, r#ref: ObjRef, obj: &dyn Serialize) -> io::Result<()> {
200        let offset = self.inner.bytes_written();
201        writeln!(self.inner, "{} {} obj", r#ref.id, r#ref.gen)?;
202        obj.write(self)?;
203        writeln!(self.inner, "endobj")?;
204
205        while self.xref.len() <= (r#ref.id as usize) {
206            self.xref.push(None);
207        }
208        self.xref[r#ref.id as usize] = Some((offset, r#ref.gen, false));
209        Ok(())
210    }
211
212    /// Write a classic xref section
213    pub fn xref(&mut self) -> io::Result<usize> {
214        let offset = self.inner.bytes_written();
215        writeln!(self.inner, "xref")?;
216
217        let mut rest = &self.xref[..];
218        let mut index = 0;
219        while let Some(pos) = rest.iter().position(Option::is_some) {
220            rest = &rest[pos..];
221            index += pos;
222            let mid = rest.iter().position(Option::is_none).unwrap_or(rest.len());
223            let (a, b) = rest.split_at(mid);
224
225            writeln!(self.inner, "{} {}", index, mid)?;
226            for elem in a {
227                let (offset, gen, free) = elem.unwrap();
228                let mark = if free { 'f' } else { 'n' };
229                // NOTE: the PDF spec requires the eol to be two bytes long (i.e. SP LF or CR LF)
230                writeln!(self.inner, "{:010} {:05} {} ", offset, gen, mark)?;
231            }
232
233            rest = b;
234            index += mid;
235        }
236
237        Ok(offset)
238    }
239
240    fn indent(&mut self) -> io::Result<()> {
241        write!(self.inner, "{:indent$}", "", indent = self.indent)?;
242        Ok(())
243    }
244}
245
246/// Trait to serialize some PDF object
247pub trait Serialize {
248    /// Write the object to a stream
249    fn write(&self, f: &mut Formatter) -> io::Result<()>;
250}
251
252impl<X: Serialize> Serialize for &'_ X {
253    fn write(&self, f: &mut Formatter) -> io::Result<()> {
254        (*self).write(f)
255    }
256}
257
258impl Serialize for PdfString {
259    fn write(&self, f: &mut Formatter) -> io::Result<()> {
260        f.needs_space = write_string(self.as_bytes(), &mut f.inner)?;
261        Ok(())
262    }
263}
264
265macro_rules! serialize_display_impl {
266    ($ty:ty) => {
267        impl Serialize for $ty {
268            fn write(&self, f: &mut Formatter) -> io::Result<()> {
269                if f.needs_space {
270                    write!(f.inner, " ")?;
271                }
272                write!(f.inner, "{}", self)?;
273                f.needs_space = true;
274                Ok(())
275            }
276        }
277    };
278}
279
280serialize_display_impl!(u8);
281serialize_display_impl!(usize);
282serialize_display_impl!(u32);
283serialize_display_impl!(i32);
284serialize_display_impl!(f32);
285
286impl<X: Serialize> Serialize for Vec<X> {
287    fn write(&self, f: &mut Formatter) -> io::Result<()> {
288        write!(f.inner, "[")?;
289        f.needs_space = false;
290        for elem in self {
291            elem.write(f)?;
292        }
293        write!(f.inner, "]")?;
294        Ok(())
295    }
296}
297
298impl<X: Serialize> Serialize for [X] {
299    fn write(&self, f: &mut Formatter) -> io::Result<()> {
300        write!(f.inner, "[")?;
301        f.needs_space = false;
302        for elem in self {
303            elem.write(f)?;
304        }
305        write!(f.inner, "]")?;
306        Ok(())
307    }
308}
309
310impl Serialize for ObjRef {
311    fn write(&self, f: &mut Formatter) -> io::Result<()> {
312        if f.needs_space {
313            write!(f.inner, " ")?;
314        }
315        f.needs_space = write_ref(*self, &mut f.inner)?;
316        Ok(())
317    }
318}
319
320/// A borrowed PDF name (e.g. `/Info`)
321#[derive(Debug, Copy, Clone)]
322pub struct PdfName<'a>(pub &'a str);
323
324impl Serialize for PdfName<'_> {
325    fn write(&self, f: &mut Formatter) -> io::Result<()> {
326        f.needs_space = write_name(&self.0, &mut f.inner)?;
327        Ok(())
328    }
329}
330
331impl Serialize for DateTime<Local> {
332    fn write(&self, f: &mut Formatter) -> io::Result<()> {
333        let off = self.offset();
334        let off_sec = off.local_minus_utc();
335        let (off_sec, mark) = if off_sec < 0 {
336            (-off_sec, '-')
337        } else {
338            (off_sec, '+')
339        };
340        let (_, off_min) = (off_sec % 60, off_sec / 60);
341        let (off_min, off_hor) = (off_min % 60, off_min / 60);
342        let date_time = format!(
343            "D:{}{}{:02}'{:02}",
344            self.format("%Y%m%d%H%M%S"),
345            mark,
346            off_hor,
347            off_min
348        );
349        let st = date_time.into_bytes();
350        f.needs_space = write_string(&st, &mut f.inner)?;
351        Ok(())
352    }
353}
354
355/// Writes a complete string to a writer
356pub fn write_string<W: Write>(bytes: &[u8], w: &mut W) -> io::Result<bool> {
357    let mut cpc = bytes.iter().copied().filter(|c| *c == 41 /* ')' */).count();
358    let mut opc = 0;
359    write!(w, "(")?;
360    for byte in bytes.iter().copied() {
361        match byte {
362            0..=31 | 127..=255 => write!(w, "\\{:03o}", byte)?,
363            92 => write!(w, "\\\\")?,
364            40 => {
365                if cpc == 0 {
366                    write!(w, "\\(")?
367                } else {
368                    write!(w, "(")?;
369                    cpc -= 1;
370                    opc += 1;
371                }
372            }
373            41 => {
374                if opc == 0 {
375                    write!(w, "\\)")?
376                } else {
377                    write!(w, ")")?;
378                    opc -= 1;
379                }
380            }
381            _ => write!(w, "{}", byte as char)?,
382        }
383    }
384    write!(w, ")")?;
385    Ok(false)
386}
387
388/// Write a borrowed string as a PDF name
389///
390/// FIXME: Probably not all unicode strings allowed
391pub fn write_name<W: Write>(name: &str, w: &mut W) -> io::Result<bool> {
392    write!(w, "/{}", name)?;
393    Ok(true)
394}
395
396/// Write a plain reference
397pub fn write_ref<W: Write>(plain_ref: ObjRef, w: &mut W) -> io::Result<bool> {
398    write!(w, "{} {} R", plain_ref.id, plain_ref.gen)?;
399    Ok(true)
400}