@jasy/pdf 1.0.0-alpha.7 → 1.0.0-alpha.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +7 -7
  2. package/dist/api/descriptor.js +23 -0
  3. package/dist/api/forms.d.ts +347 -0
  4. package/dist/api/forms.js +189 -0
  5. package/dist/api/index.d.ts +1 -0
  6. package/dist/api/index.js +1 -0
  7. package/dist/api/structure.d.ts +6 -0
  8. package/dist/api/structure.js +1 -0
  9. package/dist/crypto/legacy-handler.d.ts +43 -0
  10. package/dist/crypto/legacy-handler.js +145 -0
  11. package/dist/crypto/security-handler.d.ts +16 -0
  12. package/dist/crypto/security-handler.js +26 -0
  13. package/dist/edit/acroform-reader.d.ts +70 -0
  14. package/dist/edit/acroform-reader.js +126 -0
  15. package/dist/edit/appearance.d.ts +47 -0
  16. package/dist/edit/appearance.js +171 -0
  17. package/dist/edit/document.d.ts +135 -0
  18. package/dist/edit/document.js +649 -0
  19. package/dist/edit/fill.d.ts +48 -0
  20. package/dist/edit/fill.js +395 -0
  21. package/dist/edit/flatten.d.ts +42 -0
  22. package/dist/edit/flatten.js +437 -0
  23. package/dist/edit/index.d.ts +18 -0
  24. package/dist/edit/index.js +16 -0
  25. package/dist/edit/lexer.d.ts +30 -0
  26. package/dist/edit/lexer.js +285 -0
  27. package/dist/edit/objects.d.ts +63 -0
  28. package/dist/edit/objects.js +56 -0
  29. package/dist/edit/writer.d.ts +53 -0
  30. package/dist/edit/writer.js +261 -0
  31. package/dist/elements/forms/checkbox-element.d.ts +51 -0
  32. package/dist/elements/forms/checkbox-element.js +48 -0
  33. package/dist/elements/forms/choice-element.d.ts +53 -0
  34. package/dist/elements/forms/choice-element.js +59 -0
  35. package/dist/elements/forms/push-button-element.d.ts +56 -0
  36. package/dist/elements/forms/push-button-element.js +49 -0
  37. package/dist/elements/forms/radio-element.d.ts +52 -0
  38. package/dist/elements/forms/radio-element.js +49 -0
  39. package/dist/elements/forms/signature-element.d.ts +54 -0
  40. package/dist/elements/forms/signature-element.js +47 -0
  41. package/dist/elements/forms/text-field-element.d.ts +61 -0
  42. package/dist/elements/forms/text-field-element.js +54 -0
  43. package/dist/elements/index.d.ts +6 -0
  44. package/dist/elements/index.js +6 -0
  45. package/dist/forms/acroform.d.ts +63 -0
  46. package/dist/forms/acroform.js +427 -0
  47. package/dist/forms/appearance.d.ts +58 -0
  48. package/dist/forms/appearance.js +204 -0
  49. package/dist/forms/field.d.ts +164 -0
  50. package/dist/forms/field.js +1 -0
  51. package/dist/forms/pdf.d.ts +19 -0
  52. package/dist/forms/pdf.js +28 -0
  53. package/dist/ir/display-list.d.ts +17 -1
  54. package/dist/renderer/form-field-renderer.d.ts +20 -0
  55. package/dist/renderer/form-field-renderer.js +12 -0
  56. package/dist/renderer/page-renderer.js +8 -2
  57. package/dist/renderer/pdf-backend.js +8 -0
  58. package/dist/renderer/pdf-renderer.js +19 -1
  59. package/dist/utils/dest-registry.d.ts +5 -2
  60. package/dist/utils/dest-registry.js +5 -5
  61. package/dist/utils/outline.js +1 -2
  62. package/dist/utils/pdf-object-manager.d.ts +18 -0
  63. package/dist/utils/pdf-object-manager.js +59 -6
  64. package/dist/utils/struct-tree.js +2 -3
  65. package/dist/validators/element-validator.js +7 -3
  66. package/package.json +9 -2
