pdf_writer/
forms.rs

1use super::*;
2use crate::types::AnnotationType;
3
4/// Writer for an _interactive forms dictionary_. PDF 1.2+.
5///
6/// This struct is created by [`Catalog::form`].
7pub struct Form<'a> {
8    dict: Dict<'a>,
9}
10
11writer!(Form: |obj| Self { dict: obj.dict() });
12
13impl Form<'_> {
14    /// Write the `/Fields` attribute to reference the root [form fields](Field)
15    /// (those who have no immediate parent) of this document.
16    pub fn fields(&mut self, fields: impl IntoIterator<Item = Ref>) -> &mut Self {
17        self.insert(Name(b"Fields")).array().items(fields);
18        self
19    }
20
21    /// Write the `/SigFlags` attribute to set various document-level
22    /// characteristics related to signature fields.
23    pub fn sig_flags(&mut self, flags: SigFlags) -> &mut Self {
24        self.pair(Name(b"SigFlags"), flags.bits() as i32);
25        self
26    }
27
28    /// Write the `/CO` attribute to set the field dictionaries with calculation
29    /// actions, defining the calculation order in which their values will be
30    /// recalculated when the value of any field changes.
31    pub fn calculation_order(
32        &mut self,
33        actions: impl IntoIterator<Item = Ref>,
34    ) -> &mut Self {
35        self.insert(Name(b"CO")).array().items(actions);
36        self
37    }
38
39    /// Start writing the `/DR` attribute to set the default resources
40    /// that shall be used by form field appearance streams. At a minimum, this
41    /// dictionary shall contain a font entry specifying the resource name and
42    /// font dictionary of the default font for displaying text.
43    pub fn default_resources(&mut self) -> Resources<'_> {
44        self.insert(Name(b"DR")).start()
45    }
46
47    /// Write the document-wide default value for the `/DA` attribute of
48    /// fields containing variable text. See
49    /// [`Field::vartext_default_appearance`].
50    pub fn default_appearance(&mut self, default: Str) -> &mut Self {
51        self.pair(Name(b"DA"), default);
52        self
53    }
54
55    /// Write the document-wide default value for the `/Q` attribute of
56    /// fields containing variable text. See [`Field::vartext_quadding`].
57    pub fn quadding(&mut self, default: Quadding) -> &mut Self {
58        self.pair(Name(b"Q"), default as i32);
59        self
60    }
61}
62
63deref!('a, Form<'a> => Dict<'a>, dict);
64
65bitflags::bitflags! {
66    /// Bitflags describing various document-level characteristics related to
67    /// signature fields.
68    pub struct SigFlags: u32 {
69        /// The document contains at least one signature field.
70        const SIGNATURES_EXIST = 1;
71
72        /// The document contains signatures that may be invalidated if the
73        /// file is saved (written) in a way that alters its previous contents,
74        /// as opposed to an incremental update. Merely updating the file by
75        /// appending new information to the end of the previous version is
76        /// safe.
77        const APPEND_ONLY = 2;
78    }
79}
80
81/// Writer for an _form field dictionary_.
82///
83/// This struct is created by [`Chunk::form_field`].
84pub struct Field<'a> {
85    dict: Dict<'a>,
86}
87
88writer!(Field: |obj| Self { dict: obj.dict() });
89
90/// Permissible on all fields.
91impl<'a> Field<'a> {
92    /// Write the `/FT` attribute to set the type of this field.
93    pub fn field_type(&mut self, typ: FieldType) -> &mut Self {
94        self.pair(Name(b"FT"), typ.to_name());
95        self
96    }
97
98    /// Write the `/Parent` attribute to set the immediate parent of this
99    /// field.
100    pub fn parent(&mut self, id: Ref) -> &mut Self {
101        self.pair(Name(b"Parent"), id);
102        self
103    }
104
105    /// Write the `/Kids` attribute to set the immediate children of this field.
106    /// These references shall refer to other [fields][Field], or
107    /// [widget](crate::types::AnnotationType::Widget) [annotations](Annotation).
108    pub fn children(&mut self, children: impl IntoIterator<Item = Ref>) -> &mut Self {
109        self.insert(Name(b"Kids")).array().items(children);
110        self
111    }
112
113    /// Write the `/T` attribute to set the partial field name.
114    ///
115    /// The fully qualified field name of a field is a path along it's
116    /// ancestor's partial field names separated by periods `.`. Therefore, a
117    /// partial field name may not contain a period `.`.
118    ///
119    /// If two fields have the same parent and no partial field name, then they
120    /// refer to two representations of the same field and should only differ
121    /// in properties that specify their visual appearance. In particular, they
122    /// should have the same `/FT`, `/V` and `/DV` attribute values.
123    pub fn partial_name(&mut self, name: TextStr) -> &mut Self {
124        self.pair(Name(b"T"), name);
125        self
126    }
127
128    /// Write the `/TU` attribute to set the alternative field name. This
129    /// field name is used in place of the actual field name whenever the field
130    /// shall be identified in the user interface (such as in error or status
131    /// messages). This text is also useful when extracting the document's
132    /// contents in support of accessibility to users with disabilities or for
133    /// other purposes. PDF 1.3+.
134    pub fn alternate_name(&mut self, alternate: TextStr) -> &mut Self {
135        self.pair(Name(b"TU"), alternate);
136        self
137    }
138
139    /// Write the `/TM` attribute to set the mapping field name. This
140    /// name shall be used when exporting interactive form field data from the
141    /// document.
142    pub fn mapping_name(&mut self, name: TextStr) -> &mut Self {
143        self.pair(Name(b"TM"), name);
144        self
145    }
146
147    /// Write the `/Ff` attribute to set various characteristics of this
148    /// field.
149    pub fn field_flags(&mut self, flags: FieldFlags) -> &mut Self {
150        self.pair(Name(b"Ff"), flags.bits() as i32);
151        self
152    }
153
154    /// Start writing the `/AA` dictionary to set the field's response to
155    /// various trigger events.
156    ///
157    /// Note that this attribute is forbidden in PDF/A.
158    pub fn additional_actions(&mut self) -> AdditionalActions<'_> {
159        self.insert(Name(b"AA")).start()
160    }
161
162    /// Finish writing this field as a widget annotation. This is encouraged
163    /// for fields which are non-root and terminal (i.e. they have a parent and
164    /// no children).
165    ///
166    /// While the widget annotation could be a single child to a
167    /// terminal field, most readers will not correctly read the form
168    /// field, if it's not merged with its annotation.
169    pub fn into_annotation(mut self) -> Annotation<'a> {
170        self.dict.pair(Name(b"Type"), Name(b"Annot"));
171        let mut annot = Annotation { dict: self.dict };
172        annot.subtype(AnnotationType::Widget);
173        annot
174    }
175}
176
177deref!('a, Field<'a> => Dict<'a>, dict);
178
179/// The type of a [`Field`].
180#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
181pub enum FieldType {
182    /// A button field, includes push buttons, check boxes and radio buttons.
183    Button,
184    /// A text field, a box which a user can enter text into.
185    Text,
186    /// A choice field, list or combo boxes out of which the user may chose at
187    /// most one.
188    Choice,
189    /// A signature field, fields which contain digital signatures and optional
190    /// authentication data. PDF 1.3+.
191    Signature,
192}
193
194impl FieldType {
195    pub(crate) fn to_name(self) -> Name<'static> {
196        match self {
197            Self::Button => Name(b"Btn"),
198            Self::Text => Name(b"Tx"),
199            Self::Choice => Name(b"Ch"),
200            Self::Signature => Name(b"Sig"),
201        }
202    }
203}
204
205/// Only permissible on button fields.
206impl Field<'_> {
207    /// Write the `/Opt` array to set the export values of children of this
208    /// field. Only permissible on checkbox fields, or radio button fields.
209    /// PDF 1.4+.
210    pub fn button_options<'b>(
211        &mut self,
212        options: impl IntoIterator<Item = TextStr<'b>>,
213    ) -> &mut Self {
214        self.insert(Name(b"Opt")).array().items(options);
215        self
216    }
217}
218
219/// Only permissible on check box fields.
220impl Field<'_> {
221    /// Write the `/V` attribute to set the state of this check box field. The
222    /// state corresponds to an appearance stream in the [appearance
223    /// dictionary](AppearanceCharacteristics) of this field's widget
224    /// [annotation](Annotation). Only permissible on check box fields.
225    pub fn checkbox_value(&mut self, state: CheckBoxState) -> &mut Self {
226        self.pair(Name(b"V"), state.to_name());
227        self
228    }
229
230    /// Write the `/DV` attribute to set the default state of this check box
231    /// field. The state corresponds to an appearance stream in the [appearance
232    /// dictionary](AppearanceCharacteristics) of this field's widget
233    /// [annotation](Annotation). Only permissible on check box fields.
234    pub fn checkbox_default_value(&mut self, state: CheckBoxState) -> &mut Self {
235        self.pair(Name(b"DV"), state.to_name());
236        self
237    }
238}
239
240/// The state of a check box [`Field`].
241pub enum CheckBoxState {
242    /// The check box selected state `/Yes`.
243    Yes,
244    /// The check box unselected state `/Off`.
245    Off,
246}
247
248impl CheckBoxState {
249    pub(crate) fn to_name(self) -> Name<'static> {
250        match self {
251            Self::Yes => Name(b"Yes"),
252            Self::Off => Name(b"Off"),
253        }
254    }
255}
256
257/// Only permissible on radio button fields.
258impl Field<'_> {
259    /// Write the `/V` attribute to set the state of this radio button field.
260    /// The state corresponds to an appearance stream in the
261    /// [appearance subdictionary](Appearance) of this field's widget
262    /// [annotation](Annotation) and is either a custom name unique for
263    /// all unique fields, or `/Off`. Only permissible on radio button fields.
264    pub fn radio_value(&mut self, state: Name) -> &mut Self {
265        self.pair(Name(b"V"), state);
266        self
267    }
268
269    /// Write the `/DV` attribute to set the default state of this radio button
270    /// field. The state corresponds to an appearance stream in the
271    /// [appearance subdictionary](Appearance) of this field's widget
272    /// [annotation](Annotation) and is either a custom name unique for
273    /// all unique fields, or `/Off`. Only permissible on radio button fields.
274    pub fn radio_default_value(&mut self, state: Name) -> &mut Self {
275        self.pair(Name(b"DV"), state);
276        self
277    }
278}
279
280/// Only permissible on text fields.
281impl Field<'_> {
282    /// Write the `/MaxLen` attribute to set the maximum length of the fields
283    /// text in characters. Only permissible on text fields.
284    ///
285    /// The definition of a chracter depends on the encoding of the content of
286    /// `/V`. Which is either one byte for PDFDocEncoding or 2 for UTF16-BE.
287    pub fn text_max_len(&mut self, len: i32) -> &mut Self {
288        self.pair(Name(b"MaxLen"), len);
289        self
290    }
291
292    /// Write the `/V` attribute to set the value of this text field.
293    /// Only permissible on text fields.
294    pub fn text_value(&mut self, value: TextStr) -> &mut Self {
295        self.pair(Name(b"V"), value);
296        self
297    }
298
299    /// Start writing the `/DV` attribute to set the default value of this text
300    /// field. Only permissible on text fields.
301    pub fn text_default_value(&mut self, value: TextStr) -> &mut Self {
302        self.pair(Name(b"DV"), value);
303        self
304    }
305}
306
307/// Only permissible on fields containing variable text.
308impl Field<'_> {
309    /// Write the `/DA` attribute containing a sequence of valid page-content
310    /// graphics or text state operators that define such properties as the
311    /// field's text size and colour. Only permissible on fields containing
312    /// variable text.
313    pub fn vartext_default_appearance(&mut self, appearance: Str) -> &mut Self {
314        self.pair(Name(b"DA"), appearance);
315        self
316    }
317
318    /// Write the `/Q` attribute to set the quadding (justification) that shall
319    /// be used in dispalying the text. Only permissible on fields containing
320    /// variable text.
321    pub fn vartext_quadding(&mut self, quadding: Quadding) -> &mut Self {
322        self.pair(Name(b"Q"), quadding as i32);
323        self
324    }
325
326    /// Write the `/DS` attribute to set the default style string. Only
327    /// permissible on fields containing variable text. PDF 1.5+.
328    pub fn vartext_default_style(&mut self, style: TextStr) -> &mut Self {
329        self.pair(Name(b"DS"), style);
330        self
331    }
332
333    /// Write the `/RV` attribute to set the value of this variable text field.
334    /// Only permissible on fields containing variable text. PDF 1.5+.
335    pub fn vartext_rich_value(&mut self, value: TextStr) -> &mut Self {
336        self.pair(Name(b"RV"), value);
337        self
338    }
339}
340
341/// The quadding (justification) of a field containing variable text.
342#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
343pub enum Quadding {
344    /// Left justify the text.
345    Left = 0,
346    /// Center justify the text.
347    Center = 1,
348    /// Right justify the text.
349    Right = 2,
350}
351
352/// Only permissible on choice fields.
353impl Field<'_> {
354    /// Start writing the `/Opt` array to set the options that shall be
355    /// presented to the user.
356    pub fn choice_options(&mut self) -> ChoiceOptions<'_> {
357        self.insert(Name(b"Opt")).start()
358    }
359
360    /// Write the `/TI` attribute to set the index in the
361    /// [`Field::choice_options`] array of the first visible option for
362    /// scrollable lists.
363    pub fn choice_top_index(&mut self, index: i32) -> &mut Self {
364        self.pair(Name(b"TI"), index);
365        self
366    }
367
368    /// Write the `/I` array to set the indices of the currently selected
369    /// options. The integers in this array must be sorted in ascending order
370    /// and correspond to 0-based indices in the [`Field::choice_options`]
371    /// array.
372    ///
373    /// This entry shall be used for choice fields which allow multiple
374    /// selections ([`FieldFlags::MULTI_SELECT`]). This means when two or more
375    /// elements in the [`Field::choice_options`] array have different names
376    /// but export the same value or when the value fo the choice field is an
377    /// array. This entry should not be used for choice fields that do not allow
378    /// multiple selections. PDF 1.4+.
379    pub fn choice_indices(
380        &mut self,
381        indices: impl IntoIterator<Item = i32>,
382    ) -> &mut Self {
383        self.insert(Name(b"I")).array().items(indices);
384        self
385    }
386
387    /// Write the `/V` attribute to set the currently selected values
388    /// of this choice field. Should be one of the values given in
389    /// [`Self::choice_options`] or `None` if no choice is selected. Only
390    /// permissible on choice fields.
391    pub fn choice_value(&mut self, option: Option<TextStr>) -> &mut Self {
392        match option {
393            Some(value) => self.pair(Name(b"V"), value),
394            None => self.pair(Name(b"V"), Null),
395        };
396        self
397    }
398
399    /// Write the `/V` attribute to set the currently selected values of this
400    /// choice field. See also [`Self::choice_value`], for a single or no value.
401    /// Only permissible on choice fields.
402    pub fn choice_values<'b>(
403        &mut self,
404        options: impl IntoIterator<Item = TextStr<'b>>,
405    ) -> &mut Self {
406        self.insert(Name(b"V")).array().items(options);
407        self
408    }
409
410    /// Write the `/DV` attribute to set the default selected value
411    /// of this choice field. Should be one of the values given in
412    /// [`Self::choice_options`] or `None` if no choice is selected. Only
413    /// permissible on choice fields.
414    pub fn choice_default_value(&mut self, option: Option<TextStr>) -> &mut Self {
415        match option {
416            Some(value) => self.pair(Name(b"DV"), value),
417            None => self.pair(Name(b"DV"), Null),
418        };
419        self
420    }
421
422    /// Write the `/DV` attribute to set the default selected values of this
423    /// choice field. See also [`Self::choice_default_value`], for a single or
424    /// no value. Only permissible on choice fields.
425    pub fn choice_default_values<'b>(
426        &mut self,
427        options: impl IntoIterator<Item = TextStr<'b>>,
428    ) -> &mut Self {
429        self.insert(Name(b"DV")).array().items(options);
430        self
431    }
432}
433
434/// Writer for a _choice options array_.
435///
436/// This struct is created by [`Field::choice_options`].
437pub struct ChoiceOptions<'a> {
438    array: Array<'a>,
439}
440
441writer!(ChoiceOptions: |obj| Self { array: obj.array() });
442
443impl ChoiceOptions<'_> {
444    /// Add an option with the given value.
445    pub fn option(&mut self, value: TextStr) -> &mut Self {
446        self.array.item(value);
447        self
448    }
449
450    /// Add options with the given values.
451    pub fn options<'b>(
452        &mut self,
453        values: impl IntoIterator<Item = TextStr<'b>>,
454    ) -> &mut Self {
455        self.array.items(values);
456        self
457    }
458
459    /// Add an option with the given value and export value.
460    pub fn export(&mut self, value: TextStr, export_value: TextStr) -> &mut Self {
461        self.array.push().array().items([export_value, value]);
462        self
463    }
464
465    /// Add options with the given pairs of value and export value.
466    pub fn exports<'b>(
467        &mut self,
468        values: impl IntoIterator<Item = (TextStr<'b>, TextStr<'b>)>,
469    ) -> &mut Self {
470        for (value, export) in values {
471            self.export(value, export);
472        }
473        self
474    }
475}
476
477deref!('a, ChoiceOptions<'a> => Array<'a>, array);
478
479bitflags::bitflags! {
480    /// Bitflags describing various characteristics of a form field.
481    pub struct FieldFlags: u32 {
482        /// The user may not change the value of the field. Any associated
483        /// widget annotations will not interact with the user; that is, they
484        /// will not respond to mouse clicks or change their appearance in
485        /// response to mouse motions. This flag is useful for fields whose
486        /// values are computed or imported from a database.
487        const READ_ONLY = 1;
488        /// The field shall have a value at the time it is exported by a
489        /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`].
490        const REQUIRED = 2;
491        /// The field shall not be exported by a
492        /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`].
493        const NO_EXPORT = 1 << 2;
494        /// The entered text shall not be spell-checked, can be used for text
495        /// and choice fields.
496        const DO_NOT_SPELL_CHECK = 1 << 22;
497
498        // Button specific flags
499
500        /// Exactly one radio button shall be selected at all times; selecting
501        /// the currently selected button has no effect. If unset, clicking
502        /// the selected button deselects it, leaving no button selected. Only
503        /// permissible for radio buttons.
504        const NO_TOGGLE_TO_OFF = 1 << 14;
505        /// The field is a set of radio buttons; if clear, the field is a check
506        /// box. This flag may be set only if the `PUSHBUTTON` flag is unset.
507        const RADIO = 1 << 15;
508        /// The field is a push button that does not retain a permanent
509        /// value.
510        const PUSHBUTTON = 1 << 16;
511        /// A group of radio buttons within a radio button field that use the
512        /// same value for the on state will turn on and off in unison; that
513        /// is if one is checked, they are all checked. If unset, the buttons
514        /// are mutually exclusive (the same behavior as HTML radio buttons).
515        /// PDF 1.5+.
516        const RADIOS_IN_UNISON = 1 << 25;
517
518        // Text field specific flags
519
520        /// The text may contain multiple lines of text, otherwise the text is
521        /// restricted to one line.
522        const MULTILINE = 1 << 12;
523        /// The text contains a password and should not be echoed visibly to
524        /// the screen.
525        const PASSWORD = 1 << 13;
526        /// The entered text represents a path to a file who's contents shall be
527        /// submitted as the value of the field. PDF 1.4+.
528        const FILE_SELECT = 1 << 20;
529        /// The field shall not scroll horizontally (for single-line) or
530        /// vertically (for multi-line) to accomodate more text. Once the field
531        /// is full, no further text shall be accepted for interactive form
532        /// filling; for non-interactive form filling, the filler should take
533        /// care not to add more character than will visibly fit in the defined
534        /// area. PDF 1.4+.
535        const DO_NOT_SCROLL = 1 << 23;
536        /// The field shall be automatically divided into as many equally
537        /// spaced positions or _combs_ as the value of [`Field::max_len`]
538        /// and the text is layed out into these combs. May only be set if
539        /// the [`Field::max_len`] property is set and if the [`MULTILINE`],
540        /// [`PASSWORD`] and [`FILE_SELECT`] flags are clear. PDF 1.5+.
541        const COMB = 1 << 24;
542        /// The value of this field shall be a rich text string. If the field
543        /// has a value, the [`TextField::rich_text_value`] shall specify the
544        /// rich text string. PDF 1.5+.
545        const RICH_TEXT = 1 << 25;
546
547        // Choice field specific flags
548
549        /// The field is a combo box if set, else it's a list box. A combo box
550        /// is often referred to as a dropdown menu.
551        const COMBO = 1 << 17;
552        /// The combo box shall include an editable text box as well as a
553        /// drop-down list. Shall only be used if [`COMBO`] is set.
554        const EDIT = 1 << 18;
555        /// The field’s option items shall be sorted alphabetically. This
556        /// flag is intended for use by writers, not by readers.
557        const SORT = 1 << 19;
558        /// More than one option of the choice field may be selected
559        /// simultaneously. PDF 1.4+.
560        const MULTI_SELECT = 1 << 21;
561        /// The new value shall be committed as soon as a selection is made
562        /// (commonly with the mouse). In this case, supplying a value for
563        /// a field involves three actions: selecting the field for fill-in,
564        /// selecting a choice for the fill-in value, and leaving that field,
565        /// which finalizes or "commits" the data choice and triggers any
566        /// actions associated with the entry or changing of this data.
567        ///
568        /// If set, processing does not wait for leaving the field action to
569        /// occur, but immediately proceeds to the third step. PDF 1.5+.
570        const COMMIT_ON_SEL_CHANGE = 1 << 26;
571    }
572}