pdf_writer/
actions.rs

1use super::*;
2
3/// Writer for an _action dictionary_.
4///
5/// This struct is created by [`Annotation::action`] and many keys of
6/// [`AdditionalActions`].
7pub struct Action<'a> {
8    dict: Dict<'a>,
9}
10
11writer!(Action: |obj| {
12    let mut dict = obj.dict();
13    dict.pair(Name(b"Type"), Name(b"Action"));
14    Self { dict }
15});
16
17impl Action<'_> {
18    /// Write the `/S` attribute to set the action type.
19    pub fn action_type(&mut self, kind: ActionType) -> &mut Self {
20        self.pair(Name(b"S"), kind.to_name());
21        self
22    }
23
24    /// Start writing the `/D` attribute to set the destination of this
25    /// GoTo-type action.
26    pub fn destination(&mut self) -> Destination<'_> {
27        self.insert(Name(b"D")).start()
28    }
29
30    /// Write the `/D` attribute to set the destination of this GoTo-type action
31    /// to a named destination.
32    pub fn destination_named(&mut self, name: Name) -> &mut Self {
33        self.pair(Name(b"D"), name);
34        self
35    }
36
37    /// Start writing the `/F` attribute, depending on the [`ActionType`], setting:
38    /// - `RemoteGoTo`: which file to go to
39    /// - `Launch`: which application to launch
40    /// - `SubmitForm`: script location of the webserver that processes the
41    ///   submission
42    /// - `ImportData`: the FDF file from which to import data.
43    pub fn file_spec(&mut self) -> FileSpec<'_> {
44        self.insert(Name(b"F")).start()
45    }
46
47    /// Write the `/NewWindow` attribute to set whether this remote GoTo action
48    /// should open the referenced destination in another window.
49    pub fn new_window(&mut self, new: bool) -> &mut Self {
50        self.pair(Name(b"NewWindow"), new);
51        self
52    }
53
54    /// Write the `/URI` attribute to set where this link action goes.
55    pub fn uri(&mut self, uri: Str) -> &mut Self {
56        self.pair(Name(b"URI"), uri);
57        self
58    }
59
60    /// Write the `/IsMap` attribute to set if the click position of the user's
61    /// cursor inside the link rectangle should be appended to the referenced
62    /// URI as a query parameter.
63    pub fn is_map(&mut self, map: bool) -> &mut Self {
64        self.pair(Name(b"IsMap"), map);
65        self
66    }
67
68    /// Write the `/JS` attribute to set the script of this action as a text
69    /// string. Only permissible for JavaScript and Rendition actions.
70    pub fn js_string(&mut self, script: TextStr) -> &mut Self {
71        self.pair(Name(b"JS"), script);
72        self
73    }
74
75    /// Write the `/JS` attribute to set the script of this action as a text
76    /// stream. The indirect reference shall point to a stream containing valid
77    /// ECMAScript. The stream must have `PdfDocEncoding` or be in Unicode,
78    /// starting with `U+FEFF`. Only permissible for JavaScript and Rendition
79    /// actions.
80    pub fn js_stream(&mut self, script: Ref) -> &mut Self {
81        self.pair(Name(b"JS"), script);
82        self
83    }
84
85    /// Start writing the `/Fields` array to set the fields which are
86    /// [include/exclude](FormActionFlags::INCLUDE_EXCLUDE) when submitting a
87    /// form, resetting a form, or loading an FDF file.
88    pub fn fields(&mut self) -> Fields<'_> {
89        self.insert(Name(b"Fields")).start()
90    }
91
92    /// Write the `/Flags` attribute to set the various characteristics of form
93    /// action.
94    pub fn form_flags(&mut self, flags: FormActionFlags) -> &mut Self {
95        self.pair(Name(b"Flags"), flags.bits() as i32);
96        self
97    }
98
99    /// Write the `/OP` attribute to set the operation to perform when the
100    /// action is triggered.
101    pub fn operation(&mut self, op: RenditionOperation) -> &mut Self {
102        self.pair(Name(b"OP"), op as i32);
103        self
104    }
105
106    /// Write the `/AN` attribute to provide a reference to the screen
107    /// annotation for the operation. Required if OP is present.
108    pub fn annotation(&mut self, id: Ref) -> &mut Self {
109        self.pair(Name(b"AN"), id);
110        self
111    }
112
113    /// Start writing the `/R` dictionary. Only permissible for the subtype
114    /// `Rendition`.
115    pub fn rendition(&mut self) -> Rendition<'_> {
116        self.insert(Name(b"R")).start()
117    }
118}
119
120deref!('a, Action<'a> => Dict<'a>, dict);
121
122/// The operation to perform when a rendition action is triggered.
123#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
124pub enum RenditionOperation {
125    /// Play the rendition specified by /R, and associating it with the
126    /// annotation. If a rendition is already associated with the annotation, it
127    /// shall be stopped, and the new rendition shall be associated with the
128    /// annotation.
129    Play = 0,
130    /// Stop any rendition being played in association with the annotation.
131    Stop = 1,
132    /// Pause any rendition being played in association with the annotation.
133    Pause = 2,
134    /// Resume any rendition being played in association with the annotation.
135    Resume = 3,
136    /// Play the rendition specified by /R, and associating it with the
137    /// annotation, or resume if a rendition is already associated.
138    PlayOrResume = 4,
139}
140
141/// Writer for a _fields array_.
142///
143/// This struct is created by [`Action::fields`].
144pub struct Fields<'a> {
145    array: Array<'a>,
146}
147
148writer!(Fields: |obj| Self { array: obj.array() });
149
150impl Fields<'_> {
151    /// The indirect reference to the field.
152    pub fn id(&mut self, id: Ref) -> &mut Self {
153        self.array.item(id);
154        self
155    }
156
157    /// The indirect references to the fields.
158    pub fn ids(&mut self, ids: impl IntoIterator<Item = Ref>) -> &mut Self {
159        self.array.items(ids);
160        self
161    }
162
163    /// The fully qualified name of the field. PDF 1.3+.
164    pub fn name(&mut self, name: TextStr) -> &mut Self {
165        self.array.item(name);
166        self
167    }
168
169    /// The fully qualified names of the fields. PDF 1.3+.
170    pub fn names<'b>(
171        &mut self,
172        names: impl IntoIterator<Item = TextStr<'b>>,
173    ) -> &mut Self {
174        self.array.items(names);
175        self
176    }
177}
178
179deref!('a, Fields<'a> => Array<'a>, array);
180
181/// What kind of action to perform when clicking a link annotation.
182#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
183pub enum ActionType {
184    /// Go to a destination in the document.
185    GoTo,
186    /// Go to a destination in another document.
187    RemoteGoTo,
188    /// Launch an application.
189    ///
190    /// This action type is forbidden in PDF/A.
191    Launch,
192    /// Open a URI.
193    Uri,
194    /// Set an annotation's hidden flag. PDF 1.2+.
195    SubmitForm,
196    /// Set form fields to their default values. PDF 1.2+.
197    ///
198    /// This action type is forbidden in PDF/A.
199    ResetForm,
200    /// Import form field values from a file. PDF 1.2+.
201    ///
202    /// This action type is forbidden in PDF/A.
203    ImportData,
204    /// Execute a JavaScript action. PDF 1.2+.
205    ///
206    /// See Adobe's
207    /// [JavaScript for Acrobat API Reference](https://opensource.adobe.com/dc-acrobat-sdk-docs/acrobatsdk/pdfs/acrobatsdk_jsapiref.pdf)
208    /// and ISO 21757.
209    ///
210    /// This action type is forbidden in PDF/A.
211    JavaScript,
212    /// A rendition action to control the playing of multimedia content. PDF 1.5+.
213    ///
214    /// This action type is forbidden in PDF/A.
215    Rendition,
216}
217
218impl ActionType {
219    pub(crate) fn to_name(self) -> Name<'static> {
220        match self {
221            Self::GoTo => Name(b"GoTo"),
222            Self::RemoteGoTo => Name(b"GoToR"),
223            Self::Launch => Name(b"Launch"),
224            Self::Uri => Name(b"URI"),
225            Self::SubmitForm => Name(b"SubmitForm"),
226            Self::ResetForm => Name(b"ResetForm"),
227            Self::ImportData => Name(b"ImportData"),
228            Self::JavaScript => Name(b"JavaScript"),
229            Self::Rendition => Name(b"Rendition"),
230        }
231    }
232}
233
234bitflags::bitflags! {
235    /// A set of flags specifying various characteristics of an [`Action`].
236    pub struct FormActionFlags: u32 {
237        /// Whether to include (unset) or exclude (set) the values in the
238        /// `/Fields` attribute on form submission or reset. This Flag has very
239        /// specific interacitons with other flags and fields, read the PDF 1.7
240        /// spec for more info.
241        const INCLUDE_EXCLUDE = 1;
242        /// Fields shall be submitted regardless of if they have a value or
243        /// not, otherwise they are excluded.
244        const INCLUDE_NO_VALUE_FIELDS = 2;
245        /// Export the fields as HTML instead of submitting as FDF. Ignored if
246        /// `SUBMIT_PDF` or `XFDF` are set.
247        const EXPORT_FORMAT = 1 << 2;
248        /// Field name should be submitted using an HTTP GET request, otherwise
249        /// POST. Should only be if `EXPORT_FORMAT` is also set.
250        const GET_METHOD = 1 << 3;
251        /// Include the coordinates of the mouse when submit was pressed. Should
252        /// only be if `EXPORT_FORMAT` is also set.
253        const SUBMIT_COORDINATES = 1 << 4;
254        /// Submit field names and values as XFDF instead of submitting an FDF.
255        /// Should not be set if `SUBMIT_PDF` is set. PDF1.4+.
256        const XFDF = 1 << 5;
257        /// Include all updates done to the PDF document in the submission FDF
258        /// file. Should only be used when `XFDF` and `EXPORT_FORMAT` are not
259        /// set. PDF 1.4+.
260        const INCLUDE_APPEND_SAVES = 1 << 6;
261        /// Include all markup annotations of the PDF dcoument in the submission
262        /// FDF file. Should only be used when `XFDF` and `EXPORT_FORMAT` are
263        /// not set. PDF 1.4+.
264        const INCLUDE_ANNOTATIONS = 1 << 7;
265        /// Submit the PDF file instead of an FDF file. All other flags other
266        /// than `GET_METHOD` are ignored if this is set. PDF 1.4+.
267        const SUBMIT_PDF = 1 << 8;
268        /// Convert fields which represent dates into the
269        /// [canonical date format](crate::types::Date). The interpretation of
270        /// a form field as a date is is not specified in the field but the
271        /// JavaScript code that processes it. PDF 1.4+.
272        const CANONICAL_FORMAT = 1 << 9;
273        /// Include only the markup annotations made by the current user (the
274        /// `/T` entry of the annotation) as determined by the remote server
275        /// the form will be submitted to. Should only be used when `XFDF` and
276        /// `EXPORT_FORMAT` are not set and `INCLUDE_ANNOTATIONS` is set. PDF
277        /// 1.4+.
278        const EXCLUDE_NON_USER_ANNOTS = 1 << 10;
279        /// Include the F entry in the FDF file.
280        /// Should only be used when `XFDF` and `EXPORT_FORMAT` are not set.
281        /// PDF 1.4+
282        const EXCLUDE_F_KEY = 1 << 11;
283        /// Include the PDF file as a stream in the FDF file that will be submitted.
284        /// Should only be used when `XFDF` and `EXPORT_FORMAT` are not set.
285        /// PDF 1.5+.
286        const EMBED_FORM = 1 << 13;
287    }
288}
289
290/// Writer for an _additional actions dictionary_.
291///
292/// This struct is created by [`Annotation::additional_actions`],
293/// [`Field::additional_actions`], [`Page::additional_actions`] and
294/// [`Catalog::additional_actions`].
295pub struct AdditionalActions<'a> {
296    dict: Dict<'a>,
297}
298
299writer!(AdditionalActions: |obj| Self { dict: obj.dict() });
300
301/// Only permissible for [annotations](Annotation).
302impl AdditionalActions<'_> {
303    /// Start writing the `/E` dictionary. An action that shall be performed
304    /// when the cursor enters the annotation's active area. Only permissible
305    /// for annotations. PDF 1.2+.
306    pub fn annot_curser_enter(&mut self) -> Action<'_> {
307        self.insert(Name(b"E")).start()
308    }
309
310    /// Start writing the `/X` dictionary. An action that shall be performed
311    /// when the cursor exits the annotation's active area. Only permissible for
312    /// annotations. PDF 1.2+.
313    pub fn annot_cursor_exit(&mut self) -> Action<'_> {
314        self.insert(Name(b"X")).start()
315    }
316
317    /// Start writing the `/D` dictionary. This sets the action action
318    /// that shall be performed when the mouse button is pressed inside the
319    /// annotation's active area. Only permissible for annotations. PDF 1.2+.
320    pub fn annot_mouse_press(&mut self) -> Action<'_> {
321        self.insert(Name(b"D")).start()
322    }
323
324    /// Start writing the `/U` dictionary. This sets the action action that
325    /// shall be performed when the mouse button is released inside the
326    /// annotation's active area. Only permissible for annotations. PDF 1.2+.
327    pub fn annot_mouse_release(&mut self) -> Action<'_> {
328        self.insert(Name(b"U")).start()
329    }
330
331    /// Start writing the `/PO` dictionary. This sets the action action that
332    /// shall be performed when the page containing the annotation is opened.
333    /// Only permissible for annotations. PDF 1.5+.
334    pub fn annot_page_open(&mut self) -> Action<'_> {
335        self.insert(Name(b"PO")).start()
336    }
337
338    /// Start writing the `/PC` dictionary. This sets the action action that
339    /// shall be performed when the page containing the annotation is closed.
340    /// Only permissible for annotations. PDF 1.5+.
341    pub fn annot_page_close(&mut self) -> Action<'_> {
342        self.insert(Name(b"PV")).start()
343    }
344
345    /// Start writing the `/PV` dictionary. This sets the action action that
346    /// shall be performed when the page containing the annotation becomes
347    /// visible. Only permissible for annotations. PDF 1.5+.
348    pub fn annot_page_visible(&mut self) -> Action<'_> {
349        self.insert(Name(b"PV")).start()
350    }
351
352    /// Start writing the `/PI` dictionary. This sets the action action that
353    /// shall be performed when the page containing the annotation is no longer
354    /// visible in the conforming reader's user interface. Only permissible for
355    /// annotations. PDF 1.5+.
356    pub fn annot_page_invisible(&mut self) -> Action<'_> {
357        self.insert(Name(b"PI")).start()
358    }
359}
360
361/// Only permissible for [widget](crate::types::AnnotationType::Widget)
362/// [annotations](Annotation).
363impl AdditionalActions<'_> {
364    /// Start writing the `/Fo` dictionary. This sets the action that shall be
365    /// performed when the annotation receives the input focus. Only permissible
366    /// for widget annotations. PDF 1.2+.
367    pub fn widget_focus(&mut self) -> Action<'_> {
368        self.insert(Name(b"Fo")).start()
369    }
370
371    /// Start writing the `/Bl` dictionary. This sets the action that shall be
372    /// performed when the annotation loses the input focus. Only permissible
373    /// for widget annotations. PDF 1.2+.
374    pub fn widget_focus_loss(&mut self) -> Action<'_> {
375        self.insert(Name(b"Bl")).start()
376    }
377}
378
379/// Only permissible for [page objects](Page).
380impl AdditionalActions<'_> {
381    /// Start writing the `/O` dictionary. This sets the action that shall be
382    /// performed when the page is opened. This action is independent of any
383    /// that may be defined by the open action entry in the
384    /// [document catalog](Catalog) and shall be executed after such an action.
385    /// Only permissible for [page objects](Page). PDF 1.2+.
386    pub fn page_open(&mut self) -> Action<'_> {
387        self.insert(Name(b"O")).start()
388    }
389
390    /// Start writing the `/C` dictionary. This sets the action that shall
391    /// be performed when the page is closed. This action applies to the page
392    /// being closed and shall be executed before any other page is opened. Only
393    /// permissible for [page objects](Page). PDF 1.2+.
394    pub fn page_close(&mut self) -> Action<'_> {
395        self.insert(Name(b"C")).start()
396    }
397}
398
399/// Only permisible for form fields.
400impl AdditionalActions<'_> {
401    /// Start writing the `/K` dictionary. This sets the JavaScript action that
402    /// shall be performed when the user modifies a character in a text field
403    /// or combo box or modifies the selection in a scrollable list box. This
404    /// action may check the added text for validity and reject or modify it.
405    /// Only permissible for form fields. PDF 1.3+.
406    pub fn form_calculate_partial(&mut self) -> Action<'_> {
407        self.insert(Name(b"K")).start()
408    }
409
410    /// Start writing the `/F` dictionary. This sets the JavaScript action
411    /// that shall be performed before the field is formatted to display its
412    /// value. This action may modify the field's value before formatting. Only
413    /// permissible for form fields. PDF 1.3+.
414    pub fn form_format(&mut self) -> Action<'_> {
415        self.insert(Name(b"F")).start()
416    }
417
418    /// Start writing the `/V` dictionary. This sets the JavaScript action that
419    /// shall be performed when the field's value is changed. This action may
420    /// check the new value for validity. Only permissible for form fields.
421    /// PDF 1.3+.
422    pub fn form_validate(&mut self) -> Action<'_> {
423        self.insert(Name(b"V")).start()
424    }
425
426    /// Start writing the `/C` dictionary. This sets the JavaScript action that
427    /// shall be performed to recalculate the value of this field when that
428    /// of another field changes. The order in which the document's fields are
429    /// recalculated shall be defined by the `/CO` entry in the interactive form
430    /// dictionary. Only permissible for form fields. PDF 1.3+.
431    pub fn form_calculate(&mut self) -> Action<'_> {
432        self.insert(Name(b"C")).start()
433    }
434}
435
436/// Only permisible for [document catalog](Catalog).
437impl AdditionalActions<'_> {
438    /// Start writing the `/WC` dictionary. This sets the JavaScript action
439    /// that shall be performed before closing a document. Only permissible for
440    /// the [document catalog](Catalog) PDF 1.4+.
441    pub fn cat_before_close(&mut self) -> Action<'_> {
442        self.insert(Name(b"WC")).start()
443    }
444
445    /// Start writing the `/WS` dictionary. This sets the JavaScript action
446    /// that shall be performed before saving a document. Only permissible for
447    /// the [document catalog](Catalog) PDF 1.4+.
448    pub fn cat_before_save(&mut self) -> Action<'_> {
449        self.insert(Name(b"WS")).start()
450    }
451
452    /// Start writing the `/DS` dictionary. This sets the JavaScript action
453    /// that shall be performed after saving a document. Only permissible for
454    /// the [document catalog](Catalog) PDF 1.4+.
455    pub fn cat_after_save(&mut self) -> Action<'_> {
456        self.insert(Name(b"DS")).start()
457    }
458
459    /// Start writing the `/WP` dictionary. This sets the JavaScript action
460    /// that shall be performed before printing a document. Only permissible for
461    /// the [document catalog](Catalog) PDF 1.4+.
462    pub fn cat_before_print(&mut self) -> Action<'_> {
463        self.insert(Name(b"WP")).start()
464    }
465
466    /// Start writing the `/DP` dictionary. This sets the JavaScript action
467    /// that shall be performed after printing a document. Only permissible for
468    /// the [document catalog](Catalog) PDF 1.4+.
469    pub fn cat_after_print(&mut self) -> Action<'_> {
470        self.insert(Name(b"DP")).start()
471    }
472}
473
474deref!('a, AdditionalActions<'a> => Dict<'a>, dict);