@@ -0,0 +1,54 @@
1
+ import { Color } from "../../common/color.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ import { LayoutContext, SizedPDFElement } from "../pdf-element.js";
4
+ import type { FieldStyle, SignatureSpec } from "../../forms/field.js";
5
+ export interface SignatureFieldParams {
6
+ /** The field name (/T) - unique in the document. */
7
+ name: string;
8
+ /** A hint drawn inside the empty box, e.g. "Signature". */
9
+ label?: string;
10
+ /** Tooltip / accessible name. */
11
+ tooltip?: string;
12
+ /** Draw it but do not let it be signed. */
13
+ readOnly?: boolean;
14
+ /** Mark it as a field that must be filled in before submitting. */
15
+ required?: boolean;
16
+ /** Hide the widget entirely - neither on screen nor in print. */
17
+ hidden?: boolean;
18
+ /** Include the widget when printing (default true). */
19
+ print?: boolean;
20
+ /** Box width in points; omit to fill the offered width. */
21
+ width?: number;
22
+ /** Box height in points (default 48 - room for a signature). */
23
+ height?: number;
24
+ /** Hint font size (default 9). */
25
+ fontSize?: number;
26
+ /** Hint colour (default a muted grey). */
27
+ color?: Color;
28
+ /** Box border + signing-rule colour (default a mid grey). */
29
+ border?: Color;
30
+ /** Box background fill. */
31
+ background?: Color;
32
+ /** Border thickness (default 1). */
33
+ borderWidth?: number;
34
+ }
35
+ /**
36
+ * A signature field (AcroForm /Sig) - a PLACEHOLDER someone can sign later. jasy creates the field and
37
+ * its empty "sign here" appearance; it does not sign (that needs a certificate and a byte-range digest -
38
+ * a separate feature). Draws nothing itself: it reserves its box and emits a `formfield` IR node.
39
+ */
40
+ export declare class SignatureFieldElement extends SizedPDFElement {
41
+ private spec;
42
+ private style;
43
+ private requested;
44
+ constructor(p: SignatureFieldParams);
45
+ calculateLayout(constraints: BoxConstraints, offset: Offset, _ctx: LayoutContext): Size;
46
+ getProps(): {
47
+ x: number;
48
+ y: number;
49
+ width: number;
50
+ height: number;
51
+ spec: SignatureSpec;
52
+ style: FieldStyle;
53
+ };
54
+ }
@@ -0,0 +1,47 @@
1
+ import { Color } from "../../common/color.js";
2
+ import { SizedPDFElement } from "../pdf-element.js";
3
+ /**
4
+ * A signature field (AcroForm /Sig) - a PLACEHOLDER someone can sign later. jasy creates the field and
5
+ * its empty "sign here" appearance; it does not sign (that needs a certificate and a byte-range digest -
6
+ * a separate feature). Draws nothing itself: it reserves its box and emits a `formfield` IR node.
7
+ */
8
+ export class SignatureFieldElement extends SizedPDFElement {
9
+ constructor(p) {
10
+ super({ x: 0, y: 0, width: p.width, height: p.height });
11
+ this.spec = {
12
+ kind: "signature",
13
+ name: p.name,
14
+ label: p.label,
15
+ tooltip: p.tooltip,
16
+ readOnly: p.readOnly,
17
+ required: p.required,
18
+ hidden: p.hidden,
19
+ print: p.print,
20
+ };
21
+ this.style = {
22
+ border: p.border ?? new Color(154, 164, 178),
23
+ background: p.background,
24
+ color: p.color ?? new Color(107, 114, 128),
25
+ fontSize: p.fontSize ?? 9,
26
+ borderWidth: p.borderWidth ?? 1,
27
+ };
28
+ this.requested = { width: p.width, height: p.height };
29
+ }
30
+ calculateLayout(constraints, offset, _ctx) {
31
+ this.x = offset.x;
32
+ this.y = offset.y;
33
+ this.width = this.requested.width ?? (constraints.hasBoundedWidth ? constraints.maxWidth : 240);
34
+ this.height = this.requested.height ?? 48;
35
+ return { width: this.width, height: this.height };
36
+ }
37
+ getProps() {
38
+ return {
39
+ x: this.x,
40
+ y: this.y,
41
+ width: this.width ?? 0,
42
+ height: this.height ?? 0,
43
+ spec: this.spec,
44
+ style: this.style,
45
+ };
46
+ }
47
+ }
@@ -0,0 +1,61 @@
1
+ import { Color } from "../../common/color.js";
2
+ import { BoxConstraints, Offset, Size } from "../../layout/box-constraints.js";
3
+ import { LayoutContext, SizedPDFElement } from "../pdf-element.js";
4
+ import type { FieldAlign, FieldStyle, TextFieldSpec } from "../../forms/field.js";
5
+ export interface TextFieldParams {
6
+ /** The field name (/T) - unique in the document; you read the value back by it. */
7
+ name: string;
8
+ /** Initial value (/V). */
9
+ value?: string;
10
+ /** Tooltip / accessible name (/TU). */
11
+ tooltip?: string;
12
+ /** Wrap across lines instead of one line. */
13
+ multiline?: boolean;
14
+ /** Mask the input. */
15
+ password?: boolean;
16
+ /** Maximum character count. */
17
+ maxLength?: number;
18
+ /** Show but do not allow editing. */
19
+ readOnly?: boolean;
20
+ /** How the value sits in the box (default left). */
21
+ align?: FieldAlign;
22
+ /** Mark it as a field that must be filled in before submitting. */
23
+ required?: boolean;
24
+ /** Hide the widget entirely - neither on screen nor in print. */
25
+ hidden?: boolean;
26
+ /** Include the widget when printing (default true). */
27
+ print?: boolean;
28
+ /** Box width in points; omit to fill the offered width. */
29
+ width?: number;
30
+ /** Box height in points; omit for a single-line default (`multiline` wants an explicit height). */
31
+ height?: number;
32
+ /** Value font size; `0` = viewer auto-size. */
33
+ fontSize?: number;
34
+ /** Value text colour. */
35
+ color?: Color;
36
+ /** Box border colour (omit for no border). */
37
+ border?: Color;
38
+ /** Box background fill (omit for transparent). */
39
+ background?: Color;
40
+ /** Border thickness in points. */
41
+ borderWidth?: number;
42
+ }
43
+ /**
44
+ * A text input field (AcroForm /Tx). A leaf that draws NOTHING itself: it reserves its box in the layout
45
+ * and emits a `formfield` IR node that becomes a Widget annotation + /AcroForm field at the seam.
46
+ */
47
+ export declare class TextFieldElement extends SizedPDFElement {
48
+ private spec;
49
+ private style;
50
+ private requested;
51
+ constructor(p: TextFieldParams);
52
+ calculateLayout(constraints: BoxConstraints, offset: Offset, _ctx: LayoutContext): Size;
53
+ getProps(): {
54
+ x: number;
55
+ y: number;
56
+ width: number;
57
+ height: number;
58
+ spec: TextFieldSpec;
59
+ style: FieldStyle;
60
+ };
61
+ }
@@ -0,0 +1,54 @@
1
+ import { Color } from "../../common/color.js";
2
+ import { SizedPDFElement } from "../pdf-element.js";
3
+ /**
4
+ * A text input field (AcroForm /Tx). A leaf that draws NOTHING itself: it reserves its box in the layout
5
+ * and emits a `formfield` IR node that becomes a Widget annotation + /AcroForm field at the seam.
6
+ */
7
+ export class TextFieldElement extends SizedPDFElement {
8
+ constructor(p) {
9
+ super({ x: 0, y: 0, width: p.width, height: p.height });
10
+ const fontSize = p.fontSize ?? 12;
11
+ this.spec = {
12
+ kind: "text",
13
+ name: p.name,
14
+ value: p.value,
15
+ tooltip: p.tooltip,
16
+ multiline: p.multiline,
17
+ password: p.password,
18
+ maxLength: p.maxLength,
19
+ readOnly: p.readOnly,
20
+ align: p.align,
21
+ required: p.required,
22
+ hidden: p.hidden,
23
+ print: p.print,
24
+ };
25
+ this.style = {
26
+ border: p.border,
27
+ background: p.background,
28
+ color: p.color ?? new Color(0, 0, 0),
29
+ fontSize,
30
+ borderWidth: p.borderWidth ?? 1,
31
+ };
32
+ this.requested = { width: p.width, height: p.height, fontSize };
33
+ }
34
+ calculateLayout(constraints, offset, _ctx) {
35
+ this.x = offset.x;
36
+ this.y = offset.y;
37
+ // Width: explicit, else fill the offered box (a form field with no width spans the column).
38
+ this.width = this.requested.width ?? (constraints.hasBoundedWidth ? constraints.maxWidth : 200);
39
+ // Height: explicit, else a comfortable single line (font size + padding). Multiline without an
40
+ // explicit height still gets the single-line default - the caller should size a multiline box.
41
+ this.height = this.requested.height ?? this.requested.fontSize + 9;
42
+ return { width: this.width, height: this.height };
43
+ }
44
+ getProps() {
45
+ return {
46
+ x: this.x,
47
+ y: this.y,
48
+ width: this.width ?? 0,
49
+ height: this.height ?? 0,
50
+ spec: this.spec,
51
+ style: this.style,
52
+ };
53
+ }
54
+ }
@@ -8,6 +8,12 @@ export * from "./layout/expanded-element.js";
8
8
  export * from "./layout/padding-element.js";
