mirror of
https://github.com/foliojs/pdfkit.git
synced 2025-12-08 20:15:54 +00:00
Added shortcut support for formatting form text inputs.
Fixed annotations to not automatically add Border and C for Widget annotations. More documentation.
This commit is contained in:
parent
9f6c5fb825
commit
bf75b0881a
119
docs/forms.md
119
docs/forms.md
@ -2,12 +2,16 @@
|
||||
|
||||
AcroForms are interactive features of the PDF format, and they make it possible
|
||||
to include things like text fields, buttons and actions. To include AcroForms
|
||||
you must call the `document.initAcroForm()` method.
|
||||
you must call the document `initAcroForm()` method.
|
||||
|
||||
AcroForm elements are _widget_ annotations and are added using the
|
||||
`widgetAnnotation` method. Other methods are shortcut methods that call the
|
||||
`widgetAnnotation` method. Here is a list of the available _Widget Annotation_
|
||||
methods:
|
||||
* `initAcroform()` - Must be called when using AcroForms
|
||||
|
||||
## AcroForm Methods
|
||||
|
||||
AcroForm elements are _Widget Annotations_ and are added using the
|
||||
`widgetAnnotation` method. Additional methods listed below are shortcut methods
|
||||
that call the `widgetAnnotation` method. The list of the available _Widget
|
||||
Annotation_ document methods is:
|
||||
|
||||
* `widgetAnnotation( name, x, y, width, height, options)`
|
||||
* `formText( name, x, y, width, height, options)`
|
||||
@ -16,29 +20,54 @@ methods:
|
||||
* `formNoToggleToOffButton( name, x, y, width, height, options)`
|
||||
* `formChoice( name, x, y, width, height, options)`
|
||||
|
||||
Some Widget Annotations have a `color` option that you can specify. You can use
|
||||
### Options Parameter
|
||||
|
||||
Some Widget Annotations have a `color` option that can be specified. You can use
|
||||
an array of RGB values, a hex color, or a named CSS color value for that option.
|
||||
For example, form buttons can have a `backgroundColor` and `borderColor`.
|
||||
|
||||
* `backgroundColor` - button background color
|
||||
* `borderColor` - button border color
|
||||
|
||||
Other `options` conveniences include:
|
||||
|
||||
* `label` - set button text labels (MK.CA)
|
||||
* `align` - set to `left`, `center` or `right` for text within the Widget Annotation
|
||||
* Field flags to set `Ff`
|
||||
* readyOnly: 1,
|
||||
* required: 2,
|
||||
* noExport: 4,
|
||||
* multiline: 0x1000,
|
||||
* password: 0x2000,
|
||||
* toggleToOffButton: 0x4000,
|
||||
* radioButton: 0x8000, (also set when calling `formRadioButton`)
|
||||
* pushButton: 0x10000 (also set when calling `formPushButton`)
|
||||
* toggleToOffButton: 0x10000 (also set when calling `formNoToggleToOffButton`)
|
||||
* combo: 0x20000,
|
||||
* edit: 0x40000,
|
||||
* sort: 0x80000
|
||||
* `label` - set button text labels (will set <<MK <<CA (label)>> >>)
|
||||
* `align` - set to `left`, `center` or `right` for text within the
|
||||
Widget Annotation
|
||||
* Field flags that will set bits in `Ff`
|
||||
* `readyOnly`: 1,
|
||||
* `required`: 2,
|
||||
* `noExport`: 4,
|
||||
* `multiline`: 0x1000,
|
||||
* `password`: 0x2000,
|
||||
* `toggleToOffButton`: 0x4000,
|
||||
* `radioButton`: 0x8000, (will be set when calling the `formRadioButton` method)
|
||||
* `pushButton`: 0x10000 (will be set when calling the `formPushButton` method)
|
||||
* `toggleToOffButton`: 0x10000 (will be set when calling the `formNoToggleToOffButton` method)
|
||||
* `combo`: 0x20000,
|
||||
* `edit`: 0x40000,
|
||||
* `sort`: 0x80000
|
||||
|
||||
When using `formChoice`, set `options.Opt` to the array of choices.
|
||||
When using the `formChoice` method, set `options.Opt` to the array of choices.
|
||||
|
||||
When needing to format the text value of a Widget Annotation, the following
|
||||
`options` shortcuts are available to implement predefined JavaScript actions.
|
||||
Refer to the Acrobat SDK documentation for the [Acrobat Forms
|
||||
Plugin](https://help.adobe.com/en_US/acrobat/acrobat_dc_sdk/2015/HTMLHelp/#t=Acro12_MasterBook%2FIAC_API_FormsIntro%2FMethods1.htm) for more information.
|
||||
|
||||
* `format` - object
|
||||
* `type` - value is a string with one of the following values:
|
||||
* `time`
|
||||
* `date`
|
||||
* `percent`
|
||||
* `number`
|
||||
* `special`
|
||||
* `zip`
|
||||
* `zipPlus4`
|
||||
* `phone`
|
||||
* `ssn`
|
||||
* `params` - value is a string, number or array of strings and numbers
|
||||
|
||||
## Other Methods
|
||||
|
||||
The font used for a Widget Annotation is set using the `document.font` method.
|
||||
|
||||
@ -48,32 +77,40 @@ _shipping.address.street_. You can either set the `name` of each Widget
|
||||
Annotation with the full name (e.g. _shipping.address.street_) or you can create
|
||||
parent Fields. In this example you might have a _shipping_ field that is added
|
||||
to the AcroForm Fields array, an _address_ field that refers to the _shipping_
|
||||
Field as it's parent, and a _street_ Widget Annotation which would refer to the
|
||||
_address_ field as it's parent. To create a field use:
|
||||
Field as it's parent, and a _street_ Widget Annotation that would refer to the
|
||||
_address_ field as it's parent. To create a field use the document method:
|
||||
|
||||
* `field( name, options )` returns a reference to the field
|
||||
* `field( name, options )` - returns a reference to the field
|
||||
|
||||
To specify the parent of a _Field_ or _Widget Annotation_, set the `parent`
|
||||
option to the field reference.
|
||||
options to the field reference.
|
||||
|
||||
In support of Widget Annotations that execute PDF JavaScript, you can call the following method:
|
||||
```js
|
||||
var shippingRef = doc.field( 'shipping' );
|
||||
var addressRef = doc.field( 'address', shippingRef );
|
||||
doc.formText('street`,10,10,100,20,{parent:addressRef});
|
||||
```
|
||||
|
||||
In support of Widget Annotations that execute PDF JavaScript, you can call the following document method:
|
||||
|
||||
* `addNamedJavaScript( name, buffer )`
|
||||
|
||||
There is an important caveat when using AcroForms with PDFKit. Form elements
|
||||
must each have an _appearance_ set using the _AP_ attribute of the annotation.
|
||||
If this attribute is not set, the form element _may_ not be visible. Because
|
||||
appearances can be complex to generate, Adobe Acrobat has an option to build
|
||||
these apperances when a PDF is opened. To do this PDFKit sets the AcroForm
|
||||
dictionary's _NeedAppearances_ attribute to true. This could mean that the PDF
|
||||
will be _dirty_ upon open, meaning it will need to be saved. It is also
|
||||
important to realize that the _NeedAppearances_ flag may not be honored by PDF
|
||||
viewers that don't implement this aspect of the PDF Reference.
|
||||
## Limitations
|
||||
|
||||
A final note on _NeedAppearances_ is that for some form documents you may not
|
||||
need to generate appearances. We believe this to be the case for text widget
|
||||
annotations that are initially blank. It is not true for push button widget
|
||||
annotations.
|
||||
An important caveat when using AcroForms with PDFKit is that form elements must
|
||||
each have an _appearance_ set using the `AP` attribute of the annotation. If
|
||||
this attribute is not set, the form element _may_ not be visible. Because
|
||||
appearances can be complex to generate, Adobe Acrobat has an option to build
|
||||
these apperances from form values and Widget Annotation attributes when a PDF is
|
||||
opened. To do this PDFKit sets the AcroForm dictionary's `NeedAppearances`
|
||||
attribute to true. This could mean that the PDF will be _dirty_ upon open,
|
||||
meaning it will need to be saved. It is also important to realize that the
|
||||
`NeedAppearances` flag may not be honored by PDF viewers that do not implement
|
||||
this aspect of the PDF Reference.
|
||||
|
||||
A final note on `NeedAppearances` is that for some form documents you may not
|
||||
need to generate appearances. This may be the case for text Widget Annotations
|
||||
that are initially blank. This is not true for push button widget annotations.
|
||||
|
||||
|
||||
* * *
|
||||
|
||||
@ -20,6 +20,13 @@ const FIELD_JUSTIFY = {
|
||||
center: 1,
|
||||
right: 2
|
||||
};
|
||||
const FORMAT_SPECIAL = {
|
||||
zip: '0',
|
||||
zipPlus4: '1',
|
||||
zip4: '1',
|
||||
phone: '2',
|
||||
ssn: '3'
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@ -117,12 +124,52 @@ export default {
|
||||
opts = this._resolveFont(opts);
|
||||
opts = this._resolveStrings(opts);
|
||||
opts = this._resolveColors(opts);
|
||||
opts = this._resolveFormat(opts);
|
||||
opts = Object.assign(opts, {
|
||||
T: new String(name),
|
||||
});
|
||||
return opts;
|
||||
},
|
||||
|
||||
_resolveFormat (opts) {
|
||||
if (opts.format && opts.format.type) {
|
||||
let fnKeystroke;
|
||||
let fnFormat;
|
||||
let params;
|
||||
if (FORMAT_SPECIAL[opts.format.type] !== undefined) {
|
||||
fnKeystroke = `AFSpecial_Keystroke`;
|
||||
fnFormat = `AFSpecial_Format`;
|
||||
params = FORMAT_SPECIAL[opts.format.type]
|
||||
} else {
|
||||
let format = opts.format.type.charAt(0).toUpperCase() + opts.format.type.slice(1);
|
||||
fnKeystroke = `AF${format}_Keystroke`;
|
||||
fnFormat = `AF${format}_Format`;
|
||||
params = this._formatParamsAsString(opts.format.params);
|
||||
if (opts.format.type === 'date') {
|
||||
fnKeystroke += 'Ex';
|
||||
}
|
||||
}
|
||||
opts.AA = opts.AA ? opts.AA : {};
|
||||
opts.AA.K = {
|
||||
S: "JavaScript",
|
||||
JS: new String(`${fnKeystroke}(${params});`)
|
||||
};
|
||||
opts.AA.F = {
|
||||
S: "JavaScript",
|
||||
JS: new String(`${fnFormat}(${params});`)
|
||||
};
|
||||
}
|
||||
delete opts.format;
|
||||
return opts;
|
||||
},
|
||||
|
||||
_formatParamsAsString (params) {
|
||||
if (Array.isArray(params)) {
|
||||
return JSON.stringify(params).replace('[', '').replace(']', '')
|
||||
}
|
||||
return String(params);
|
||||
},
|
||||
|
||||
_resolveColors (opts) {
|
||||
let color = this._normalizeColor(opts.backgroundColor);
|
||||
if (color) {
|
||||
@ -185,7 +232,6 @@ export default {
|
||||
} else {
|
||||
arr.push(options.Opt[idx])
|
||||
}
|
||||
arr.push(new String(options.Opt[idx]));
|
||||
}
|
||||
options.Opt = arr;
|
||||
}
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
export default {
|
||||
annotate(x, y, w, h, options) {
|
||||
annotate (x, y, w, h, options) {
|
||||
options.Type = 'Annot';
|
||||
options.Rect = this._convertRect(x, y, w, h);
|
||||
options.Border = [0, 0, 0];
|
||||
if (options.Subtype !== 'Link') {
|
||||
if (options.Subtype !== 'Widget') {
|
||||
options.Border = [0, 0, 0];
|
||||
}
|
||||
if (options.Subtype !== 'Link' && options.Subtype !== 'Widget') {
|
||||
if (options.C == null) {
|
||||
options.C = this._normalizeColor(options.color || [0, 0, 0]);
|
||||
}
|
||||
@ -26,7 +28,7 @@ export default {
|
||||
return this;
|
||||
},
|
||||
|
||||
note(x, y, w, h, contents, options = {}) {
|
||||
note (x, y, w, h, contents, options = {}) {
|
||||
options.Subtype = 'Text';
|
||||
options.Contents = new String(contents);
|
||||
options.Name = 'Comment';
|
||||
@ -36,7 +38,7 @@ export default {
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
goTo(x, y, w, h, name, options = {}) {
|
||||
goTo (x, y, w, h, name, options = {}) {
|
||||
options.Subtype = 'Link';
|
||||
options.A = this.ref({
|
||||
S: 'GoTo',
|
||||
@ -46,7 +48,7 @@ export default {
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
link(x, y, w, h, url, options = {}) {
|
||||
link (x, y, w, h, url, options = {}) {
|
||||
options.Subtype = 'Link';
|
||||
|
||||
if (typeof url === 'number') {
|
||||
@ -73,14 +75,14 @@ export default {
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
_markup(x, y, w, h, options = {}) {
|
||||
_markup (x, y, w, h, options = {}) {
|
||||
const [x1, y1, x2, y2] = this._convertRect(x, y, w, h);
|
||||
options.QuadPoints = [x1, y2, x2, y2, x1, y1, x2, y1];
|
||||
options.Contents = new String();
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
highlight(x, y, w, h, options = {}) {
|
||||
highlight (x, y, w, h, options = {}) {
|
||||
options.Subtype = 'Highlight';
|
||||
if (options.color == null) {
|
||||
options.color = [241, 238, 148];
|
||||
@ -88,43 +90,43 @@ export default {
|
||||
return this._markup(x, y, w, h, options);
|
||||
},
|
||||
|
||||
underline(x, y, w, h, options = {}) {
|
||||
underline (x, y, w, h, options = {}) {
|
||||
options.Subtype = 'Underline';
|
||||
return this._markup(x, y, w, h, options);
|
||||
},
|
||||
|
||||
strike(x, y, w, h, options = {}) {
|
||||
strike (x, y, w, h, options = {}) {
|
||||
options.Subtype = 'StrikeOut';
|
||||
return this._markup(x, y, w, h, options);
|
||||
},
|
||||
|
||||
lineAnnotation(x1, y1, x2, y2, options = {}) {
|
||||
lineAnnotation (x1, y1, x2, y2, options = {}) {
|
||||
options.Subtype = 'Line';
|
||||
options.Contents = new String();
|
||||
options.L = [x1, this.page.height - y1, x2, this.page.height - y2];
|
||||
return this.annotate(x1, y1, x2, y2, options);
|
||||
},
|
||||
|
||||
rectAnnotation(x, y, w, h, options = {}) {
|
||||
rectAnnotation (x, y, w, h, options = {}) {
|
||||
options.Subtype = 'Square';
|
||||
options.Contents = new String();
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
ellipseAnnotation(x, y, w, h, options = {}) {
|
||||
ellipseAnnotation (x, y, w, h, options = {}) {
|
||||
options.Subtype = 'Circle';
|
||||
options.Contents = new String();
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
textAnnotation(x, y, w, h, text, options = {}) {
|
||||
textAnnotation (x, y, w, h, text, options = {}) {
|
||||
options.Subtype = 'FreeText';
|
||||
options.Contents = new String(text);
|
||||
options.DA = new String();
|
||||
return this.annotate(x, y, w, h, options);
|
||||
},
|
||||
|
||||
_convertRect(x1, y1, w, h) {
|
||||
_convertRect (x1, y1, w, h) {
|
||||
// flip y1 and y2
|
||||
let y2 = y1;
|
||||
y1 += h;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user