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}