9
9
  export * from "./layout/page-break-element.js";
10
10
  export * from "./layout/keep-together-element.js";
11
+ export * from "./forms/text-field-element.js";
12
+ export * from "./forms/checkbox-element.js";
13
+ export * from "./forms/radio-element.js";
14
+ export * from "./forms/choice-element.js";
15
+ export * from "./forms/push-button-element.js";
16
+ export * from "./forms/signature-element.js";
11
17
  export * from "./layout/default-text-style-element.js";
12
18
  export * from "./layout/positioned-element.js";
13
19
  export * from "./layout/link-element.js";
@@ -8,6 +8,12 @@ export * from "./layout/expanded-element.js";
8
8
  export * from "./layout/padding-element.js";
9
9
  export * from "./layout/page-break-element.js";
10
10
  export * from "./layout/keep-together-element.js";
11
+ export * from "./forms/text-field-element.js";
12
+ export * from "./forms/checkbox-element.js";
13
+ export * from "./forms/radio-element.js";
14
+ export * from "./forms/choice-element.js";
15
+ export * from "./forms/push-button-element.js";
16
+ export * from "./forms/signature-element.js";
11
17
  export * from "./layout/default-text-style-element.js";
12
18
  export * from "./layout/positioned-element.js";
13
19
  export * from "./layout/link-element.js";
