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}