@jasy/pdf 1.0.0-alpha.1 → 1.0.0-alpha.11
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.
- package/LICENSE +21 -0
- package/README.md +35 -21
- package/dist/api/args.d.ts +1 -1
- package/dist/api/args.js +2 -5
- package/dist/api/color.d.ts +4 -4
- package/dist/api/color.js +11 -17
- package/dist/api/content.d.ts +20 -13
- package/dist/api/content.js +44 -29
- package/dist/api/descriptor.d.ts +2 -2
- package/dist/api/descriptor.js +121 -31
- package/dist/api/dimension.d.ts +76 -0
- package/dist/api/dimension.js +43 -0
- package/dist/api/font-url.d.ts +28 -0
- package/dist/api/font-url.js +134 -0
- package/dist/api/forms.d.ts +347 -0
- package/dist/api/forms.js +189 -0
- package/dist/api/gradient.d.ts +53 -0
- package/dist/api/gradient.js +97 -0
- package/dist/api/index.d.ts +13 -8
- package/dist/api/index.js +13 -24
- package/dist/api/insets.d.ts +19 -12
- package/dist/api/insets.js +19 -12
- package/dist/api/layout.d.ts +149 -25
- package/dist/api/layout.js +182 -51
- package/dist/api/page-builder.d.ts +40 -0
- package/dist/api/page-builder.js +44 -0
- package/dist/api/structure.d.ts +107 -13
- package/dist/api/structure.js +187 -88
- package/dist/api/table.d.ts +5 -5
- package/dist/api/table.js +38 -26
- package/dist/api/text.d.ts +90 -4
- package/dist/api/text.js +116 -31
- package/dist/assets/font-data.d.ts +2 -0
- package/dist/assets/font-data.js +21 -0
- package/dist/assets/font-data.ts +37 -0
- package/dist/common/color.js +1 -5
- package/dist/constants/page-sizes.js +3 -6
- package/dist/constants/pdf-parts.js +1 -4
- package/dist/crypto/legacy-handler.d.ts +43 -0
- package/dist/crypto/legacy-handler.js +145 -0
- package/dist/crypto/security-handler.d.ts +62 -0
- package/dist/crypto/security-handler.js +155 -0
- package/dist/crypto/webcrypto.d.ts +11 -0
- package/dist/crypto/webcrypto.js +62 -0
- package/dist/edit/acroform-reader.d.ts +70 -0
- package/dist/edit/acroform-reader.js +126 -0
- package/dist/edit/appearance.d.ts +47 -0
- package/dist/edit/appearance.js +171 -0
- package/dist/edit/document.d.ts +145 -0
- package/dist/edit/document.js +642 -0
- package/dist/edit/fill.d.ts +65 -0
- package/dist/edit/fill.js +424 -0
- package/dist/edit/flatten.d.ts +54 -0
- package/dist/edit/flatten.js +462 -0
- package/dist/edit/index.d.ts +20 -0
- package/dist/edit/index.js +18 -0
- package/dist/edit/lexer.d.ts +30 -0
- package/dist/edit/lexer.js +285 -0
- package/dist/edit/objects.d.ts +68 -0
- package/dist/edit/objects.js +83 -0
- package/dist/edit/writer.d.ts +60 -0
- package/dist/edit/writer.js +283 -0
- package/dist/elements/container-element.d.ts +50 -5
- package/dist/elements/container-element.js +100 -39
- package/dist/elements/forms/checkbox-element.d.ts +51 -0
- package/dist/elements/forms/checkbox-element.js +48 -0
- package/dist/elements/forms/choice-element.d.ts +53 -0
- package/dist/elements/forms/choice-element.js +59 -0
- package/dist/elements/forms/push-button-element.d.ts +56 -0
- package/dist/elements/forms/push-button-element.js +49 -0
- package/dist/elements/forms/radio-element.d.ts +52 -0
- package/dist/elements/forms/radio-element.js +49 -0
- package/dist/elements/forms/signature-element.d.ts +54 -0
- package/dist/elements/forms/signature-element.js +47 -0
- package/dist/elements/forms/text-field-element.d.ts +61 -0
- package/dist/elements/forms/text-field-element.js +54 -0
- package/dist/elements/image-element.d.ts +58 -6
- package/dist/elements/image-element.js +145 -111
- package/dist/elements/index.d.ts +26 -10
- package/dist/elements/index.js +26 -28
- package/dist/elements/layout/anchor-element.d.ts +23 -0
- package/dist/elements/layout/anchor-element.js +27 -0
- package/dist/elements/layout/bookmark-element.d.ts +27 -0
- package/dist/elements/layout/bookmark-element.js +30 -0
- package/dist/elements/layout/default-text-style-element.d.ts +30 -0
- package/dist/elements/layout/default-text-style-element.js +47 -0
- package/dist/elements/layout/deferred-element.d.ts +3 -3
- package/dist/elements/layout/deferred-element.js +4 -8
- package/dist/elements/layout/expanded-element.d.ts +6 -4
- package/dist/elements/layout/expanded-element.js +22 -17
- package/dist/elements/layout/keep-together-element.d.ts +42 -0
- package/dist/elements/layout/keep-together-element.js +85 -0
- package/dist/elements/layout/link-element.d.ts +33 -0
- package/dist/elements/layout/link-element.js +39 -0
- package/dist/elements/layout/padding-element.d.ts +10 -5
- package/dist/elements/layout/padding-element.js +25 -16
- package/dist/elements/layout/page-break-element.d.ts +17 -0
- package/dist/elements/layout/page-break-element.js +24 -0
- package/dist/elements/layout/page-builder-element.d.ts +32 -0
- package/dist/elements/layout/page-builder-element.js +45 -0
- package/dist/elements/layout/positioned-element.d.ts +47 -0
- package/dist/elements/layout/positioned-element.js +73 -0
- package/dist/elements/layout/repeating-header-element.d.ts +3 -3
- package/dist/elements/layout/repeating-header-element.js +8 -12
- package/dist/elements/layout/rotated-box-element.d.ts +35 -0
- package/dist/elements/layout/rotated-box-element.js +54 -0
- package/dist/elements/layout/rotated-element.d.ts +32 -0
- package/dist/elements/layout/rotated-element.js +41 -0
- package/dist/elements/layout/sized-container-element.d.ts +2 -2
- package/dist/elements/layout/sized-container-element.js +6 -11
- package/dist/elements/layout/struct-group.d.ts +28 -0
- package/dist/elements/layout/struct-group.js +42 -0
- package/dist/elements/line-element.d.ts +3 -3
- package/dist/elements/line-element.js +5 -10
- package/dist/elements/page-element.d.ts +26 -6
- package/dist/elements/page-element.js +72 -27
- package/dist/elements/pdf-document-element.d.ts +10 -4
- package/dist/elements/pdf-document-element.js +11 -10
- package/dist/elements/pdf-element.d.ts +150 -4
- package/dist/elements/pdf-element.js +138 -20
- package/dist/elements/rectangle-element.d.ts +52 -11
- package/dist/elements/rectangle-element.js +129 -36
- package/dist/elements/row-element.d.ts +45 -4
- package/dist/elements/row-element.js +66 -18
- package/dist/elements/text-element.d.ts +139 -11
- package/dist/elements/text-element.js +234 -57
- package/dist/forms/acroform.d.ts +63 -0
- package/dist/forms/acroform.js +427 -0
- package/dist/forms/appearance.d.ts +58 -0
- package/dist/forms/appearance.js +204 -0
- package/dist/forms/field.d.ts +164 -0
- package/dist/forms/field.js +1 -0
- package/dist/forms/pdf.d.ts +19 -0
- package/dist/forms/pdf.js +28 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -19
- package/dist/ir/display-list.d.ts +197 -8
- package/dist/ir/display-list.js +8 -2
- package/dist/layout/alignment.d.ts +10 -0
- package/dist/layout/alignment.js +6 -0
- package/dist/layout/box-constraints.d.ts +61 -0
- package/dist/layout/box-constraints.js +88 -6
- package/dist/layout/collect-images.d.ts +9 -0
- package/dist/layout/collect-images.js +34 -0
- package/dist/layout/fragmentation.d.ts +20 -1
- package/dist/layout/fragmentation.js +74 -18
- package/dist/layout/insets.d.ts +28 -0
- package/dist/layout/insets.js +20 -0
- package/dist/platform/browser-fs.d.ts +2 -0
- package/dist/platform/browser-fs.js +9 -0
- package/dist/platform/browser-image.d.ts +5 -0
- package/dist/platform/browser-image.js +13 -0
- package/dist/platform/node-fs.d.ts +2 -0
- package/dist/platform/node-fs.js +10 -0
- package/dist/platform/node-image.d.ts +5 -0
- package/dist/platform/node-image.js +9 -0
- package/dist/renderer/anchor-renderer.d.ts +6 -0
- package/dist/renderer/anchor-renderer.js +11 -0
- package/dist/renderer/bookmark-renderer.d.ts +6 -0
- package/dist/renderer/bookmark-renderer.js +11 -0
- package/dist/renderer/container-renderer.d.ts +3 -3
- package/dist/renderer/container-renderer.js +11 -28
- package/dist/renderer/default-text-style-renderer.d.ts +6 -0
- package/dist/renderer/default-text-style-renderer.js +10 -0
- package/dist/renderer/deferred-renderer.d.ts +3 -3
- package/dist/renderer/deferred-renderer.js +8 -23
- package/dist/renderer/emoji-image.d.ts +9 -0
- package/dist/renderer/emoji-image.js +68 -0
- package/dist/renderer/expanded-renderer.d.ts +3 -3
- package/dist/renderer/expanded-renderer.js +6 -21
- package/dist/renderer/form-field-renderer.d.ts +20 -0
- package/dist/renderer/form-field-renderer.js +12 -0
- package/dist/renderer/image-renderer.d.ts +4 -4
- package/dist/renderer/image-renderer.js +86 -75
- package/dist/renderer/index.d.ts +10 -10
- package/dist/renderer/index.js +10 -26
- package/dist/renderer/keep-together-renderer.d.ts +10 -0
- package/dist/renderer/keep-together-renderer.js +12 -0
- package/dist/renderer/line-renderer.d.ts +3 -3
- package/dist/renderer/line-renderer.js +13 -28
- package/dist/renderer/link-renderer.d.ts +6 -0
- package/dist/renderer/link-renderer.js +11 -0
- package/dist/renderer/padding-renderer.d.ts +3 -3
- package/dist/renderer/padding-renderer.js +6 -21
- package/dist/renderer/page-break-renderer.d.ts +14 -0
- package/dist/renderer/page-break-renderer.js +15 -0
- package/dist/renderer/page-builder-renderer.d.ts +6 -0
- package/dist/renderer/page-builder-renderer.js +11 -0
- package/dist/renderer/page-renderer.d.ts +2 -2
- package/dist/renderer/page-renderer.js +115 -77
- package/dist/renderer/pdf-backend.d.ts +31 -4
- package/dist/renderer/pdf-backend.js +287 -49
- package/dist/renderer/pdf-config.js +4 -7
- package/dist/renderer/pdf-document-class.d.ts +5 -5
- package/dist/renderer/pdf-document-class.js +27 -41
- package/dist/renderer/pdf-document-renderer.d.ts +19 -10
- package/dist/renderer/pdf-document-renderer.js +135 -91
- package/dist/renderer/pdf-renderer.d.ts +2 -2
- package/dist/renderer/pdf-renderer.js +165 -90
- package/dist/renderer/positioned-renderer.d.ts +6 -0
- package/dist/renderer/positioned-renderer.js +10 -0
- package/dist/renderer/rectangle-renderer.d.ts +3 -3
- package/dist/renderer/rectangle-renderer.js +49 -44
- package/dist/renderer/repeating-header-renderer.d.ts +3 -3
- package/dist/renderer/repeating-header-renderer.js +10 -26
- package/dist/renderer/rotated-renderer.d.ts +7 -0
- package/dist/renderer/rotated-renderer.js +29 -0
- package/dist/renderer/row-renderer.d.ts +3 -3
- package/dist/renderer/row-renderer.js +11 -28
- package/dist/renderer/struct-group-renderer.d.ts +10 -0
- package/dist/renderer/struct-group-renderer.js +24 -0
- package/dist/renderer/text-renderer.d.ts +9 -5
- package/dist/renderer/text-renderer.js +437 -89
- package/dist/text/advance.d.ts +34 -0
- package/dist/text/advance.js +45 -0
- package/dist/text/arabic.d.ts +20 -0
- package/dist/text/arabic.js +101 -0
- package/dist/text/bidi.d.ts +33 -0
- package/dist/text/bidi.js +94 -0
- package/dist/text/emoji-codepoints.d.ts +1 -0
- package/dist/text/emoji-codepoints.js +29 -0
- package/dist/text/font-fallback.d.ts +25 -0
- package/dist/text/font-fallback.js +38 -0
- package/dist/text/glyph-coverage.d.ts +15 -0
- package/dist/text/glyph-coverage.js +77 -0
- package/dist/text/line-breaker.d.ts +50 -12
- package/dist/text/line-breaker.js +200 -54
- package/dist/text/line-metrics.d.ts +49 -0
- package/dist/text/line-metrics.js +57 -0
- package/dist/text/orphans-widows.d.ts +27 -0
- package/dist/text/orphans-widows.js +53 -0
- package/dist/text/shape.d.ts +29 -0
- package/dist/text/shape.js +67 -0
- package/dist/text/text-decoration.d.ts +50 -0
- package/dist/text/text-decoration.js +62 -0
- package/dist/text/text-style.d.ts +60 -0
- package/dist/text/text-style.js +79 -0
- package/dist/text/whitespace.d.ts +4 -0
- package/dist/text/whitespace.js +43 -0
- package/dist/utils/afm-parser.d.ts +34 -0
- package/dist/utils/afm-parser.js +76 -17
- package/dist/utils/bytes.d.ts +24 -0
- package/dist/utils/bytes.js +76 -0
- package/dist/utils/dest-registry.d.ts +22 -0
- package/dist/utils/dest-registry.js +32 -0
- package/dist/utils/flex-layout.d.ts +36 -9
- package/dist/utils/flex-layout.js +207 -30
- package/dist/utils/font-metrics.d.ts +26 -1
- package/dist/utils/font-metrics.js +1 -2
- package/dist/utils/font-path.js +3 -6
- package/dist/utils/gsub.d.ts +36 -0
- package/dist/utils/gsub.js +178 -0
- package/dist/utils/image-helper.d.ts +6 -5
- package/dist/utils/image-helper.js +101 -111
- package/dist/utils/inflate.d.ts +16 -0
- package/dist/utils/inflate.js +52 -0
- package/dist/utils/md5.d.ts +4 -0
- package/dist/utils/md5.js +79 -0
- package/dist/utils/outline.d.ts +21 -0
- package/dist/utils/outline.js +79 -0
- package/dist/utils/pdf-object-manager.d.ts +127 -8
- package/dist/utils/pdf-object-manager.js +615 -141
- package/dist/utils/renderer-registry.d.ts +13 -1
- package/dist/utils/renderer-registry.js +23 -6
- package/dist/utils/struct-tree.d.ts +44 -0
- package/dist/utils/struct-tree.js +129 -0
- package/dist/utils/ttf-parser.d.ts +134 -2
- package/dist/utils/ttf-parser.js +873 -50
- package/dist/utils/ttf-subsetter.d.ts +1 -1
- package/dist/utils/ttf-subsetter.js +40 -42
- package/dist/utils/ua-xmp.d.ts +9 -0
- package/dist/utils/ua-xmp.js +32 -0
- package/dist/utils/utf8-to-windows1252-encoder.d.ts +6 -0
- package/dist/utils/utf8-to-windows1252-encoder.js +11 -4
- package/dist/utils/woff.d.ts +10 -0
- package/dist/utils/woff.js +116 -0
- package/dist/validators/element-validator.d.ts +2 -2
- package/dist/validators/element-validator.js +31 -26
- package/package.json +22 -2
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.PdfBackend = void 0;
|
|
1
|
+
import { isRounded } from "../ir/display-list.js";
|
|
2
|
+
import { Color } from "../common/color.js";
|
|
4
3
|
/**
|
|
5
4
|
* PDF backend - turns display-list primitives into content-stream operators.
|
|
6
5
|
*
|
|
@@ -9,7 +8,7 @@ exports.PdfBackend = void 0;
|
|
|
9
8
|
* emitted inline by the per-element renderers, so output stays byte-identical while
|
|
10
9
|
* the renderers are migrated onto the IR one at a time.
|
|
11
10
|
*/
|
|
12
|
-
class PdfBackend {
|
|
11
|
+
export class PdfBackend {
|
|
13
12
|
/**
|
|
14
13
|
* Flip a display list from the engine's top-left origin (y grows downward) to PDF's
|
|
15
14
|
* bottom-left origin (y grows upward). This is the ONE place the Y axis is flipped -
|
|
@@ -20,21 +19,80 @@ class PdfBackend {
|
|
|
20
19
|
static flipY(nodes, pageHeight) {
|
|
21
20
|
return nodes.map((node) => {
|
|
22
21
|
switch (node.type) {
|
|
23
|
-
case "rect":
|
|
24
|
-
|
|
22
|
+
case "rect": {
|
|
23
|
+
// A gradient fill carries its own page-space anchors; flip them with the box (see "path").
|
|
24
|
+
const fill = node.fill === undefined || node.fill instanceof Color
|
|
25
|
+
? node.fill
|
|
26
|
+
: { ...node.fill, y0: pageHeight - node.fill.y0, y1: pageHeight - node.fill.y1 };
|
|
27
|
+
return { ...node, y: pageHeight - node.y - node.height, fill };
|
|
28
|
+
}
|
|
25
29
|
case "line":
|
|
26
|
-
return
|
|
30
|
+
return {
|
|
31
|
+
...node,
|
|
32
|
+
y1: pageHeight - node.y1,
|
|
33
|
+
y2: pageHeight - node.y2,
|
|
34
|
+
};
|
|
27
35
|
case "text":
|
|
28
36
|
// node.y is the baseline measured from the page top; flip it directly.
|
|
29
|
-
return
|
|
37
|
+
return { ...node, y: pageHeight - node.y };
|
|
30
38
|
case "image": {
|
|
31
39
|
// Flip the placement box (and the clip frame, if any) around its bottom edge.
|
|
32
|
-
const flipped =
|
|
40
|
+
const flipped = { ...node, y: pageHeight - node.y - node.height };
|
|
33
41
|
if (node.clip) {
|
|
34
|
-
flipped.clip =
|
|
42
|
+
flipped.clip = {
|
|
43
|
+
...node.clip,
|
|
44
|
+
y: pageHeight - node.clip.y - node.clip.height,
|
|
45
|
+
};
|
|
35
46
|
}
|
|
36
47
|
return flipped;
|
|
37
48
|
}
|
|
49
|
+
case "clip-push":
|
|
50
|
+
// Flip the clip rect around its bottom edge, like a rect.
|
|
51
|
+
return { ...node, y: pageHeight - node.y - node.height };
|
|
52
|
+
case "clip-pop":
|
|
53
|
+
return node;
|
|
54
|
+
case "path": {
|
|
55
|
+
// Flip every point's y directly (like a line endpoint); `z` carries no coordinates.
|
|
56
|
+
const commands = node.commands.map((c) => {
|
|
57
|
+
if (c.op === "z")
|
|
58
|
+
return c;
|
|
59
|
+
if (c.op === "c") {
|
|
60
|
+
return { ...c, y1: pageHeight - c.y1, y2: pageHeight - c.y2, y: pageHeight - c.y };
|
|
61
|
+
}
|
|
62
|
+
return { ...c, y: pageHeight - c.y };
|
|
63
|
+
});
|
|
64
|
+
// A gradient fill carries its own page-space anchor points; flip their y too (radii and
|
|
65
|
+
// x stay). A solid Color fill has no geometry.
|
|
66
|
+
const fill = node.fill instanceof Color
|
|
67
|
+
? node.fill
|
|
68
|
+
: { ...node.fill, y0: pageHeight - node.fill.y0, y1: pageHeight - node.fill.y1 };
|
|
69
|
+
return { ...node, commands, fill };
|
|
70
|
+
}
|
|
71
|
+
case "link":
|
|
72
|
+
// A link's clickable rect flips around its bottom edge, exactly like a rect.
|
|
73
|
+
return { ...node, y: pageHeight - node.y - node.height };
|
|
74
|
+
case "formfield":
|
|
75
|
+
// A form field's box flips around its bottom edge, exactly like a link rect.
|
|
76
|
+
return { ...node, y: pageHeight - node.y - node.height };
|
|
77
|
+
case "outline":
|
|
78
|
+
// An outline anchor is a single point (the target's top); flip it like a text baseline.
|
|
79
|
+
return { ...node, y: pageHeight - node.y };
|
|
80
|
+
case "anchor":
|
|
81
|
+
// A named-destination anchor is a single point (the target's top), flipped like a baseline.
|
|
82
|
+
return { ...node, y: pageHeight - node.y };
|
|
83
|
+
case "transform-push": {
|
|
84
|
+
// The child nodes are flipped from top-left to bottom-left by F = [1,0,0,-1,0,H] (F is its
|
|
85
|
+
// own inverse). For a matrix authored in top-left space to act correctly on them, conjugate
|
|
86
|
+
// it by that flip: M_pdf = F · M · F. Worked out for [a,b,c,d,e,f] with H = pageHeight:
|
|
87
|
+
const [a, b, c, d, e, f] = node.matrix;
|
|
88
|
+
const H = pageHeight;
|
|
89
|
+
return {
|
|
90
|
+
...node,
|
|
91
|
+
matrix: [a, -b, -c, d, H * c + e, H - H * d - f],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
case "transform-pop":
|
|
95
|
+
return node; // no coordinates to flip
|
|
38
96
|
default: {
|
|
39
97
|
const unknown = node;
|
|
40
98
|
return unknown;
|
|
@@ -42,9 +100,59 @@ class PdfBackend {
|
|
|
42
100
|
}
|
|
43
101
|
});
|
|
44
102
|
}
|
|
45
|
-
/** Serialize a whole display list into one content stream (page-level entry point).
|
|
46
|
-
|
|
47
|
-
|
|
103
|
+
/** Serialize a whole display list into one content stream (page-level entry point). When a
|
|
104
|
+
* `PageStructContext` is given (accessible tagging on), each drawable node is wrapped in a marked-content
|
|
105
|
+
* sequence (`/Role <</MCID n>> BDC … EMC`, or `/Artifact` when untagged); graphics-state and empty nodes
|
|
106
|
+
* pass through untouched, so untagged output stays byte-identical. */
|
|
107
|
+
/**
|
|
108
|
+
* Every number reaching the backend must be finite. A non-finite coordinate is a layout bug, but
|
|
109
|
+
* silence turns it into a corrupt PDF: `Infinity` is written into the operator stream verbatim, and a
|
|
110
|
+
* viewer then discards everything from that point on - including the footer, which is drawn last. That
|
|
111
|
+
* failure is invisible until somebody opens the file, so we refuse instead.
|
|
112
|
+
*
|
|
113
|
+
* Checks the node's numbers, not the serialized text: a document containing the WORD "Infinity" is
|
|
114
|
+
* perfectly legal and must not trip this.
|
|
115
|
+
*/
|
|
116
|
+
static assertFinite(node) {
|
|
117
|
+
const finite = (value) => {
|
|
118
|
+
if (typeof value === "number")
|
|
119
|
+
return Number.isFinite(value);
|
|
120
|
+
if (Array.isArray(value))
|
|
121
|
+
return value.every(finite);
|
|
122
|
+
if (value !== null && typeof value === "object")
|
|
123
|
+
return Object.values(value).every(finite);
|
|
124
|
+
return true;
|
|
125
|
+
};
|
|
126
|
+
if (!finite(node)) {
|
|
127
|
+
throw new Error(`Layout produced a non-finite number on a "${node.type}" node, refusing to emit a corrupt ` +
|
|
128
|
+
`content stream. This is a bug in an element's calculateLayout (a size resolved to Infinity ` +
|
|
129
|
+
`or NaN), not in your document.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
static serialize(nodes, om, struct) {
|
|
133
|
+
return nodes
|
|
134
|
+
.map((node) => {
|
|
135
|
+
PdfBackend.assertFinite(node);
|
|
136
|
+
const ops = PdfBackend.serializeNode(node, om);
|
|
137
|
+
// Two kinds of node skip the marked-content wrapper, both because they carry no tag and never
|
|
138
|
+
// draw: GRAPHICS-STATE nodes (clip / transform push+pop) only save/restore state around the
|
|
139
|
+
// drawables they enclose, and SIDE-CHANNEL nodes (link, outline, anchor) become annotations /
|
|
140
|
+
// catalog entries instead of content-stream operators.
|
|
141
|
+
if (!struct ||
|
|
142
|
+
node.type === "clip-push" ||
|
|
143
|
+
node.type === "clip-pop" ||
|
|
144
|
+
node.type === "transform-push" ||
|
|
145
|
+
node.type === "transform-pop" ||
|
|
146
|
+
node.type === "link" ||
|
|
147
|
+
node.type === "outline" ||
|
|
148
|
+
node.type === "anchor" ||
|
|
149
|
+
node.type === "formfield" ||
|
|
150
|
+
ops === "")
|
|
151
|
+
return ops;
|
|
152
|
+
const { open, close } = struct.mark(node.tag);
|
|
153
|
+
return open + ops + close;
|
|
154
|
+
})
|
|
155
|
+
.join("");
|
|
48
156
|
}
|
|
49
157
|
/**
|
|
50
158
|
* Escapes a string for a PDF literal string `( ... )`. The backslash must be doubled
|
|
@@ -54,6 +162,27 @@ class PdfBackend {
|
|
|
54
162
|
static escapePdfString(text) {
|
|
55
163
|
return text.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
|
|
56
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* Builds the `[ ... ]` operand of a `TJ` from a run and its per-gap kern adjustments (em/1000, the
|
|
167
|
+
* sign the font declares - negative tightens). A `TJ` number moves the pen LEFT, so it is the
|
|
168
|
+
* NEGATED kern. Consecutive un-kerned glyphs stay in one encoded chunk, so `[(T) 40 (otal)]` rather
|
|
169
|
+
* than one chunk per glyph. `kerns[i]` is the adjustment AFTER code point `i`.
|
|
170
|
+
*/
|
|
171
|
+
static kernedArray(text, kerns, encode) {
|
|
172
|
+
const chars = [...text];
|
|
173
|
+
let out = "";
|
|
174
|
+
let chunk = chars[0] ?? "";
|
|
175
|
+
for (let i = 0; i < kerns.length; i++) {
|
|
176
|
+
if (kerns[i] === 0) {
|
|
177
|
+
chunk += chars[i + 1];
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
out += encode(chunk) + ` ${-kerns[i]} `;
|
|
181
|
+
chunk = chars[i + 1];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return `[${out}${encode(chunk)}]`;
|
|
185
|
+
}
|
|
57
186
|
/**
|
|
58
187
|
* Returns the `/GSx gs` operator that selects a transparency state, or `""` when both
|
|
59
188
|
* alphas are fully opaque. Opaque draws emit nothing here, so output stays
|
|
@@ -70,32 +199,50 @@ class PdfBackend {
|
|
|
70
199
|
* (kappa ≈ 0.5523). Returns m/l/c/h ops WITHOUT the paint operator.
|
|
71
200
|
*/
|
|
72
201
|
static roundedRectPath(x, y, w, h, radius) {
|
|
73
|
-
|
|
74
|
-
|
|
202
|
+
// Per corner, in PDF coordinates (y up). With all four equal this emits exactly the operators the
|
|
203
|
+
// single-radius version did - the byte-identity guard for every document that never asks for one.
|
|
204
|
+
const r = PdfBackend.clampRadii(radius, w, h);
|
|
205
|
+
const k = 0.5523; // control-point offset that approximates a quarter circle
|
|
75
206
|
const f = (n) => n.toFixed(3);
|
|
76
|
-
const xr = x + r;
|
|
77
|
-
const xwr = x + w - r;
|
|
78
207
|
const xw = x + w;
|
|
79
|
-
const yr = y + r;
|
|
80
|
-
const yhr = y + h - r;
|
|
81
208
|
const yh = y + h;
|
|
82
|
-
return (`${f(
|
|
83
|
-
`${f(
|
|
84
|
-
`${f(
|
|
85
|
-
`${f(xw)} ${f(
|
|
86
|
-
`${f(xw)} ${f(
|
|
87
|
-
`${f(
|
|
88
|
-
`${f(
|
|
89
|
-
`${f(x)} ${f(
|
|
90
|
-
`${f(x)} ${f(
|
|
209
|
+
return (`${f(x + r.bl)} ${f(y)} m\n` +
|
|
210
|
+
`${f(xw - r.br)} ${f(y)} l\n` +
|
|
211
|
+
`${f(xw - r.br + r.br * k)} ${f(y)} ${f(xw)} ${f(y + r.br - r.br * k)} ${f(xw)} ${f(y + r.br)} c\n` +
|
|
212
|
+
`${f(xw)} ${f(yh - r.tr)} l\n` +
|
|
213
|
+
`${f(xw)} ${f(yh - r.tr + r.tr * k)} ${f(xw - r.tr + r.tr * k)} ${f(yh)} ${f(xw - r.tr)} ${f(yh)} c\n` +
|
|
214
|
+
`${f(x + r.tl)} ${f(yh)} l\n` +
|
|
215
|
+
`${f(x + r.tl - r.tl * k)} ${f(yh)} ${f(x)} ${f(yh - r.tl + r.tl * k)} ${f(x)} ${f(yh - r.tl)} c\n` +
|
|
216
|
+
`${f(x)} ${f(y + r.bl)} l\n` +
|
|
217
|
+
`${f(x)} ${f(y + r.bl - r.bl * k)} ${f(x + r.bl - r.bl * k)} ${f(y)} ${f(x + r.bl)} ${f(y)} c\n` +
|
|
91
218
|
`h`);
|
|
92
219
|
}
|
|
220
|
+
/**
|
|
221
|
+
* Clamp the four radii into the box. Each is capped at half the box, and two radii sharing an edge
|
|
222
|
+
* are scaled down together when they would overlap - the CSS rule, and what keeps the path from
|
|
223
|
+
* folding back on itself.
|
|
224
|
+
*/
|
|
225
|
+
static clampRadii(radius, w, h) {
|
|
226
|
+
const n = typeof radius === "number" ? radius : 0;
|
|
227
|
+
const cap = Math.max(0, Math.min(w, h) / 2);
|
|
228
|
+
const at = (v) => Math.max(0, Math.min(v ?? n, cap));
|
|
229
|
+
const r = typeof radius === "number"
|
|
230
|
+
? { tl: at(radius), tr: at(radius), br: at(radius), bl: at(radius) }
|
|
231
|
+
: { tl: at(radius.tl), tr: at(radius.tr), br: at(radius.br), bl: at(radius.bl) };
|
|
232
|
+
// Per-edge overlap: scale the whole set by the tightest edge, so the corners stay proportional.
|
|
233
|
+
// An edge whose two corners are both 0 constrains NOTHING - it must not contribute a ratio of 0,
|
|
234
|
+
// which would scale every other corner away with it.
|
|
235
|
+
const ratio = (extent, a, b) => a + b > 0 ? extent / (a + b) : Infinity;
|
|
236
|
+
const scale = Math.min(1, ratio(w, r.tl, r.tr), ratio(w, r.bl, r.br), ratio(h, r.tl, r.bl), ratio(h, r.tr, r.br));
|
|
237
|
+
if (scale >= 1)
|
|
238
|
+
return r;
|
|
239
|
+
return { tl: r.tl * scale, tr: r.tr * scale, br: r.br * scale, bl: r.bl * scale };
|
|
240
|
+
}
|
|
93
241
|
/**
|
|
94
242
|
* Serialize a single display-list node to its content-stream operators.
|
|
95
243
|
* `om` is used only by primitives that allocate PDF resources (images, fonts).
|
|
96
244
|
*/
|
|
97
245
|
static serializeNode(node, om) {
|
|
98
|
-
var _a, _b, _c, _d, _e;
|
|
99
246
|
switch (node.type) {
|
|
100
247
|
case "line":
|
|
101
248
|
// q/Q isolates the graphics state; "[] 0 d" resets the dash pattern to solid.
|
|
@@ -109,28 +256,43 @@ class PdfBackend {
|
|
|
109
256
|
`S\n` +
|
|
110
257
|
`Q\n`);
|
|
111
258
|
case "rect": {
|
|
112
|
-
// Stroke only with a stroke
|
|
259
|
+
// Stroke only with a stroke color AND a positive width - a 0-width border means
|
|
113
260
|
// "no border" (e.g. a filled box with no outline). Nothing to paint at all (no
|
|
114
261
|
// fill, no border) draws nothing. Paint: B = fill+stroke, f = fill, S = stroke.
|
|
115
|
-
const doStroke = !!node.stroke && (
|
|
262
|
+
const doStroke = !!node.stroke && (node.strokeWidth ?? 0) > 0;
|
|
116
263
|
if (!node.fill && !doStroke)
|
|
117
264
|
return "";
|
|
118
|
-
let ops = "";
|
|
119
|
-
if (doStroke) {
|
|
120
|
-
ops += `${node.strokeWidth} w\n${node.stroke.toPDFColorString()} RG\n`;
|
|
121
|
-
}
|
|
122
|
-
if (node.fill)
|
|
123
|
-
ops += `${node.fill.toPDFColorString()} rg\n`;
|
|
124
|
-
const paint = node.fill ? (doStroke ? "B" : "f") : "S";
|
|
125
265
|
// Rounded corners emit a Bézier path; sharp corners keep the plain `re`
|
|
126
266
|
// (byte-identical when no radius is set).
|
|
127
|
-
const path = (
|
|
267
|
+
const path = isRounded(node.radius)
|
|
128
268
|
? PdfBackend.roundedRectPath(node.x, node.y, node.width, node.height, node.radius)
|
|
129
269
|
: `${node.x} ${node.y} ${node.width} ${node.height} re`;
|
|
270
|
+
// A gradient cannot be a fill COLOUR - PDF paints one with `sh`, which floods the current
|
|
271
|
+
// clip. So the box becomes the clip, the shading is painted inside it, and a border is
|
|
272
|
+
// stroked afterwards on its own. Solid fills keep the plain operators, byte for byte.
|
|
273
|
+
const gradient = node.fill !== undefined && !(node.fill instanceof Color) ? node.fill : undefined;
|
|
274
|
+
if (gradient) {
|
|
275
|
+
const shading = om.registerShading(gradient);
|
|
276
|
+
let out = `q\n${path} W n\n/${shading} sh\nQ\n`;
|
|
277
|
+
if (doStroke) {
|
|
278
|
+
const gsStroke = PdfBackend.alphaPrefix(om, 1, node.stroke.getAlpha());
|
|
279
|
+
const stroke = `${node.strokeWidth} w\n${node.stroke.toPDFColorString()} RG\n` + `${path} S\n`;
|
|
280
|
+
out += gsStroke ? `q\n${gsStroke}${stroke}Q\n` : stroke;
|
|
281
|
+
}
|
|
282
|
+
return out;
|
|
283
|
+
}
|
|
284
|
+
const fill = node.fill;
|
|
285
|
+
let ops = "";
|
|
286
|
+
if (doStroke) {
|
|
287
|
+
ops += `${node.strokeWidth} w\n${node.stroke.toPDFColorString()} RG\n`;
|
|
288
|
+
}
|
|
289
|
+
if (fill)
|
|
290
|
+
ops += `${fill.toPDFColorString()} rg\n`;
|
|
291
|
+
const paint = fill ? (doStroke ? "B" : "f") : "S";
|
|
130
292
|
const body = ops + `${path} ${paint}\n`;
|
|
131
293
|
// Transparency needs an isolating q/Q so the state does not leak; opaque rects
|
|
132
294
|
// keep their bare operators (byte-identical).
|
|
133
|
-
const gs = PdfBackend.alphaPrefix(om,
|
|
295
|
+
const gs = PdfBackend.alphaPrefix(om, fill?.getAlpha() ?? 1, doStroke ? node.stroke.getAlpha() : 1);
|
|
134
296
|
return gs ? `q\n${gs}${body}Q\n` : body;
|
|
135
297
|
}
|
|
136
298
|
case "text": {
|
|
@@ -145,34 +307,111 @@ class PdfBackend {
|
|
|
145
307
|
const font = isCustom
|
|
146
308
|
? om.getCustomFontResource(node.fontFamily, node.fontStyle)
|
|
147
309
|
: om.registerFont(node.fontFamily, node.fontStyle);
|
|
148
|
-
const
|
|
149
|
-
? `<${om.encodeCustomText(node.fontFamily,
|
|
150
|
-
: `(${PdfBackend.escapePdfString(
|
|
310
|
+
const encode = (t) => isCustom
|
|
311
|
+
? `<${om.encodeCustomText(node.fontFamily, t, node.fontStyle)}>`
|
|
312
|
+
: `(${PdfBackend.escapePdfString(t)})`;
|
|
313
|
+
// A shaped run brings its own glyphs, already in drawing order - they cannot be derived from
|
|
314
|
+
// the text here.
|
|
315
|
+
const shapedHex = node.glyphs && isCustom
|
|
316
|
+
? om.registerGlyphs(node.fontFamily, node.glyphs, node.fontStyle)
|
|
317
|
+
: undefined;
|
|
318
|
+
// Kerning (if the document has it on): a `TJ` array with the font's per-pair adjustments
|
|
319
|
+
// between glyph chunks, measured into the layout by the SAME numbers (runAdvance). A plain
|
|
320
|
+
// `Tj` when the run has no kerning, byte-identical.
|
|
321
|
+
const kerns = om.kerningEnabled
|
|
322
|
+
? om.getKernPairs(node.text, node.fontFamily, node.fontStyle)
|
|
323
|
+
: [];
|
|
324
|
+
const showOp = shapedHex
|
|
325
|
+
? `<${shapedHex}> Tj`
|
|
326
|
+
: kerns.some((k) => k !== 0)
|
|
327
|
+
? `${PdfBackend.kernedArray(node.text, kerns, encode)} TJ`
|
|
328
|
+
: `${encode(node.text)} Tj`;
|
|
329
|
+
// letterSpacing is the `Tc` operator: extra advance after EVERY glyph (an embedded
|
|
330
|
+
// Identity-H font too - that is `Tw`, word spacing, which only touches single-byte code 32).
|
|
331
|
+
const spacing = node.letterSpacing ? `${node.letterSpacing.toFixed(3)} Tc\n` : "";
|
|
151
332
|
const block = `BT\n` +
|
|
152
333
|
`${node.color.toPDFColorString()} rg ` +
|
|
153
334
|
`/F${font.fontIndex} ${node.fontSize} Tf ` +
|
|
154
335
|
`${node.x.toFixed(3)} ${node.y.toFixed(3)} Td ` +
|
|
155
|
-
`${
|
|
336
|
+
`${showOp}\n` +
|
|
156
337
|
`ET\n`;
|
|
157
|
-
// Transparent text gets an isolating q/Q + gs; opaque text is byte-identical.
|
|
158
338
|
const gs = PdfBackend.alphaPrefix(om, node.color.getAlpha(), 1);
|
|
159
|
-
|
|
339
|
+
// `Tc` is graphics state and would leak into the next run, so isolate it in q/Q - the same
|
|
340
|
+
// reason transparent text is isolated. A run with neither stays byte-identical.
|
|
341
|
+
return gs || spacing ? `q\n${gs}${spacing}${block}Q\n` : block;
|
|
160
342
|
}
|
|
161
343
|
case "image": {
|
|
162
344
|
// The backend owns PDF resource creation: register the XObject (using the
|
|
163
345
|
// source pixel dimensions) and then place it with a scaling matrix.
|
|
164
|
-
const ref = om.registerImage(node.intrinsicWidth, node.intrinsicHeight, node.imageType, node.data);
|
|
346
|
+
const ref = om.registerImage(node.intrinsicWidth, node.intrinsicHeight, node.imageType, node.data, node.smask);
|
|
165
347
|
const draw = `q\n${node.width} 0 0 ${node.height} ${node.x} ${node.y} cm\n` + `/IM${ref} Do\nQ\n`;
|
|
166
348
|
if (!node.clip)
|
|
167
349
|
return draw;
|
|
168
350
|
// Clip to the frame (re … W n); rounded when a radius is set. The rectangular
|
|
169
351
|
// path is byte-identical to before.
|
|
170
352
|
const c = node.clip;
|
|
171
|
-
const clipPath = (
|
|
353
|
+
const clipPath = isRounded(node.radius)
|
|
172
354
|
? PdfBackend.roundedRectPath(c.x, c.y, c.width, c.height, node.radius)
|
|
173
355
|
: `${c.x} ${c.y} ${c.width} ${c.height} re `;
|
|
174
356
|
return `q\n${clipPath}\nW n \n` + draw + `Q\n`;
|
|
175
357
|
}
|
|
358
|
+
case "clip-push": {
|
|
359
|
+
// Save the graphics state and intersect the clip with this (rounded) rect. Everything
|
|
360
|
+
// drawn until the matching clip-pop is cropped to it.
|
|
361
|
+
const path = isRounded(node.radius)
|
|
362
|
+
? PdfBackend.roundedRectPath(node.x, node.y, node.width, node.height, node.radius)
|
|
363
|
+
: `${node.x} ${node.y} ${node.width} ${node.height} re`;
|
|
364
|
+
return `q\n${path}\nW n\n`;
|
|
365
|
+
}
|
|
366
|
+
case "path": {
|
|
367
|
+
// A filled vector path (one color-glyph layer). Emit the subpath ops, then either a solid
|
|
368
|
+
// nonzero fill (a Color) or, for a gradient, clip to the path and paint a shading inside it.
|
|
369
|
+
const f = (n) => n.toFixed(3);
|
|
370
|
+
let path = "";
|
|
371
|
+
for (const c of node.commands) {
|
|
372
|
+
if (c.op === "m")
|
|
373
|
+
path += `${f(c.x)} ${f(c.y)} m\n`;
|
|
374
|
+
else if (c.op === "l")
|
|
375
|
+
path += `${f(c.x)} ${f(c.y)} l\n`;
|
|
376
|
+
else if (c.op === "c")
|
|
377
|
+
path += `${f(c.x1)} ${f(c.y1)} ${f(c.x2)} ${f(c.y2)} ${f(c.x)} ${f(c.y)} c\n`;
|
|
378
|
+
else
|
|
379
|
+
path += `h\n`;
|
|
380
|
+
}
|
|
381
|
+
if (!(node.fill instanceof Color)) {
|
|
382
|
+
// Gradient: clip to the path (W n keeps it as the clip without painting it), then paint
|
|
383
|
+
// the registered shading across that clip. The q/Q isolates the clip. Note: per-stop alpha
|
|
384
|
+
// is not represented (a DeviceRGB shading has no alpha channel - that would need a soft-mask
|
|
385
|
+
// group); COLR gradient stops are opaque in real fonts, so they render correctly.
|
|
386
|
+
const shading = om.registerShading(node.fill);
|
|
387
|
+
return `q\n${path}W n\n/${shading} sh\nQ\n`;
|
|
388
|
+
}
|
|
389
|
+
const body = `${node.fill.toPDFColorString()} rg\n${path}f\n`;
|
|
390
|
+
const gs = PdfBackend.alphaPrefix(om, node.fill.getAlpha(), 1);
|
|
391
|
+
return gs ? `q\n${gs}${body}Q\n` : body;
|
|
392
|
+
}
|
|
393
|
+
case "clip-pop":
|
|
394
|
+
return `Q\n`;
|
|
395
|
+
case "transform-push": {
|
|
396
|
+
// Save the graphics state, then apply the affine; everything until transform-pop paints through it.
|
|
397
|
+
const f = (n) => n.toFixed(3);
|
|
398
|
+
return `q\n${node.matrix.map(f).join(" ")} cm\n`;
|
|
399
|
+
}
|
|
400
|
+
case "transform-pop":
|
|
401
|
+
return `Q\n`;
|
|
402
|
+
case "link":
|
|
403
|
+
// A link draws nothing in the content stream - it becomes a page /Annot (built in PageRenderer).
|
|
404
|
+
return "";
|
|
405
|
+
case "outline":
|
|
406
|
+
// An outline anchor draws nothing - it becomes a /Outlines entry (built in PageRenderer/PDFRenderer).
|
|
407
|
+
return "";
|
|
408
|
+
case "anchor":
|
|
409
|
+
// A named destination draws nothing - it becomes a /Names /Dests entry (built in PageRenderer/PDFRenderer).
|
|
410
|
+
return "";
|
|
411
|
+
case "formfield":
|
|
412
|
+
// A form field draws nothing in the content stream - it becomes a Widget /Annot + /AcroForm field
|
|
413
|
+
// (built in PageRenderer via forms/acroform.ts).
|
|
414
|
+
return "";
|
|
176
415
|
default: {
|
|
177
416
|
// Exhaustiveness guard: if a new IRNode variant is added, this fails to compile.
|
|
178
417
|
const unknown = node;
|
|
@@ -181,4 +420,3 @@ class PdfBackend {
|
|
|
181
420
|
}
|
|
182
421
|
}
|
|
183
422
|
}
|
|
184
|
-
exports.PdfBackend = PdfBackend;
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
// Leaf module: no imports, so it can never sit inside an import cycle. The page/color
|
|
3
2
|
// enums live here because they are runtime values used across modules that DO form
|
|
4
3
|
// cycles (object manager <-> document <-> elements); importing them from a cyclic
|
|
5
4
|
// module snapshots them as `undefined` under some load orders.
|
|
6
|
-
|
|
7
|
-
exports.ColorMode = exports.Orientation = void 0;
|
|
8
|
-
var Orientation;
|
|
5
|
+
export var Orientation;
|
|
9
6
|
(function (Orientation) {
|
|
10
7
|
Orientation["portrait"] = "PORTRAIT";
|
|
11
8
|
Orientation["landscape"] = "LANDSCAPE";
|
|
12
|
-
})(Orientation || (
|
|
13
|
-
var ColorMode;
|
|
9
|
+
})(Orientation || (Orientation = {}));
|
|
10
|
+
export var ColorMode;
|
|
14
11
|
(function (ColorMode) {
|
|
15
12
|
ColorMode["color"] = "COLOR";
|
|
16
13
|
ColorMode["grayscale"] = "GRAYSCALE";
|
|
17
|
-
})(ColorMode || (
|
|
14
|
+
})(ColorMode || (ColorMode = {}));
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PageSize } from "../constants/page-sizes";
|
|
2
|
-
import { PDFDocumentElement } from "../elements";
|
|
3
|
-
import { FontStyle, PDFObjectManager } from "../utils/pdf-object-manager";
|
|
4
|
-
import { ColorMode, Orientation } from "./pdf-config";
|
|
5
|
-
export { ColorMode, Orientation } from "./pdf-config";
|
|
1
|
+
import { PageSize } from "../constants/page-sizes.js";
|
|
2
|
+
import { PDFDocumentElement } from "../elements/index.js";
|
|
3
|
+
import { FontStyle, PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
4
|
+
import { ColorMode, Orientation } from "./pdf-config.js";
|
|
5
|
+
export { ColorMode, Orientation } from "./pdf-config.js";
|
|
6
6
|
export interface Margin {
|
|
7
7
|
left: number;
|
|
8
8
|
top: number;
|
|
@@ -1,90 +1,76 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.PDFDocument = exports.Orientation = exports.ColorMode = void 0;
|
|
13
|
-
const pdf_object_manager_1 = require("../utils/pdf-object-manager");
|
|
14
|
-
const pdf_renderer_1 = require("./pdf-renderer");
|
|
1
|
+
import { FontStyle, PDFObjectManager } from "../utils/pdf-object-manager.js";
|
|
2
|
+
import { PDFRenderer } from "./pdf-renderer.js";
|
|
15
3
|
// Re-exported so existing `../renderer` consumers keep importing these from here.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Object.defineProperty(exports, "Orientation", { enumerable: true, get: function () { return pdf_config_1.Orientation; } });
|
|
19
|
-
class PDFDocument {
|
|
4
|
+
export { ColorMode, Orientation } from "./pdf-config.js";
|
|
5
|
+
export class PDFDocument {
|
|
20
6
|
//#region Helper
|
|
21
7
|
// Method to register all standard fonts
|
|
22
8
|
registerStandardFonts(objectManager) {
|
|
23
9
|
const standardFonts = [
|
|
24
10
|
{
|
|
25
11
|
fontName: "Helvetica",
|
|
26
|
-
fontStyle:
|
|
12
|
+
fontStyle: FontStyle.Normal,
|
|
27
13
|
fullName: "Helvetica",
|
|
28
14
|
},
|
|
29
15
|
{
|
|
30
16
|
fontName: "Helvetica",
|
|
31
|
-
fontStyle:
|
|
17
|
+
fontStyle: FontStyle.Bold,
|
|
32
18
|
fullName: "Helvetica-Bold",
|
|
33
19
|
},
|
|
34
20
|
{
|
|
35
21
|
fontName: "Helvetica",
|
|
36
|
-
fontStyle:
|
|
22
|
+
fontStyle: FontStyle.Italic,
|
|
37
23
|
fullName: "Helvetica-Oblique",
|
|
38
24
|
},
|
|
39
25
|
{
|
|
40
26
|
fontName: "Helvetica",
|
|
41
|
-
fontStyle:
|
|
27
|
+
fontStyle: FontStyle.BoldItalic,
|
|
42
28
|
fullName: "Helvetica-BoldOblique",
|
|
43
29
|
},
|
|
44
|
-
{ fontName: "Courier", fontStyle:
|
|
30
|
+
{ fontName: "Courier", fontStyle: FontStyle.Normal, fullName: "Courier" },
|
|
45
31
|
{
|
|
46
32
|
fontName: "Courier",
|
|
47
|
-
fontStyle:
|
|
33
|
+
fontStyle: FontStyle.Bold,
|
|
48
34
|
fullName: "Courier-Bold",
|
|
49
35
|
},
|
|
50
36
|
{
|
|
51
37
|
fontName: "Courier",
|
|
52
|
-
fontStyle:
|
|
38
|
+
fontStyle: FontStyle.Italic,
|
|
53
39
|
fullName: "Courier-Oblique",
|
|
54
40
|
},
|
|
55
41
|
{
|
|
56
42
|
fontName: "Courier",
|
|
57
|
-
fontStyle:
|
|
43
|
+
fontStyle: FontStyle.BoldItalic,
|
|
58
44
|
fullName: "Courier-BoldOblique",
|
|
59
45
|
},
|
|
60
46
|
{
|
|
61
47
|
fontName: "Times-Roman",
|
|
62
|
-
fontStyle:
|
|
48
|
+
fontStyle: FontStyle.Normal,
|
|
63
49
|
fullName: "Times-Roman",
|
|
64
50
|
},
|
|
65
51
|
{
|
|
66
52
|
fontName: "Times-Roman",
|
|
67
|
-
fontStyle:
|
|
53
|
+
fontStyle: FontStyle.Bold,
|
|
68
54
|
fullName: "Times-Bold",
|
|
69
55
|
},
|
|
70
56
|
{
|
|
71
57
|
fontName: "Times-Roman",
|
|
72
|
-
fontStyle:
|
|
58
|
+
fontStyle: FontStyle.Italic,
|
|
73
59
|
fullName: "Times-Italic",
|
|
74
60
|
},
|
|
75
61
|
{
|
|
76
62
|
fontName: "Times-Roman",
|
|
77
|
-
fontStyle:
|
|
63
|
+
fontStyle: FontStyle.BoldItalic,
|
|
78
64
|
fullName: "Times-BoldItalic",
|
|
79
65
|
},
|
|
80
66
|
{
|
|
81
67
|
fontName: "Symbol",
|
|
82
|
-
fontStyle:
|
|
68
|
+
fontStyle: FontStyle.Normal,
|
|
83
69
|
fullName: "Symbol",
|
|
84
70
|
},
|
|
85
71
|
{
|
|
86
72
|
fontName: "ITC Zapf Dingbats",
|
|
87
|
-
fontStyle:
|
|
73
|
+
fontStyle: FontStyle.Normal,
|
|
88
74
|
fullName: "ZapfDingbats",
|
|
89
75
|
},
|
|
90
76
|
];
|
|
@@ -94,25 +80,25 @@ class PDFDocument {
|
|
|
94
80
|
constructor(config) {
|
|
95
81
|
// One object manager per document instance - no global singleton. Threaded
|
|
96
82
|
// explicitly into the renderer.
|
|
97
|
-
this._objectManager = new
|
|
83
|
+
this._objectManager = new PDFObjectManager();
|
|
98
84
|
// Add all standard font families - unless the document is PDF/A, which forbids non-embedded
|
|
99
85
|
// fonts (the caller then supplies embedded fonts for every name it uses).
|
|
100
|
-
if (
|
|
86
|
+
if (config?.registerStandardFonts !== false) {
|
|
101
87
|
this.registerStandardFonts(this._objectManager);
|
|
102
88
|
}
|
|
103
89
|
if (config)
|
|
104
90
|
this._objectManager.changePDFConfig(config);
|
|
91
|
+
// Kerning is on by default at the document level (the `renderToBytes` path sets the same). A
|
|
92
|
+
// bare `PDFObjectManager` still defaults OFF, so unit tests keep predictable un-kerned metrics.
|
|
93
|
+
this._objectManager.setKerning(true);
|
|
105
94
|
}
|
|
106
95
|
get objectManager() {
|
|
107
96
|
return this._objectManager;
|
|
108
97
|
}
|
|
109
98
|
beforeRenderer() { }
|
|
110
|
-
static render() {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return yield pdf_renderer_1.PDFRenderer.render(instance.child, instance._objectManager);
|
|
115
|
-
});
|
|
99
|
+
static async render() {
|
|
100
|
+
const instance = new this();
|
|
101
|
+
instance.child = instance.build();
|
|
102
|
+
return await PDFRenderer.render(instance.child, instance._objectManager);
|
|
116
103
|
}
|
|
117
104
|
}
|
|
118
|
-
exports.PDFDocument = PDFDocument;
|