pdf_writer/
files.rs

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