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}