pdf_writer/
files.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
use super::*;

/// Writer for a _file specification dictionary_.
///
/// This struct is created by [`Annotation::file_spec`],
/// [`Reference::file_spec`], [`MediaClip::data`], and [`Action::file_spec`].
pub struct FileSpec<'a> {
    dict: Dict<'a>,
}

writer!(FileSpec: |obj| {
    let mut dict = obj.dict();
    dict.pair(Name(b"Type"), Name(b"Filespec"));
    Self { dict }
});

impl<'a> FileSpec<'a> {
    /// Write the `/FS` attribute to set the file system this entry relates to.
    /// If you set the `system` argument to `Name(b"URL")`, this becomes an URL
    /// specification.
    pub fn file_system(&mut self, system: Name) -> &mut Self {
        self.pair(Name(b"FS"), system);
        self
    }

    /// Write the `/F` attribute to set the file path. Directories are indicated
    /// by `/`, independent of the platform.
    pub fn path(&mut self, path: Str) -> &mut Self {
        self.pair(Name(b"F"), path);
        self
    }

    /// Write the `/UF` attribute to set a Unicode-compatible path. Directories
    /// are indicated by `/`, independent of the platform. PDF 1.7+.
    pub fn unic_file(&mut self, path: TextStr) -> &mut Self {
        self.pair(Name(b"UF"), path);
        self
    }

    /// Write the `/V` attribute to indicate whether _not_ to cache the file.
    pub fn volatile(&mut self, dont_cache: bool) -> &mut Self {
        self.pair(Name(b"V"), dont_cache);
        self
    }

    /// Write the `/Desc` attribute to set a file description. PDF 1.6+.
    pub fn description(&mut self, desc: TextStr) -> &mut Self {
        self.pair(Name(b"Desc"), desc);
        self
    }

    /// Write the `/EF` attribute to reference an [embedded file](EmbeddedFile).
    /// PDF 1.3+.
    ///
    /// This only sets an embedded file for the `F` attribute corresponding to
    /// the [`path`](Self::path) method. If you want to set the same embedded
    /// file for the `UF` attribute, also call [`Self::embedded_file_with_unicode`]
    /// instead.
    ///
    /// Note that this key is forbidden in PDF/A-1 and restricted in PDF/A-2 and
    /// PDF/A-4.
    pub fn embedded_file(&mut self, id: Ref) -> &mut Self {
        self.insert(Name(b"EF")).dict().pair(Name(b"F"), id);
        self
    }

    /// Write the `/EF` attribute to reference an [embedded file](EmbeddedFile)
    /// for the legacy and Unicode-compatible file path. PDF 1.7+.
    ///
    /// Note that this key is forbidden in PDF/A-1 and restricted in PDF/A-2 an
    /// PDF/A-4.
    pub fn embedded_file_with_unicode(&mut self, id: Ref) -> &mut Self {
        self.insert(Name(b"EF"))
            .dict()
            .pair(Name(b"F"), id)
            .pair(Name(b"UF"), id);
        self
    }

    /// How this file relates to the PDF document it is embedded in.
    /// PDF/A-3 and PDF/A-4f.
    pub fn association_kind(&mut self, kind: AssociationKind) -> &mut Self {
        self.pair(Name(b"AFRelationship"), kind.to_name());
        self
    }
}

deref!('a, FileSpec<'a> => Dict<'a>, dict);

/// Writer for an _embedded file stream_.
///
/// This struct is created by [`Chunk::embedded_file`].
pub struct EmbeddedFile<'a> {
    stream: Stream<'a>,
}

impl<'a> EmbeddedFile<'a> {
    /// Create a new embedded file writer.
    pub(crate) fn start(mut stream: Stream<'a>) -> Self {
        stream.pair(Name(b"Type"), Name(b"EmbeddedFile"));
        Self { stream }
    }

    /// Write the `/Subtype` attribute to set the file type.
    ///
    /// This can either be a MIME type or a name prefixed by a first class PDF
    /// prefix. Note that special characters must be encoded as described in
    /// section 7.3.5 of the PDF 1.7 specification, e.g. `image/svg+xml` would
    /// become `Name(b"image#2Fsvg+xml")`.
    pub fn subtype(&mut self, subtype: Name) -> &mut Self {
        self.pair(Name(b"Subtype"), subtype);
        self
    }

    /// Start writing the `/Params` dictionary.
    pub fn params(&mut self) -> EmbeddingParams<'_> {
        self.insert(Name(b"Params")).start()
    }
}

deref!('a, EmbeddedFile<'a> => Stream<'a>, stream);

/// Writer for an _embedded file parameter dictionary_.
///
/// This struct is created by [`EmbeddedFile::params`].
pub struct EmbeddingParams<'a> {
    dict: Dict<'a>,
}

writer!(EmbeddingParams: |obj| Self { dict: obj.dict() });

impl<'a> EmbeddingParams<'a> {
    /// Write the `/Size` attribute to set the uncompressed file size in bytes.
    pub fn size(&mut self, size: i32) -> &mut Self {
        self.pair(Name(b"Size"), size);
        self
    }

    /// Write the `/CreationDate` attribute to set the file creation date.
    pub fn creation_date(&mut self, date: Date) -> &mut Self {
        self.pair(Name(b"CreationDate"), date);
        self
    }

    /// Write the `/ModDate` attribute to set the file modification date.
    pub fn modification_date(&mut self, date: Date) -> &mut Self {
        self.pair(Name(b"ModDate"), date);
        self
    }

    /// Write the `/CheckSum` attribute to set the file checksum.
    ///
    /// The checksum shall be a 16-byte MD5 string.
    pub fn checksum(&mut self, checksum: Str) -> &mut Self {
        self.pair(Name(b"CheckSum"), checksum);
        self
    }
}

deref!('a, EmbeddingParams<'a> => Dict<'a>, dict);

/// How an embedded file relates to the PDF document it is embedded in.
/// PDF/A-3 and PDF/A-4f.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub enum AssociationKind {
    /// The PDF document was created from this source file.
    Source,
    /// This file was used to derive a visual presentation in the PDF.
    Data,
    /// An alternative representation of this document.
    Alternative,
    /// Additional resources for this document.
    Supplement,
    /// There is no clear relationship or it is not known.
    Unspecified,
}

impl AssociationKind {
    pub(crate) fn to_name(self) -> Name<'static> {
        match self {
            Self::Source => Name(b"Source"),
            Self::Data => Name(b"Data"),
            Self::Alternative => Name(b"Alternative"),
            Self::Supplement => Name(b"Supplement"),
            Self::Unspecified => Name(b"Unspecified"),
        }
    }
}