@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.
Files changed (279) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -21
  3. package/dist/api/args.d.ts +1 -1
  4. package/dist/api/args.js +2 -5
  5. package/dist/api/color.d.ts +4 -4
  6. package/dist/api/color.js +11 -17
  7. package/dist/api/content.d.ts +20 -13
  8. package/dist/api/content.js +44 -29
  9. package/dist/api/descriptor.d.ts +2 -2
  10. package/dist/api/descriptor.js +121 -31
  11. package/dist/api/dimension.d.ts +76 -0
  12. package/dist/api/dimension.js +43 -0
  13. package/dist/api/font-url.d.ts +28 -0
  14. package/dist/api/font-url.js +134 -0
  15. package/dist/api/forms.d.ts +347 -0
  16. package/dist/api/forms.js +189 -0
  17. package/dist/api/gradient.d.ts +53 -0
  18. package/dist/api/gradient.js +97 -0
  19. package/dist/api/index.d.ts +13 -8
  20. package/dist/api/index.js +13 -24
  21. package/dist/api/insets.d.ts +19 -12
  22. package/dist/api/insets.js +19 -12
  23. package/dist/api/layout.d.ts +149 -25
  24. package/dist/api/layout.js +182 -51
  25. package/dist/api/page-builder.d.ts +40 -0
  26. package/dist/api/page-builder.js +44 -0
  27. package/dist/api/structure.d.ts +107 -13
  28. package/dist/api/structure.js +187 -88
  29. package/dist/api/table.d.ts +5 -5
  30. package/dist/api/table.js +38 -26
  31. package/dist/api/text.d.ts +90 -4
  32. package/dist/api/text.js +116 -31
  33. package/dist/assets/font-data.d.ts +2 -0
  34. package/dist/assets/font-data.js +21 -0
  35. package/dist/assets/font-data.ts +37 -0
  36. package/dist/common/color.js +1 -5
  37. package/dist/constants/page-sizes.js +3 -6
  38. package/dist/constants/pdf-parts.js +1 -4
  39. package/dist/crypto/legacy-handler.d.ts +43 -0
  40. package/dist/crypto/legacy-handler.js +145 -0
  41. package/dist/crypto/security-handler.d.ts +62 -0
  42. package/dist/crypto/security-handler.js +155 -0
  43. package/dist/crypto/webcrypto.d.ts +11 -0
  44. package/dist/crypto/webcrypto.js +62 -0
  45. package/dist/edit/acroform-reader.d.ts +70 -0
  46. package/dist/edit/acroform-reader.js +126 -0
  47. package/dist/edit/appearance.d.ts +47 -0
  48. package/dist/edit/appearance.js +171 -0
  49. package/dist/edit/document.d.ts +145 -0
  50. package/dist/edit/document.js +642 -0
  51. package/dist/edit/fill.d.ts +65 -0
  52. package/dist/edit/fill.js +424 -0
  53. package/dist/edit/flatten.d.ts +54 -0
  54. package/dist/edit/flatten.js +462 -0
  55. package/dist/edit/index.d.ts +20 -0
  56. package/dist/edit/index.js +18 -0
  57. package/dist/edit/lexer.d.ts +30 -0
  58. package/dist/edit/lexer.js +285 -0
  59. package/dist/edit/objects.d.ts +68 -0
  60. package/dist/edit/objects.js +83 -0
  61. package/dist/edit/writer.d.ts +60 -0
  62. package/dist/edit/writer.js +283 -0
  63. package/dist/elements/container-element.d.ts +50 -5
  64. package/dist/elements/container-element.js +100 -39
  65. package/dist/elements/forms/checkbox-element.d.ts +51 -0
  66. package/dist/elements/forms/checkbox-element.js +48 -0
  67. package/dist/elements/forms/choice-element.d.ts +53 -0
  68. package/dist/elements/forms/choice-element.js +59 -0
  69. package/dist/elements/forms/push-button-element.d.ts +56 -0
  70. package/dist/elements/forms/push-button-element.js +49 -0
  71. package/dist/elements/forms/radio-element.d.ts +52 -0
  72. package/dist/elements/forms/radio-element.js +49 -0
  73. package/dist/elements/forms/signature-element.d.ts +54 -0
  74. package/dist/elements/forms/signature-element.js +47 -0
  75. package/dist/elements/forms/text-field-element.d.ts +61 -0
  76. package/dist/elements/forms/text-field-element.js +54 -0
  77. package/dist/elements/image-element.d.ts +58 -6
  78. package/dist/elements/image-element.js +145 -111
  79. package/dist/elements/index.d.ts +26 -10
  80. package/dist/elements/index.js +26 -28
  81. package/dist/elements/layout/anchor-element.d.ts +23 -0
  82. package/dist/elements/layout/anchor-element.js +27 -0
  83. package/dist/elements/layout/bookmark-element.d.ts +27 -0
  84. package/dist/elements/layout/bookmark-element.js +30 -0
  85. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  86. package/dist/elements/layout/default-text-style-element.js +47 -0
  87. package/dist/elements/layout/deferred-element.d.ts +3 -3
  88. package/dist/elements/layout/deferred-element.js +4 -8
  89. package/dist/elements/layout/expanded-element.d.ts +6 -4
  90. package/dist/elements/layout/expanded-element.js +22 -17
  91. package/dist/elements/layout/keep-together-element.d.ts +42 -0
  92. package/dist/elements/layout/keep-together-element.js +85 -0
  93. package/dist/elements/layout/link-element.d.ts +33 -0
  94. package/dist/elements/layout/link-element.js +39 -0
  95. package/dist/elements/layout/padding-element.d.ts +10 -5
  96. package/dist/elements/layout/padding-element.js +25 -16
  97. package/dist/elements/layout/page-break-element.d.ts +17 -0
  98. package/dist/elements/layout/page-break-element.js +24 -0
  99. package/dist/elements/layout/page-builder-element.d.ts +32 -0
  100. package/dist/elements/layout/page-builder-element.js +45 -0
  101. package/dist/elements/layout/positioned-element.d.ts +47 -0
  102. package/dist/elements/layout/positioned-element.js +73 -0
  103. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  104. package/dist/elements/layout/repeating-header-element.js +8 -12
  105. package/dist/elements/layout/rotated-box-element.d.ts +35 -0
  106. package/dist/elements/layout/rotated-box-element.js +54 -0
  107. package/dist/elements/layout/rotated-element.d.ts +32 -0
  108. package/dist/elements/layout/rotated-element.js +41 -0
  109. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  110. package/dist/elements/layout/sized-container-element.js +6 -11
  111. package/dist/elements/layout/struct-group.d.ts +28 -0
  112. package/dist/elements/layout/struct-group.js +42 -0
  113. package/dist/elements/line-element.d.ts +3 -3
  114. package/dist/elements/line-element.js +5 -10
  115. package/dist/elements/page-element.d.ts +26 -6
  116. package/dist/elements/page-element.js +72 -27
  117. package/dist/elements/pdf-document-element.d.ts +10 -4
  118. package/dist/elements/pdf-document-element.js +11 -10
  119. package/dist/elements/pdf-element.d.ts +150 -4
  120. package/dist/elements/pdf-element.js +138 -20
  121. package/dist/elements/rectangle-element.d.ts +52 -11
  122. package/dist/elements/rectangle-element.js +129 -36
  123. package/dist/elements/row-element.d.ts +45 -4
  124. package/dist/elements/row-element.js +66 -18
  125. package/dist/elements/text-element.d.ts +139 -11
  126. package/dist/elements/text-element.js +234 -57
  127. package/dist/forms/acroform.d.ts +63 -0
  128. package/dist/forms/acroform.js +427 -0
  129. package/dist/forms/appearance.d.ts +58 -0
  130. package/dist/forms/appearance.js +204 -0
  131. package/dist/forms/field.d.ts +164 -0
  132. package/dist/forms/field.js +1 -0
  133. package/dist/forms/pdf.d.ts +19 -0
  134. package/dist/forms/pdf.js +28 -0
  135. package/dist/index.d.ts +3 -3
  136. package/dist/index.js +3 -19
  137. package/dist/ir/display-list.d.ts +197 -8
  138. package/dist/ir/display-list.js +8 -2
  139. package/dist/layout/alignment.d.ts +10 -0
  140. package/dist/layout/alignment.js +6 -0
  141. package/dist/layout/box-constraints.d.ts +61 -0
  142. package/dist/layout/box-constraints.js +88 -6
  143. package/dist/layout/collect-images.d.ts +9 -0
  144. package/dist/layout/collect-images.js +34 -0
  145. package/dist/layout/fragmentation.d.ts +20 -1
  146. package/dist/layout/fragmentation.js +74 -18
  147. package/dist/layout/insets.d.ts +28 -0
  148. package/dist/layout/insets.js +20 -0
  149. package/dist/platform/browser-fs.d.ts +2 -0
  150. package/dist/platform/browser-fs.js +9 -0
  151. package/dist/platform/browser-image.d.ts +5 -0
  152. package/dist/platform/browser-image.js +13 -0
  153. package/dist/platform/node-fs.d.ts +2 -0
  154. package/dist/platform/node-fs.js +10 -0
  155. package/dist/platform/node-image.d.ts +5 -0
  156. package/dist/platform/node-image.js +9 -0
  157. package/dist/renderer/anchor-renderer.d.ts +6 -0
  158. package/dist/renderer/anchor-renderer.js +11 -0
  159. package/dist/renderer/bookmark-renderer.d.ts +6 -0
  160. package/dist/renderer/bookmark-renderer.js +11 -0
  161. package/dist/renderer/container-renderer.d.ts +3 -3
  162. package/dist/renderer/container-renderer.js +11 -28
  163. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  164. package/dist/renderer/default-text-style-renderer.js +10 -0
  165. package/dist/renderer/deferred-renderer.d.ts +3 -3
  166. package/dist/renderer/deferred-renderer.js +8 -23
  167. package/dist/renderer/emoji-image.d.ts +9 -0
  168. package/dist/renderer/emoji-image.js +68 -0
  169. package/dist/renderer/expanded-renderer.d.ts +3 -3
  170. package/dist/renderer/expanded-renderer.js +6 -21
  171. package/dist/renderer/form-field-renderer.d.ts +20 -0
  172. package/dist/renderer/form-field-renderer.js +12 -0
  173. package/dist/renderer/image-renderer.d.ts +4 -4
  174. package/dist/renderer/image-renderer.js +86 -75
  175. package/dist/renderer/index.d.ts +10 -10
  176. package/dist/renderer/index.js +10 -26
  177. package/dist/renderer/keep-together-renderer.d.ts +10 -0
  178. package/dist/renderer/keep-together-renderer.js +12 -0
  179. package/dist/renderer/line-renderer.d.ts +3 -3
  180. package/dist/renderer/line-renderer.js +13 -28
  181. package/dist/renderer/link-renderer.d.ts +6 -0
  182. package/dist/renderer/link-renderer.js +11 -0
  183. package/dist/renderer/padding-renderer.d.ts +3 -3
  184. package/dist/renderer/padding-renderer.js +6 -21
  185. package/dist/renderer/page-break-renderer.d.ts +14 -0
  186. package/dist/renderer/page-break-renderer.js +15 -0
  187. package/dist/renderer/page-builder-renderer.d.ts +6 -0
  188. package/dist/renderer/page-builder-renderer.js +11 -0
  189. package/dist/renderer/page-renderer.d.ts +2 -2
  190. package/dist/renderer/page-renderer.js +115 -77
  191. package/dist/renderer/pdf-backend.d.ts +31 -4
  192. package/dist/renderer/pdf-backend.js +287 -49
  193. package/dist/renderer/pdf-config.js +4 -7
  194. package/dist/renderer/pdf-document-class.d.ts +5 -5
  195. package/dist/renderer/pdf-document-class.js +27 -41
  196. package/dist/renderer/pdf-document-renderer.d.ts +19 -10
  197. package/dist/renderer/pdf-document-renderer.js +135 -91
  198. package/dist/renderer/pdf-renderer.d.ts +2 -2
  199. package/dist/renderer/pdf-renderer.js +165 -90
  200. package/dist/renderer/positioned-renderer.d.ts +6 -0
  201. package/dist/renderer/positioned-renderer.js +10 -0
  202. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  203. package/dist/renderer/rectangle-renderer.js +49 -44
  204. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  205. package/dist/renderer/repeating-header-renderer.js +10 -26
  206. package/dist/renderer/rotated-renderer.d.ts +7 -0
  207. package/dist/renderer/rotated-renderer.js +29 -0
  208. package/dist/renderer/row-renderer.d.ts +3 -3
  209. package/dist/renderer/row-renderer.js +11 -28
  210. package/dist/renderer/struct-group-renderer.d.ts +10 -0
  211. package/dist/renderer/struct-group-renderer.js +24 -0
  212. package/dist/renderer/text-renderer.d.ts +9 -5
  213. package/dist/renderer/text-renderer.js +437 -89
  214. package/dist/text/advance.d.ts +34 -0
  215. package/dist/text/advance.js +45 -0
  216. package/dist/text/arabic.d.ts +20 -0
  217. package/dist/text/arabic.js +101 -0
  218. package/dist/text/bidi.d.ts +33 -0
  219. package/dist/text/bidi.js +94 -0
  220. package/dist/text/emoji-codepoints.d.ts +1 -0
  221. package/dist/text/emoji-codepoints.js +29 -0
  222. package/dist/text/font-fallback.d.ts +25 -0
  223. package/dist/text/font-fallback.js +38 -0
  224. package/dist/text/glyph-coverage.d.ts +15 -0
  225. package/dist/text/glyph-coverage.js +77 -0
  226. package/dist/text/line-breaker.d.ts +50 -12
  227. package/dist/text/line-breaker.js +200 -54
  228. package/dist/text/line-metrics.d.ts +49 -0
  229. package/dist/text/line-metrics.js +57 -0
  230. package/dist/text/orphans-widows.d.ts +27 -0
  231. package/dist/text/orphans-widows.js +53 -0
  232. package/dist/text/shape.d.ts +29 -0
  233. package/dist/text/shape.js +67 -0
  234. package/dist/text/text-decoration.d.ts +50 -0
  235. package/dist/text/text-decoration.js +62 -0
  236. package/dist/text/text-style.d.ts +60 -0
  237. package/dist/text/text-style.js +79 -0
  238. package/dist/text/whitespace.d.ts +4 -0
  239. package/dist/text/whitespace.js +43 -0
  240. package/dist/utils/afm-parser.d.ts +34 -0
  241. package/dist/utils/afm-parser.js +76 -17
  242. package/dist/utils/bytes.d.ts +24 -0
  243. package/dist/utils/bytes.js +76 -0
  244. package/dist/utils/dest-registry.d.ts +22 -0
  245. package/dist/utils/dest-registry.js +32 -0
  246. package/dist/utils/flex-layout.d.ts +36 -9
  247. package/dist/utils/flex-layout.js +207 -30
  248. package/dist/utils/font-metrics.d.ts +26 -1
  249. package/dist/utils/font-metrics.js +1 -2
  250. package/dist/utils/font-path.js +3 -6
  251. package/dist/utils/gsub.d.ts +36 -0
  252. package/dist/utils/gsub.js +178 -0
  253. package/dist/utils/image-helper.d.ts +6 -5
  254. package/dist/utils/image-helper.js +101 -111
  255. package/dist/utils/inflate.d.ts +16 -0
  256. package/dist/utils/inflate.js +52 -0
  257. package/dist/utils/md5.d.ts +4 -0
  258. package/dist/utils/md5.js +79 -0
  259. package/dist/utils/outline.d.ts +21 -0
  260. package/dist/utils/outline.js +79 -0
  261. package/dist/utils/pdf-object-manager.d.ts +127 -8
  262. package/dist/utils/pdf-object-manager.js +615 -141
  263. package/dist/utils/renderer-registry.d.ts +13 -1
  264. package/dist/utils/renderer-registry.js +23 -6
  265. package/dist/utils/struct-tree.d.ts +44 -0
  266. package/dist/utils/struct-tree.js +129 -0
  267. package/dist/utils/ttf-parser.d.ts +134 -2
  268. package/dist/utils/ttf-parser.js +873 -50
  269. package/dist/utils/ttf-subsetter.d.ts +1 -1
  270. package/dist/utils/ttf-subsetter.js +40 -42
  271. package/dist/utils/ua-xmp.d.ts +9 -0
  272. package/dist/utils/ua-xmp.js +32 -0
  273. package/dist/utils/utf8-to-windows1252-encoder.d.ts +6 -0
  274. package/dist/utils/utf8-to-windows1252-encoder.js +11 -4
  275. package/dist/utils/woff.d.ts +10 -0
  276. package/dist/utils/woff.js +116 -0
  277. package/dist/validators/element-validator.d.ts +2 -2
  278. package/dist/validators/element-validator.js +31 -26
  279. package/package.json +22 -2
