pdf_writer/
forms.rs

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