Documentation
¶
Overview ¶
Package forms is the fillable half of a PDF: the boxes someone is meant to type into, the squares they tick, and the lists they choose from.
A form is not drawn where it is defined. The document holds one list of fields, each field holds its value, and each field points at one or more widgets — the rectangles on the pages where it shows. What a filled-in field looks like is a little content stream of its own, called an appearance, and the awkward part of forms is that a field's appearance is not derived from its value when the page is drawn: it is written down beside the value, and whoever changes the value has to write a new one. A reader that fills a field and does not do that has filled in nothing anyone can see.
So this package does three things. It reads the field tree — which is a tree, because a field may be a parent of others and inherits from wherever up the tree a thing was last said. It sets values. And it draws the appearance a value needs, from the default appearance string the document supplies, which is a fragment of content stream naming a font, a size and a colour, and in which a size of zero means "as large as fits".
What it does not do is lay out XFA, Adobe's XML form language — and the reason has two halves, because the forms do.
Measured over 2 240 real government forms: 1 499 carry a form, 560 of those carry an XFA package, and 546 of THOSE are static. A static one is a second, proprietary description of a form that is already there: the pages are drawn, the widgets exist, and everything here works on it. Such a file is not made more readable by reading the harder description.
The other fourteen are dynamic. Their pages hold a panel reading "Please wait... your PDF viewer may not be able to display this type of document", and the form is laid out from the XML when it is opened — by Adobe's reader and by nothing else, the format having been removed from PDF 2.0. Laying one out means an XFA layout engine; the reference implementation, pdf.js, spends 395 kilobytes of JavaScript on it.
So this says which kind a document is, through Form.Dynamic, and hands back the XML through Form.Packets — the values a form has been filled with live in its datasets part, as ordinary XML. What it will not do is draw nothing and say nothing, which is what every tool including this one did before: a document that looks blank and is not.
Index ¶
- Variables
- type Appearance
- type Field
- func (f *Field) Appearance(w Widget) (Appearance, bool)
- func (f *Field) Changed() bool
- func (f *Field) Checked() bool
- func (f *Field) Choose(values ...string) error
- func (f *Field) Dict() reader.Dict
- func (f *Field) Press(state string) error
- func (f *Field) Ref() (reader.Ref, bool)
- func (f *Field) SetChecked(on bool) error
- func (f *Field) SetText(s string) error
- func (f *Field) States() []string
- func (f *Field) Text() string
- type Form
- func (f *Form) Changed() []*Field
- func (f *Form) DefaultAppearance() string
- func (f *Form) Dict() reader.Dict
- func (f *Form) Dynamic() bool
- func (f *Form) Field(name string) (*Field, bool)
- func (f *Form) Fields() []*Field
- func (f *Form) Fill(name, value string) error
- func (f *Form) HasXFA() bool
- func (f *Form) NeedAppearances() bool
- func (f *Form) Packets() []Packet
- func (f *Form) Resources() reader.Dict
- type Kind
- type Option
- type Packet
- type Widget
Constants ¶
This section is empty.
Variables ¶
var ErrKind = errors.New("forms: the field does not hold that sort of value")
ErrKind is what a field says when it is asked for a value of the wrong sort — a checkbox given a sentence, or a text field ticked.
var ErrReadOnly = errors.New("forms: the field is read-only")
ErrReadOnly is what a field says when the document asks that it not be filled in.
Functions ¶
This section is empty.
Types ¶
type Appearance ¶
type Appearance struct {
// Content is the stream itself.
Content []byte
// BBox is the box it is drawn in, which is the widget's own size with its
// corner at the origin: an appearance is drawn in a space of its own and
// placed by the widget's rectangle.
BBox [4]float64
// FontName is the name Content uses for its font, and Font the object in
// the form's resource dictionary that name stands for. Whoever writes the
// stream out has to give it a resource dictionary saying so.
FontName string
Font reader.Object
}
An Appearance is the little content stream that shows a field's value, and everything needed to put it in the document.
type Field ¶
type Field struct {
// Name is the whole name, with a dot between each part, which is how a
// field is addressed from outside: the document's own names are only
// unique among their brothers.
Name string
Kind Kind
// Value is what the field holds. For a checkbox or a radio button it is
// the name of the chosen state, and Off means not chosen.
Value string
// Values is what a list box holds when more than one row is chosen.
Values []string
// Options are the rows of a choice field: what is stored and what is
// shown, which a file may say separately.
Options []Option
// MaxLen is how many characters a text field takes, or zero for as many
// as one likes.
MaxLen int
// Quadding is 0 for ranged left, 1 for centred and 2 for ranged right.
Quadding int
ReadOnly bool
Required bool
NoExport bool
// Multiline, Password and Comb are the ways a text field can be unusual.
// A comb field is one divided into MaxLen equal cells, one character to
// each, which is how a form asks for a code or a number one digit at a
// time.
Multiline bool
Password bool
Comb bool
// Sorted and MultiSelect belong to a choice field, and Editable says a
// combo box will take something that is not one of its rows.
Sorted bool
MultiSelect bool
Editable bool
// Widgets are the places on the pages where the field shows. Nearly every
// field has one; a field asking the same thing on several pages has more.
Widgets []Widget
// contains filtered or unexported fields
}
A Field is one thing a person fills in.
func (*Field) Appearance ¶
func (f *Field) Appearance(w Widget) (Appearance, bool)
Appearance draws the stream that shows what a field holds, for one of its widgets.
A checkbox or a radio button does not need one: its widget already carries a drawing for every state it has, and choosing among them is a matter of saying which — which is why every one of the 2 015 checkboxes in the corpus has an appearance dictionary and 11 803 text fields mostly have none, since an empty box has nothing to show.
func (*Field) Changed ¶
Changed says a value was put here rather than read from the file, which is what tells whoever writes the document out what has to be written.
func (*Field) Choose ¶
Choose picks rows of a choice field. A list box that says it takes several takes several; anything else takes one.
func (*Field) Dict ¶ added in v0.2.0
Dict is the field's own dictionary, as the document holds it. Whoever writes the document out copies this and changes what has to change, rather than building a field from nothing and losing everything this package does not know about — a field's actions, its appearance characteristics, the border somebody chose.
func (*Field) Press ¶
Press chooses one particular button of a radio group by the state its widget names, which is what to use when a group has more than two buttons.
func (*Field) Ref ¶ added in v0.2.0
Ref is where the field's own dictionary lives in the document. A field written inside another object rather than as one of its own has none, which happens in files that put a whole form in a single array.
func (*Field) SetChecked ¶
SetChecked ticks or unticks a checkbox, and presses a radio button.
A ticked box does not hold "true": it holds the name of the state its widget calls chosen, which every widget names for itself. That is how a row of radio buttons sharing one value says which of them was pressed.
type Form ¶
type Form struct {
// contains filtered or unexported fields
}
A Form is a document's fillable part.
func Read ¶
Read reads a document's form, or reports that it has none. A document with an AcroForm dictionary and no fields in it has none: producers leave the dictionary behind, and 561 of the 118 833 files in the figure corpus have exactly that and nothing else.
func (*Form) Changed ¶
Changed lists the fields somebody has filled in, which is what a writer needs and nothing more.
func (*Form) DefaultAppearance ¶ added in v0.2.0
DefaultAppearance is the form's own, which a field with none of its own falls back on.
func (*Form) Dict ¶ added in v0.2.0
Dict is the form's own dictionary — the AcroForm — which holds the defaults and the resources every field falls back on.
func (*Form) Dynamic ¶ added in v0.3.0
Dynamic says the document's pages are a placeholder and its real form exists only as XML.
This is the difference that matters about XFA, and it is not the same question as Form.HasXFA.
A STATIC XFA form carries a full standard form beside the XML: the pages are drawn, the widgets are there, and everything in this package works on it. Of 1 499 forms in a corpus of 2 240 real documents, 560 carry XFA and 546 are of this kind — the XML is a second description of a form that is already readable, and reading the harder one gains nothing.
A DYNAMIC one is different in kind. Its pages hold a panel reading "Please wait... your PDF viewer may not be able to display this type of document", and the form is laid out from the XML when it is opened. Fourteen of those 2 240 are like this. Every viewer but Adobe's own shows the panel: the format was removed from PDF 2.0, and neither poppler nor any browser lays it out.
So a caller meeting one of these has a document that looks blank and is not. Saying so is worth more than drawing nothing quietly, which is what every tool including this one did before.
func (*Form) Fill ¶
Fill sets a field by name, choosing the right sort of setter for what it is, which is what a command line or a map of values wants.
func (*Form) HasXFA ¶
HasXFA says the document also carries Adobe's XML form description. Nothing here reads it: a file that has both is fillable through the standard half, which is the half this reads.
func (*Form) NeedAppearances ¶ added in v0.2.0
NeedAppearances is a document saying that the values in it are right and the drawings beside them are not, and asking whoever opens it to draw them again. Fifteen of the corpus's forms say it. A writer that fills a field and draws its appearance should clear it, since it has just done what was asked.
func (*Form) Packets ¶ added in v0.3.0
Packets are the parts of the XFA package, in the order the document names them, or nil when there is no package.
The form cannot be laid out from here — that wants a layout engine this package does not have — but the values can be read: what has been filled in lives in the datasets part, as ordinary XML.
type Kind ¶
type Kind uint8
A Kind says what sort of a field it is, which decides both what a value means and what its appearance looks like.
The kinds a field may be. A push button is a field that holds no value at all — it is a place to click — and a signature field is one this package will read and will not pretend to fill.
type Option ¶
type Option struct {
// Value is what is stored when the row is chosen and Label what is shown.
// A file that gives only one gives the value, and the label is the same.
Value string
Label string
}
An Option is one row of a choice field.
type Packet ¶ added in v0.3.0
Packet is one part of a document's XFA package: a name and the XML under it.
A package is split into parts — template, datasets, config, localeSet — and the two worth reading are template, which describes the form, and datasets, which holds what has been filled in.
type Widget ¶
type Widget struct {
// Page counts from one. It is zero when the document does not say which
// page the widget is on, which happens in files whose page tree and
// annotation lists disagree.
Page int
// Rect is where on that page, in the page's own coordinates, lower left
// corner first.
Rect [4]float64
// On is the state name that means "chosen", for a checkbox or a radio
// button. Every such widget has one of its own, which is how a set of
// radio buttons sharing a value tells which one was pressed.
On string
// Hidden says the document asks for this one not to be drawn.
Hidden bool
// contains filtered or unexported fields
}
A Widget is one place on a page where a field shows.