@@ -0,0 +1,63 @@
1
+ import type { PDFObjectManager } from "../utils/pdf-object-manager.js";
2
+ import type { FormFieldNode } from "../ir/display-list.js";
3
+ /**
4
+ * Collects the document's form fields as pages render, then emits the catalog `/AcroForm` dictionary at
5
+ * finalize. Mirrors `OutlineBuilder` / `DestRegistry`: a no-op returning "" when no field was placed, so
6
+ * a document without a form stays byte-identical.
7
+ */
8
+ export declare class AcroFormCollector {
9
+ private fieldRefs;
10
+ private radioGroups;
11
+ private needAppearances;
12
+ private helvNum?;
13
+ private zadbNum?;
14
+ private hasSignature;
15
+ private usedNames;
16
+ private bake;
17
+ /** Turn appearance baking off (`renderToBytes(doc, { fieldAppearances: false })`). */
18
+ setBakeAppearances(on: boolean): void;
19
+ /** The size to draw a value at. A field may ask for `0` - the PDF convention for "auto-size"; we then
20
+ * fit the capitals comfortably inside the box, which is what a viewer's auto-size does. */
21
+ private drawSize;
22
+ /** Measure one line for the appearance generator. */
23
+ private line;
24
+ /** Bake a text field's value into an appearance stream; returns the XObject number. */
25
+ private bakeText;
26
+ /** Bake a choice field: a combo shows its current value on one line, a list box shows its options
27
+ * with the selected rows highlighted. */
28
+ private bakeChoice;
29
+ get isEmpty(): boolean;
30
+ private helv;
31
+ /**
32
+ * ZapfDingbats, the font a check mark lives in. Needed even though we bake the appearance ourselves:
33
+ * a viewer told to regenerate (`/NeedAppearances`, which filling a form sets) redraws a check box from
34
+ * its `/DA`, and the conventional `/DA` for one names `/ZaDb`. Without the matching `/DR` entry the
35
+ * viewer cannot resolve the font - poppler says "Unknown font tag 'ZaDb'" and draws no check at all.
36
+ * No encoding: ZapfDingbats brings its own.
37
+ */
38
+ private zadb;
39
+ /**
40
+ * A field name is its identity: two fields sharing one are ONE field to every viewer, showing the same
41
+ * value in both places and overwriting each other as the reader types. The format allows it and says
42
+ * nothing, so the mistake surfaces only when someone fills the form. Named here instead.
43
+ *
44
+ * A radio GROUP is the exception - its buttons deliberately share a name, which is what makes them
45
+ * mutually exclusive - so it never comes through here.
46
+ */
47
+ private claimName;
48
+ /** Emit the widget object for one form-field IR node, register it as a field, and return its object
49
+ * number so the PageRenderer can add it to that page's /Annots. */
50
+ addField(node: FormFieldNode, om: PDFObjectManager): number;
51
+ /** A push button (/Btn, Pushbutton flag): no value, an optional action, and a baked caption. The
52
+ * caption is measured here (the appearance module stays free of font metrics) and drawn into an
53
+ * appearance stream that carries its own font resource. */
54
+ private buildPushButtonWidget;
55
+ /** A radio button: one KID widget of its group's shared field. The group field is reserved on first
56
+ * sight (and added to /Fields); each button adds itself to that field's /Kids. Returns the kid widget
57
+ * number, which goes into the PAGE /Annots (the parent field does not). */
58
+ private addRadio;
59
+ /** A signature field (/Sig): an EMPTY placeholder with a baked "sign here" face. No /V - an unsigned
60
+ * field has no value; a signing tool fills that in (and replaces this appearance) later. */
61
+ private buildSignatureWidget;
62
+ finalize(om: PDFObjectManager): string;
63
+ }