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}