@@ -1,6 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
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
- return Object.assign(Object.assign({}, node), { y: pageHeight - node.y - node.height });
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 Object.assign(Object.assign({}, node), { y1: pageHeight - node.y1, y2: pageHeight - node.y2 });
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 Object.assign(Object.assign({}, node), { y: pageHeight - node.y });
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 = Object.assign(Object.assign({}, node), { y: pageHeight - node.y - node.height });
40
+ const flipped = { ...node, y: pageHeight - node.y - node.height };
33
41
  if (node.clip) {
34
- flipped.clip = Object.assign(Object.assign({}, node.clip), { y: pageHeight - node.clip.y - node.clip.height });
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
- static serialize(nodes, om) {
47
- return nodes.map((node) => PdfBackend.serializeNode(node, om)).join("");
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
- const r = Math.min(radius, w / 2, h / 2);
74
- const c = r * 0.5523; // control-point offset that approximates a quarter circle
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(xr)} ${f(y)} m\n` +
83
- `${f(xwr)} ${f(y)} l\n` +
84
- `${f(xwr + c)} ${f(y)} ${f(xw)} ${f(yr - c)} ${f(xw)} ${f(yr)} c\n` +
85
- `${f(xw)} ${f(yhr)} l\n` +
86
- `${f(xw)} ${f(yhr + c)} ${f(xwr + c)} ${f(yh)} ${f(xwr)} ${f(yh)} c\n` +
87
- `${f(xr)} ${f(yh)} l\n` +
88
- `${f(xr - c)} ${f(yh)} ${f(x)} ${f(yhr + c)} ${f(x)} ${f(yhr)} c\n` +
89
- `${f(x)} ${f(yr)} l\n` +
90
- `${f(x)} ${f(yr - c)} ${f(xr - c)} ${f(y)} ${f(xr)} ${f(y)} c\n` +
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 colour AND a positive width - a 0-width border means
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 && ((_a = node.strokeWidth) !== null && _a !== void 0 ? _a : 0) > 0;
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 = ((_b = node.radius) !== null && _b !== void 0 ? _b : 0) > 0
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, (_d = (_c = node.fill) === null || _c === void 0 ? void 0 : _c.getAlpha()) !== null && _d !== void 0 ? _d : 1, doStroke ? node.stroke.getAlpha() : 1);
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 textOp = isCustom
149
- ? `<${om.encodeCustomText(node.fontFamily, node.text, node.fontStyle)}>`
150
- : `(${PdfBackend.escapePdfString(node.text)})`;
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
- `${textOp} Tj\n` +
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
- return gs ? `q\n${gs}${block}Q\n` : block;
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 = ((_e = node.radius) !== null && _e !== void 0 ? _e : 0) > 0
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
- Object.defineProperty(exports, "__esModule", { value: true });
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 || (exports.Orientation = 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 || (exports.ColorMode = 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
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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
- var pdf_config_1 = require("./pdf-config");
17
- Object.defineProperty(exports, "ColorMode", { enumerable: true, get: function () { return pdf_config_1.ColorMode; } });
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: pdf_object_manager_1.FontStyle.Normal,
12
+ fontStyle: FontStyle.Normal,
27
13
  fullName: "Helvetica",
28
14
  },
29
15
  {
30
16
  fontName: "Helvetica",
31
- fontStyle: pdf_object_manager_1.FontStyle.Bold,
17
+ fontStyle: FontStyle.Bold,
32
18
  fullName: "Helvetica-Bold",
33
19
  },
34
20
  {
35
21
  fontName: "Helvetica",
36
- fontStyle: pdf_object_manager_1.FontStyle.Italic,
22
+ fontStyle: FontStyle.Italic,
37
23
  fullName: "Helvetica-Oblique",
38
24
  },
39
25
  {
40
26
  fontName: "Helvetica",
41
- fontStyle: pdf_object_manager_1.FontStyle.BoldItalic,
27
+ fontStyle: FontStyle.BoldItalic,
42
28
  fullName: "Helvetica-BoldOblique",
43
29
  },
44
- { fontName: "Courier", fontStyle: pdf_object_manager_1.FontStyle.Normal, fullName: "Courier" },
30
+ { fontName: "Courier", fontStyle: FontStyle.Normal, fullName: "Courier" },
45
31
  {
46
32
  fontName: "Courier",
47
- fontStyle: pdf_object_manager_1.FontStyle.Bold,
33
+ fontStyle: FontStyle.Bold,
48
34
  fullName: "Courier-Bold",
49
35
  },
50
36
  {
51
37
  fontName: "Courier",
52
- fontStyle: pdf_object_manager_1.FontStyle.Italic,
38
+ fontStyle: FontStyle.Italic,
53
39
  fullName: "Courier-Oblique",
54
40
  },
55
41
  {
56
42
  fontName: "Courier",
57
- fontStyle: pdf_object_manager_1.FontStyle.BoldItalic,
43
+ fontStyle: FontStyle.BoldItalic,
58
44
  fullName: "Courier-BoldOblique",
59
45
  },
60
46
  {
61
47
  fontName: "Times-Roman",
62
- fontStyle: pdf_object_manager_1.FontStyle.Normal,
48
+ fontStyle: FontStyle.Normal,
63
49
  fullName: "Times-Roman",
64
50
  },
65
51
  {
66
52
  fontName: "Times-Roman",
67
- fontStyle: pdf_object_manager_1.FontStyle.Bold,
53
+ fontStyle: FontStyle.Bold,
68
54
  fullName: "Times-Bold",
69
55
  },
70
56
  {
71
57
  fontName: "Times-Roman",
72
- fontStyle: pdf_object_manager_1.FontStyle.Italic,
58
+ fontStyle: FontStyle.Italic,
73
59
  fullName: "Times-Italic",
74
60
  },
75
61
  {
76
62
  fontName: "Times-Roman",
77
- fontStyle: pdf_object_manager_1.FontStyle.BoldItalic,
63
+ fontStyle: FontStyle.BoldItalic,
78
64
  fullName: "Times-BoldItalic",
79
65
  },
80
66
  {
81
67
  fontName: "Symbol",
82
- fontStyle: pdf_object_manager_1.FontStyle.Normal,
68
+ fontStyle: FontStyle.Normal,
83
69
  fullName: "Symbol",
84
70
  },
85
71
  {
86
72
  fontName: "ITC Zapf Dingbats",
87
- fontStyle: pdf_object_manager_1.FontStyle.Normal,
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 pdf_object_manager_1.PDFObjectManager();
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 ((config === null || config === void 0 ? void 0 : config.registerStandardFonts) !== false) {
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
- return __awaiter(this, void 0, void 0, function* () {
112
- const instance = new this();
113
- instance.child = instance.build();
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;