From 89fd83d08fde0714d20be962efe10371111e55fa Mon Sep 17 00:00:00 2001 From: tingerrr Date: Thu, 19 Oct 2023 18:00:51 +0200 Subject: [PATCH 1/6] Add field dicionaries --- src/forms.rs | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 ++ 2 files changed, 125 insertions(+) create mode 100644 src/forms.rs diff --git a/src/forms.rs b/src/forms.rs new file mode 100644 index 0000000..54ff341 --- /dev/null +++ b/src/forms.rs @@ -0,0 +1,122 @@ +use super::*; + +/// A form field. +pub struct Field<'a> { + dict: Dict<'a>, +} + +writer!(Field: |obj| Self { dict: obj.dict() }); + +impl<'a> Field<'a> { + /// Write the `/FT` attribute specifying the type of this field. + pub fn field_type(&mut self, typ: FieldType) -> &mut Self { + self.dict.pair(Name(b"FT"), typ.to_name()); + self + } + + /// Write the `/Parent` attribute to set the immediate parent of this + /// field. A field can have at most one parent. + pub fn parent(&mut self, id: Ref) -> &mut Self { + self.dict.pair(Name(b"Parent"), id); + self + } + + /// Start writing the `/Kids` attribute to set the immediate children of + /// this field. + pub fn children(&mut self) -> TypedArray<'_, Ref> { + self.dict.insert(Name(b"Kids")).array().typed() + } + + /// Write the `/T` attribute to set the partial field name. + /// + /// The fully qualified field name of a field is a path along it's + /// ancestor's partial field names separated by periods `.`. Therefore, a + /// partial field name may not contain a period `.`. + /// + /// If two fields have the same parent and no partial field name, then they + /// refer to two representations of the same field and should only differ + /// in properties that specify their visual appearance. In particular, they + /// should have the same `/FT`, `/V` and `/DV` attribute values. + pub fn partial_name(&mut self, name: TextStr) -> &mut Self { + self.dict.pair(Name(b"T"), name); + self + } + + /// Write the `/TU` attribute to set the alternative field name. This + /// field name is used in place of the actual field name whenever the field + /// shall be identified int he user interface (such as in error or status + /// messages). This text is also useful when extracting the document’s + /// contents in support of accessibility to users with disabilities or for + /// other purposes. PDF 1.3+. + pub fn alternate_name(&mut self, alternate: TextStr) -> &mut Self { + self.dict.pair(Name(b"TU"), alternate); + self + } + + /// Write the `/TM` attribute to set the mapping field name. This + /// name shall be used when exporting interactive form field data from the + /// document. + pub fn mapping_name(&mut self, name: TextStr) -> &mut Self { + self.dict.pair(Name(b"TM"), name); + self + } + + /// Write the `/Ff` attribute to set various characteristics of this + /// field. + pub fn field_flags(&mut self, flags: FieldFlags) -> &mut Self { + self.dict.pair(Name(b"Tf"), flags.bits() as i32); + self + } + + /// Start writing the `/AA` dictionary to seth the field's response to + /// various trigger events. + pub fn additional_actions(&mut self) -> AdditionalActions<'_> { + self.dict.insert(Name(b"AA")).start() + } +} + +deref!('a, Field<'a> => Dict<'a>, dict); + +/// The type of a [`Field`]. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub enum FieldType { + /// A button field, includes push buttons, check boxes and radio buttons. + Button, + /// A text field, a box which a user can enter text into. + Text, + /// A choice field, list or combo boxes out of which the user may chose at + /// most one. + Choice, + /// A signature field, fields which contain digital signatures and optional + /// authentication data. PDF 1.3+. + Signature, +} + +impl FieldType { + pub(crate) fn to_name(self) -> Name<'static> { + match self { + Self::Button => Name(b"Btn"), + Self::Text => Name(b"Tx"), + Self::Choice => Name(b"Ch"), + Self::Signature => Name(b"Sig"), + } + } +} + +bitflags::bitflags! { + /// Bitflags describing various characteristics of a form field. + pub struct FieldFlags: u32 { + /// If set, the user may not change the value of the field. Any + /// associated widget annotations will not interact with the user; that + /// is, they will not respond to mouse clicks or change their appearance + /// in response to mouse motions. This flag is useful for fields whose + /// values are computed or imported from a database. + const READ_ONLY = 1; + /// If set, the field shall have a value at the time it is exported by a + /// [submit-form](crate::types::ActionType::SubmitForm) [`Action`]. + const REQUIRED = 2; + /// If set, the field shall not be exported by a + /// [submit-form](crate::types::ActionType::SubmitForm) [`Action`]. + const NO_EXPORT = 1 << 3; + } +} diff --git a/src/lib.rs b/src/lib.rs index dc936a5..1e43617 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -95,6 +95,7 @@ mod color; mod content; mod files; mod font; +mod forms; mod functions; mod object; mod renumber; @@ -125,6 +126,7 @@ pub mod writers { CidFont, Cmap, Differences, Encoding, FontDescriptor, Type0Font, Type1Font, Type3Font, Widths, }; + pub use forms::Field; pub use functions::{ ExponentialFunction, PostScriptFunction, SampledFunction, StitchingFunction, }; @@ -161,6 +163,7 @@ pub mod types { }; pub use font::UnicodeCmap; pub use font::{CidFontType, FontFlags, FontStretch, SystemInfo}; + pub use forms::{FieldFlags, FieldType}; pub use functions::{InterpolationOrder, PostScriptOp}; pub use structure::{ Direction, NumberingStyle, OutlineItemFlags, PageLayout, PageMode, StructRole, From 4e5756cf3772839490a2e85875e3569677aa478a Mon Sep 17 00:00:00 2001 From: tingerrr Date: Thu, 19 Oct 2023 18:02:30 +0200 Subject: [PATCH 2/6] Minor unrelated fixes --- src/actions.rs | 6 +++--- src/lib.rs | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/actions.rs b/src/actions.rs index 473b67f..9bbc3ec 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -34,7 +34,7 @@ impl<'a> Action<'a> { self } - /// Start writing the `/F` attribute, depending on the [`action_type`], setting: + /// Start writing the `/F` attribute, depending on the [`ActionType`], setting: /// - `RemoteGoTo`: which file to go to /// - `Launch`: which application to launch /// - `SubmitForm`: script location of the webserver that processes the @@ -82,8 +82,8 @@ impl<'a> Action<'a> { } /// Start writing the `/Fields` array to set the fields which are - /// [include/exclude](ActionFlags::INCLUDE_EXCLUDE) when submitting a form, - /// resetting a form, or loading an FDF file. + /// [include/exclude](FormActionFlags::INCLUDE_EXCLUDE) when submitting a + /// form, resetting a form, or loading an FDF file. pub fn fields(&mut self) -> Fields<'_> { self.insert(Name(b"Fields")).start() } diff --git a/src/lib.rs b/src/lib.rs index 1e43617..50bea96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,8 +161,7 @@ pub mod types { LineCapStyle, LineJoinStyle, MaskType, OverprintMode, ProcSet, RenderingIntent, TextRenderingMode, }; - pub use font::UnicodeCmap; - pub use font::{CidFontType, FontFlags, FontStretch, SystemInfo}; + pub use font::{CidFontType, FontFlags, FontStretch, SystemInfo, UnicodeCmap}; pub use forms::{FieldFlags, FieldType}; pub use functions::{InterpolationOrder, PostScriptOp}; pub use structure::{ From 6954c2321170c488025b3c8559d823c9a92843b9 Mon Sep 17 00:00:00 2001 From: tingerrr Date: Thu, 19 Oct 2023 18:06:30 +0200 Subject: [PATCH 3/6] Proof read --- src/actions.rs | 3 ++- src/forms.rs | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/actions.rs b/src/actions.rs index 9bbc3ec..74be322 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -222,7 +222,8 @@ bitflags::bitflags! { /// Writer for an _additional actions dictionary_. /// /// This struct is created by [`Annotation::additional_actions`], -/// [`Page::additional_actions`] and [`Catalog::additional_actions`]. +/// [`Field::additional_actions`], [`Page::additional_actions`] and +/// [`Catalog::additional_actions`]. pub struct AdditionalActions<'a> { dict: Dict<'a>, } diff --git a/src/forms.rs b/src/forms.rs index 54ff341..5163767 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -15,7 +15,7 @@ impl<'a> Field<'a> { } /// Write the `/Parent` attribute to set the immediate parent of this - /// field. A field can have at most one parent. + /// field. pub fn parent(&mut self, id: Ref) -> &mut Self { self.dict.pair(Name(b"Parent"), id); self @@ -44,8 +44,8 @@ impl<'a> Field<'a> { /// Write the `/TU` attribute to set the alternative field name. This /// field name is used in place of the actual field name whenever the field - /// shall be identified int he user interface (such as in error or status - /// messages). This text is also useful when extracting the document’s + /// shall be identified in the user interface (such as in error or status + /// messages). This text is also useful when extracting the document's /// contents in support of accessibility to users with disabilities or for /// other purposes. PDF 1.3+. pub fn alternate_name(&mut self, alternate: TextStr) -> &mut Self { @@ -68,7 +68,7 @@ impl<'a> Field<'a> { self } - /// Start writing the `/AA` dictionary to seth the field's response to + /// Start writing the `/AA` dictionary to set the field's response to /// various trigger events. pub fn additional_actions(&mut self) -> AdditionalActions<'_> { self.dict.insert(Name(b"AA")).start() @@ -113,10 +113,10 @@ bitflags::bitflags! { /// values are computed or imported from a database. const READ_ONLY = 1; /// If set, the field shall have a value at the time it is exported by a - /// [submit-form](crate::types::ActionType::SubmitForm) [`Action`]. + /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`]. const REQUIRED = 2; /// If set, the field shall not be exported by a - /// [submit-form](crate::types::ActionType::SubmitForm) [`Action`]. + /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`]. const NO_EXPORT = 1 << 3; } } From a3762c96299b86f829ad07eab7be5f9f0c08d017 Mon Sep 17 00:00:00 2001 From: tingerrr Date: Thu, 19 Oct 2023 18:21:48 +0200 Subject: [PATCH 4/6] Minor documentation fixes --- src/forms.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/forms.rs b/src/forms.rs index 5163767..9c1738c 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -8,7 +8,7 @@ pub struct Field<'a> { writer!(Field: |obj| Self { dict: obj.dict() }); impl<'a> Field<'a> { - /// Write the `/FT` attribute specifying the type of this field. + /// Write the `/FT` attribute to set the type of this field. pub fn field_type(&mut self, typ: FieldType) -> &mut Self { self.dict.pair(Name(b"FT"), typ.to_name()); self @@ -106,16 +106,16 @@ impl FieldType { bitflags::bitflags! { /// Bitflags describing various characteristics of a form field. pub struct FieldFlags: u32 { - /// If set, the user may not change the value of the field. Any - /// associated widget annotations will not interact with the user; that - /// is, they will not respond to mouse clicks or change their appearance - /// in response to mouse motions. This flag is useful for fields whose + /// The user may not change the value of the field. Any associated + /// widget annotations will not interact with the user; that is, they + /// will not respond to mouse clicks or change their appearance in + /// response to mouse motions. This flag is useful for fields whose /// values are computed or imported from a database. const READ_ONLY = 1; - /// If set, the field shall have a value at the time it is exported by a + /// The field shall have a value at the time it is exported by a /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`]. const REQUIRED = 2; - /// If set, the field shall not be exported by a + /// The field shall not be exported by a /// [submit-form](crate::types::ActionType::SubmitForm)[`Action`]. const NO_EXPORT = 1 << 3; } From 2ff97d6c3375b9070ba91a3398f94a625a256945 Mon Sep 17 00:00:00 2001 From: tingerrr Date: Fri, 20 Oct 2023 13:49:37 +0200 Subject: [PATCH 5/6] Review --- src/forms.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/forms.rs b/src/forms.rs index 9c1738c..27f9a05 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -22,7 +22,9 @@ impl<'a> Field<'a> { } /// Start writing the `/Kids` attribute to set the immediate children of - /// this field. + /// this field. These references shall refer to other [fields][Field], or + /// [wdiget](crate::types::AnnotationType::Widget) + /// [annoations](Annotation). pub fn children(&mut self) -> TypedArray<'_, Ref> { self.dict.insert(Name(b"Kids")).array().typed() } From 3482cb432a0963571ae5f435c10126661977eeac Mon Sep 17 00:00:00 2001 From: Martin Haug Date: Fri, 20 Oct 2023 15:09:33 +0200 Subject: [PATCH 6/6] Fix spelling --- src/forms.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/forms.rs b/src/forms.rs index 27f9a05..abcbe32 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -23,7 +23,7 @@ impl<'a> Field<'a> { /// Start writing the `/Kids` attribute to set the immediate children of /// this field. These references shall refer to other [fields][Field], or - /// [wdiget](crate::types::AnnotationType::Widget) + /// [widget](crate::types::AnnotationType::Widget) /// [annoations](Annotation). pub fn children(&mut self) -> TypedArray<'_, Ref> { self.dict.insert(Name(b"Kids")).array().typed()