pdf_writer/
files.rs

1use super::*;
2
3/// Writer for a _file specification dictionary_.
4///
5/// This struct is created by [`Annotation::file_spec`],
6/// [`Reference::file_spec`], [`MediaClip::data`], and [`Action::file_spec`].
7pub struct FileSpec<'a> {
8    dict: Dict<'a>,
9}
10
11writer!(FileSpec: |obj| {
12    let mut dict = obj.dict();
13    dict.pair(Name(b"Type"), Name(b"Filespec"));
14    Self { dict }
15});
16
17impl FileSpec<'_> {
18    /// Write the `/FS` attribute to set the file system this entry relates to.
19    /// If you set the `system` argument to `Name(b"URL")`, this becomes an URL
20    /// specification.
21    pub fn file_system(&mut self, system: Name) -> &mut Self {
22        self.pair(Name(b"FS"), system);
23        self
24    }
25
26    /// Write the `/F` attribute to set the file path. Directories are indicated
27    /// by `/`, independent of the platform.
28    pub fn path(&mut self, path: Str) -> &mut Self {
29        self.pair(Name(b"F"), path);
30        self
31    }
32
33    /// Write the `/UF` attribute to set a Unicode-compatible path. Directories
34    /// are indicated by `/`, independent of the platform. PDF 1.7+.
35    pub fn unic_file(&mut self, path: TextStr) -> &mut Self {
36        self.pair(Name(b"UF"), path);
37        self
38    }
39
40    /// Write the `/V` attribute to indicate whether _not_ to cache the file.
41    pub fn volatile(&mut self, dont_cache: bool) -> &mut Self {
42        self.pair(Name(b"V"), dont_cache);
43        self
44    }
45
46    /// Write the `/Desc` attribute to set a file description. PDF 1.6+.
47    pub fn description(&mut self, desc: TextStr) -> &mut Self {
48        self.pair(Name(b"Desc"), desc);
49        self
50    }
51
52    /// Write the `/EF` attribute to reference an [embedded file](EmbeddedFile).
53    /// PDF 1.3+.
54    ///
55    /// This only sets an embedded file for the `F` attribute corresponding to
56    /// the [`path`](Self::path) method. If you want to set the same embedded
57    /// file for the `UF` attribute, also call [`Self::embedded_file_with_unicode`]
58    /// instead.
59    ///
60    /// Note that this key is forbidden in PDF/A-1 and restricted in PDF/A-2 and
61    /// PDF/A-4.
62    pub fn embedded_file(&mut self, id: Ref) -> &mut Self {
63        self.insert(Name(b"EF")).dict().pair(Name(b"F"), id);
64        self
65    }
66
67    /// Write the `/EF` attribute to reference an [embedded file](EmbeddedFile)
68    /// for the legacy and Unicode-compatible file path. PDF 1.7+.
69    ///
70    /// Note that this key is forbidden in PDF/A-1 and restricted in PDF/A-2 an
71    /// PDF/A-4.
72    pub fn embedded_file_with_unicode(&mut self, id: Ref) -> &mut Self {
73        self.insert(Name(b"EF"))
74            .dict()
75            .pair(Name(b"F"), id)
76            .pair(Name(b"UF"), id);
77        self
78    }
79
80    /// How this file relates to the PDF document it is embedded in.
81    /// PDF/A-3 and PDF/A-4f.
82    pub fn association_kind(&mut self, kind: AssociationKind) -> &mut Self {
83        self.pair(Name(b"AFRelationship"), kind.to_name());
84        self
85    }
86}
87
88deref!('a, FileSpec<'a> => Dict<'a>, dict);
89
90/// Writer for an _embedded file stream_.
91///
92/// This struct is created by [`Chunk::embedded_file`].
93pub struct EmbeddedFile<'a> {
94    stream: Stream<'a>,
95}
96
97impl<'a> EmbeddedFile<'a> {
98    /// Create a new embedded file writer.
99    pub(crate) fn start(mut stream: Stream<'a>) -> Self {
100        stream.pair(Name(b"Type"), Name(b"EmbeddedFile"));
101        Self { stream }
102    }
103
104    /// Write the `/Subtype` attribute to set the file type.
105    ///
106    /// This can either be a MIME type or a name prefixed by a first class PDF
107    /// prefix. Note that special characters must be encoded as described in
108    /// section 7.3.5 of the PDF 1.7 specification, e.g. `image/svg+xml` would
109    /// become `Name(b"image#2Fsvg+xml")`.
110    pub fn subtype(&mut self, subtype: Name) -> &mut Self {
111        self.pair(Name(b"Subtype"), subtype);
112        self
113    }
114
115    /// Start writing the `/Params` dictionary.
116    pub fn params(&mut self) -> EmbeddingParams<'_> {
117        self.insert(Name(b"Params")).start()
118    }
119}
120
121deref!('a, EmbeddedFile<'a> => Stream<'a>, stream);
122
123/// Writer for an _embedded file parameter dictionary_.
124///
125/// This struct is created by [`EmbeddedFile::params`].
126pub struct EmbeddingParams<'a> {
127    dict: Dict<'a>,
128}
129
130writer!(EmbeddingParams: |obj| Self { dict: obj.dict() });
131
132impl EmbeddingParams<'_> {
133    /// Write the `/Size` attribute to set the uncompressed file size in bytes.
134    pub fn size(&mut self, size: i32) -> &mut Self {
135        self.pair(Name(b"Size"), size);
136        self
137    }
138
139    /// Write the `/CreationDate` attribute to set the file creation date.
140    pub fn creation_date(&mut self, date: Date) -> &mut Self {
141        self.pair(Name(b"CreationDate"), date);
142        self
143    }
144
145    /// Write the `/ModDate` attribute to set the file modification date.
146    pub fn modification_date(&mut self, date: Date) -> &mut Self {
147        self.pair(Name(b"ModDate"), date);
148        self
149    }
150
151    /// Write the `/CheckSum` attribute to set the file checksum.
152    ///
153    /// The checksum shall be a 16-byte MD5 string.
154    pub fn checksum(&mut self, checksum: Str) -> &mut Self {
155        self.pair(Name(b"CheckSum"), checksum);
156        self
157    }
158}
159
160deref!('a, EmbeddingParams<'a> => Dict<'a>, dict);
161
162/// How an embedded file relates to the PDF document it is embedded in.
163/// PDF/A-3 and PDF/A-4f.
164#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
165pub enum AssociationKind {
166    /// The PDF document was created from this source file.
167    Source,
168    /// This file was used to derive a visual presentation in the PDF.
169    Data,
170    /// An alternative representation of this document.
171    Alternative,
172    /// Additional resources for this document.
173    Supplement,
174    /// There is no clear relationship or it is not known.
175    Unspecified,
176}
177
178impl AssociationKind {
179    pub(crate) fn to_name(self) -> Name<'static> {
180        match self {
181            Self::Source => Name(b"Source"),
182            Self::Data => Name(b"Data"),
183            Self::Alternative => Name(b"Alternative"),
184            Self::Supplement => Name(b"Supplement"),
185            Self::Unspecified => Name(b"Unspecified"),
186        }
187    }
188}