@jasy/pdf 1.0.0-alpha.1 → 1.0.0-alpha.10

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 (275) 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 +100 -13
  28. package/dist/api/structure.js +179 -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 +132 -11
  126. package/dist/elements/text-element.js +206 -56
  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/line-breaker.d.ts +50 -12
  225. package/dist/text/line-breaker.js +158 -37
  226. package/dist/text/line-metrics.d.ts +49 -0
  227. package/dist/text/line-metrics.js +57 -0
  228. package/dist/text/orphans-widows.d.ts +27 -0
  229. package/dist/text/orphans-widows.js +53 -0
  230. package/dist/text/shape.d.ts +29 -0
  231. package/dist/text/shape.js +67 -0
  232. package/dist/text/text-decoration.d.ts +50 -0
  233. package/dist/text/text-decoration.js +62 -0
  234. package/dist/text/text-style.d.ts +60 -0
  235. package/dist/text/text-style.js +79 -0
  236. package/dist/utils/afm-parser.d.ts +34 -0
  237. package/dist/utils/afm-parser.js +76 -17
  238. package/dist/utils/bytes.d.ts +24 -0
  239. package/dist/utils/bytes.js +76 -0
  240. package/dist/utils/dest-registry.d.ts +22 -0
  241. package/dist/utils/dest-registry.js +32 -0
  242. package/dist/utils/flex-layout.d.ts +36 -9
  243. package/dist/utils/flex-layout.js +207 -30
  244. package/dist/utils/font-metrics.d.ts +20 -1
  245. package/dist/utils/font-metrics.js +1 -2
  246. package/dist/utils/font-path.js +3 -6
  247. package/dist/utils/gsub.d.ts +36 -0
  248. package/dist/utils/gsub.js +178 -0
  249. package/dist/utils/image-helper.d.ts +6 -5
  250. package/dist/utils/image-helper.js +101 -111
  251. package/dist/utils/inflate.d.ts +16 -0
  252. package/dist/utils/inflate.js +52 -0
  253. package/dist/utils/md5.d.ts +4 -0
  254. package/dist/utils/md5.js +79 -0
  255. package/dist/utils/outline.d.ts +21 -0
  256. package/dist/utils/outline.js +79 -0
  257. package/dist/utils/pdf-object-manager.d.ts +110 -8
  258. package/dist/utils/pdf-object-manager.js +583 -141
  259. package/dist/utils/renderer-registry.d.ts +13 -1
  260. package/dist/utils/renderer-registry.js +23 -6
  261. package/dist/utils/struct-tree.d.ts +44 -0
  262. package/dist/utils/struct-tree.js +129 -0
  263. package/dist/utils/ttf-parser.d.ts +134 -2
  264. package/dist/utils/ttf-parser.js +873 -50
  265. package/dist/utils/ttf-subsetter.d.ts +1 -1
  266. package/dist/utils/ttf-subsetter.js +40 -42
  267. package/dist/utils/ua-xmp.d.ts +9 -0
  268. package/dist/utils/ua-xmp.js +32 -0
  269. package/dist/utils/utf8-to-windows1252-encoder.d.ts +6 -0
  270. package/dist/utils/utf8-to-windows1252-encoder.js +11 -4
  271. package/dist/utils/woff.d.ts +10 -0
  272. package/dist/utils/woff.js +116 -0
  273. package/dist/validators/element-validator.d.ts +2 -2
  274. package/dist/validators/element-validator.js +31 -26
  275. package/package.json +22 -2
@@ -1,6 +1,18 @@
1
+ /**
2
+ * Thrown when an element reaches the render pass with no registered renderer.
3
+ *
4
+ * This used to return undefined and every call site skipped the element silently, so a whole document
5
+ * could serialize to an empty content stream and still be a valid PDF - a blank page, no warning
6
+ * (ISSUE-11). The registry is keyed on the CONSTRUCTOR, which makes it the one place in the engine that
7
+ * two loaded copies of the library break: elements built by copy A are invisible to copy B.
8
+ */
9
+ export declare class MissingRendererError extends Error {
10
+ readonly elementName: string;
11
+ constructor(elementName: string);
12
+ }
1
13
  export declare class RendererRegistry {
2
14
  private static renderers;
3
15
  static register(elementClass: Function, renderer: Function): void;
4
- static getRenderer(element: object): Function | undefined;
16
+ static getRenderer(element: object): Function;
5
17
  static isRendererAsync(renderer: Function): boolean;
6
18
  }
@@ -1,19 +1,36 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RendererRegistry = void 0;
4
- class RendererRegistry {
1
+ /**
2
+ * Thrown when an element reaches the render pass with no registered renderer.
3
+ *
4
+ * This used to return undefined and every call site skipped the element silently, so a whole document
5
+ * could serialize to an empty content stream and still be a valid PDF - a blank page, no warning
6
+ * (ISSUE-11). The registry is keyed on the CONSTRUCTOR, which makes it the one place in the engine that
7
+ * two loaded copies of the library break: elements built by copy A are invisible to copy B.
8
+ */
9
+ export class MissingRendererError extends Error {
10
+ constructor(elementName) {
11
+ super(`@jasy/pdf: no renderer registered for "${elementName}". Either the element was never registered ` +
12
+ `in PDFRenderer.render(), or two copies of @jasy/pdf are loaded - the registry is keyed on the ` +
13
+ `element's constructor, so elements built by one copy cannot be rendered by the other. ` +
14
+ `Check the dependency tree for a duplicate (e.g. \`pnpm why @jasy/pdf\`).`);
15
+ this.elementName = elementName;
16
+ }
17
+ }
18
+ export class RendererRegistry {
5
19
  static register(elementClass, renderer) {
6
20
  if (!RendererRegistry.renderers.has(elementClass)) {
7
21
  RendererRegistry.renderers.set(elementClass, renderer);
8
22
  }
9
23
  }
10
24
  // Keyed on the element's constructor, so it only needs an object - not `any`.
25
+ // Throws rather than returning undefined: a missing renderer is always a bug, and skipping it drew nothing.
11
26
  static getRenderer(element) {
12
- return RendererRegistry.renderers.get(element.constructor);
27
+ const renderer = RendererRegistry.renderers.get(element.constructor);
28
+ if (!renderer)
29
+ throw new MissingRendererError(element.constructor.name);
30
+ return renderer;
13
31
  }
14
32
  static isRendererAsync(renderer) {
15
33
  return renderer.constructor.name === "AsyncFunction";
16
34
  }
17
35
  }
18
- exports.RendererRegistry = RendererRegistry;
19
36
  RendererRegistry.renderers = new Map();
@@ -0,0 +1,44 @@
1
+ import type { StructTag } from "../ir/display-list.js";
2
+ import type { PDFObjectManager } from "./pdf-object-manager.js";
3
+ /** Per-page tagging context: hands out page-local MCIDs and links them to their StructElem. */
4
+ export declare class PageStructContext {
5
+ readonly structParents: number;
6
+ private readonly tree;
7
+ private mcid;
8
+ constructor(structParents: number, tree: StructTree);
9
+ /** Marked-content delimiters for one drawable node. Tagged content gets an MCID linked to its (already
10
+ * registered) StructElem; untagged content becomes an Artifact (decoration, skipped by assistive tech). */
11
+ mark(tag?: StructTag): {
12
+ open: string;
13
+ close: string;
14
+ };
15
+ }
16
+ /** Builds the PDF structure tree for accessible tagging. One instance per document (held by the object manager). */
17
+ export declare class StructTree {
18
+ enabled: boolean;
19
+ lang: string;
20
+ title?: string;
21
+ private counter;
22
+ private structParentsCounter;
23
+ private elems;
24
+ private byStructId;
25
+ private stack;
26
+ private pageObjByStructParents;
27
+ /** Register a structure element for a logical element (keyed by its stable `structId`, so a paragraph or
28
+ * table split across pages resolves to the SAME element - MCIDs then accrue from every page). Its parent
29
+ * is the currently-open container, else the Document. Containers also push()/pop() around their children. */
30
+ openElement(structId: number, role: string, opts?: {
31
+ alt?: string;
32
+ }): number;
33
+ push(key: number): void;
34
+ pop(): void;
35
+ /** Begin a page: allocates its StructParents index (its slot in the ParentTree). */
36
+ beginPage(): PageStructContext;
37
+ /** Tie a page's StructParents index to its now-known page object number (for /Pg references). */
38
+ setPageObject(structParents: number, pageObjNum: number): void;
39
+ /** Link a page-local MCID to an element (called by the backend while serializing). */
40
+ linkMarkedContent(key: number, structParents: number, mcid: number): void;
41
+ /** Emit the struct-tree objects and return the catalog additions (`/MarkInfo`, `/StructTreeRoot`, `/Lang`).
42
+ * A no-op returning "" when disabled or nothing was tagged, so a plain document stays byte-identical. */
43
+ finalize(om: PDFObjectManager): string;
44
+ }
@@ -0,0 +1,129 @@
1
+ // Escapes a PDF literal string ( ... ) - the language tag is safe ASCII, but /Alt can carry arbitrary text.
2
+ // A structure role reaches the PDF as a raw name (/H1, /S /Table). Roles come from a controlled set,
3
+ // but restrict them to a safe PDF-name token anyway (defence-in-depth) so a stray "/", whitespace, or
4
+ // operator can never corrupt the content stream / object dictionary. Empty after stripping -> /Span.
5
+ const roleName = (role) => role.replace(/[^A-Za-z0-9]/g, "") || "Span";
6
+ /** Per-page tagging context: hands out page-local MCIDs and links them to their StructElem. */
7
+ export class PageStructContext {
8
+ constructor(structParents, tree) {
9
+ this.structParents = structParents;
10
+ this.tree = tree;
11
+ this.mcid = 0;
12
+ }
13
+ /** Marked-content delimiters for one drawable node. Tagged content gets an MCID linked to its (already
14
+ * registered) StructElem; untagged content becomes an Artifact (decoration, skipped by assistive tech). */
15
+ mark(tag) {
16
+ // Artifact = decoration, no properties -> BMC (BDC would need a second operand and is a syntax error).
17
+ if (!tag)
18
+ return { open: "/Artifact BMC\n", close: "EMC\n" };
19
+ const mcid = this.mcid++;
20
+ this.tree.linkMarkedContent(tag.key, this.structParents, mcid);
21
+ return { open: `/${roleName(tag.role)} <</MCID ${mcid}>> BDC\n`, close: "EMC\n" };
22
+ }
23
+ }
24
+ /** Builds the PDF structure tree for accessible tagging. One instance per document (held by the object manager). */
25
+ export class StructTree {
26
+ constructor() {
27
+ this.enabled = false;
28
+ this.lang = "en-US";
29
+ this.counter = 0;
30
+ this.structParentsCounter = 0;
31
+ this.elems = new Map(); // insertion order = render order = reading order
32
+ this.byStructId = new Map(); // element structId -> element key (dedup across pages)
33
+ this.stack = []; // open containers; top is the current parent
34
+ this.pageObjByStructParents = new Map();
35
+ }
36
+ /** Register a structure element for a logical element (keyed by its stable `structId`, so a paragraph or
37
+ * table split across pages resolves to the SAME element - MCIDs then accrue from every page). Its parent
38
+ * is the currently-open container, else the Document. Containers also push()/pop() around their children. */
39
+ openElement(structId, role, opts) {
40
+ const existing = this.byStructId.get(structId);
41
+ if (existing !== undefined)
42
+ return existing; // already opened on an earlier page/fragment
43
+ const key = this.counter++;
44
+ this.byStructId.set(structId, key);
45
+ this.elems.set(key, {
46
+ key,
47
+ role,
48
+ alt: opts?.alt,
49
+ parent: this.stack[this.stack.length - 1],
50
+ mc: [],
51
+ });
52
+ return key;
53
+ }
54
+ push(key) {
55
+ this.stack.push(key);
56
+ }
57
+ pop() {
58
+ this.stack.pop();
59
+ }
60
+ /** Begin a page: allocates its StructParents index (its slot in the ParentTree). */
61
+ beginPage() {
62
+ return new PageStructContext(this.structParentsCounter++, this);
63
+ }
64
+ /** Tie a page's StructParents index to its now-known page object number (for /Pg references). */
65
+ setPageObject(structParents, pageObjNum) {
66
+ this.pageObjByStructParents.set(structParents, pageObjNum);
67
+ }
68
+ /** Link a page-local MCID to an element (called by the backend while serializing). */
69
+ linkMarkedContent(key, structParents, mcid) {
70
+ this.elems.get(key)?.mc.push({ structParents, mcid });
71
+ }
72
+ /** Emit the struct-tree objects and return the catalog additions (`/MarkInfo`, `/StructTreeRoot`, `/Lang`).
73
+ * A no-op returning "" when disabled or nothing was tagged, so a plain document stays byte-identical. */
74
+ finalize(om) {
75
+ if (!this.enabled || this.elems.size === 0)
76
+ return "";
77
+ // Reserve object numbers first - root <-> Document <-> elements <-> ParentTree reference each other.
78
+ const rootNum = om.addObject("");
79
+ const docNum = om.addObject("");
80
+ const parentTreeNum = om.addObject("");
81
+ const objNum = new Map();
82
+ for (const key of this.elems.keys())
83
+ objNum.set(key, om.addObject(""));
84
+ const pg = (structParents) => this.pageObjByStructParents.get(structParents);
85
+ const childrenOf = (parent) => [...this.elems.values()].filter((e) => e.parent === parent); // Map order = reading order
86
+ // One StructElem per registered element: /K = its child elements ++ its marked-content references.
87
+ for (const e of this.elems.values()) {
88
+ const kids = [
89
+ ...childrenOf(e.key).map((c) => `${objNum.get(c.key)} 0 R`),
90
+ ...e.mc.map((m) => `<< /Type /MCR /Pg ${pg(m.structParents)} 0 R /MCID ${m.mcid} >>`),
91
+ ].join(" ");
92
+ const alt = e.alt ? ` /Alt ${om.pdfString(e.alt)}` : "";
93
+ // PDF/UA 7.5: a header cell needs a Scope so a reader can associate data cells with it. Our headers
94
+ // are a header ROW (the Table `header` option), so each TH is the head of its Column.
95
+ const attr = e.role === "TH" ? " /A << /O /Table /Scope /Column >>" : "";
96
+ const parentRef = e.parent !== undefined ? objNum.get(e.parent) : docNum;
97
+ om.replaceObject(objNum.get(e.key), `<< /Type /StructElem /S /${roleName(e.role)} /P ${parentRef} 0 R${alt}${attr} /K [ ${kids} ] >>`);
98
+ }
99
+ // The Document element wraps the top-level elements in reading order.
100
+ const docKids = childrenOf(undefined)
101
+ .map((e) => `${objNum.get(e.key)} 0 R`)
102
+ .join(" ");
103
+ om.replaceObject(docNum, `<< /Type /StructElem /S /Document /P ${rootNum} 0 R /K [ ${docKids} ] >>`);
104
+ // ParentTree: for each page (StructParents index), an array where [mcid] = the owning StructElem.
105
+ const byPage = new Map();
106
+ for (const e of this.elems.values()) {
107
+ for (const m of e.mc) {
108
+ const list = byPage.get(m.structParents) ?? [];
109
+ list.push({ mcid: m.mcid, key: e.key });
110
+ byPage.set(m.structParents, list);
111
+ }
112
+ }
113
+ const nums = [...byPage.keys()]
114
+ .sort((a, b) => a - b)
115
+ .map((sp) => {
116
+ const refs = byPage
117
+ .get(sp)
118
+ .slice()
119
+ .sort((a, b) => a.mcid - b.mcid)
120
+ .map((r) => `${objNum.get(r.key)} 0 R`)
121
+ .join(" ");
122
+ return `${sp} [ ${refs} ]`;
123
+ });
124
+ om.replaceObject(parentTreeNum, `<< /Nums [ ${nums.join(" ")} ] >>`);
125
+ om.replaceObject(rootNum, `<< /Type /StructTreeRoot /K ${docNum} 0 R /ParentTree ${parentTreeNum} 0 R ` +
126
+ `/ParentTreeNextKey ${this.structParentsCounter} >>`);
127
+ return `/MarkInfo << /Marked true >> /StructTreeRoot ${rootNum} 0 R /Lang ${om.pdfString(this.lang)}`;
128
+ }
129
+ }
@@ -1,29 +1,161 @@
1
+ import type { FontDecoration } from "../text/text-decoration.js";
2
+ import { GsubTable } from "./gsub.js";
3
+ export type GlyphPathCommand = {
4
+ type: "M";
5
+ x: number;
6
+ y: number;
7
+ } | {
8
+ type: "L";
9
+ x: number;
10
+ y: number;
11
+ } | {
12
+ type: "Q";
13
+ cx: number;
14
+ cy: number;
15
+ x: number;
16
+ y: number;
17
+ } | {
18
+ type: "Z";
19
+ };
20
+ export interface RGBA {
21
+ r: number;
22
+ g: number;
23
+ b: number;
24
+ a: number;
25
+ }
26
+ export interface ColorStop {
27
+ offset: number;
28
+ color: RGBA | null;
29
+ }
30
+ export type Paint = {
31
+ type: "solid";
32
+ color: RGBA | null;
33
+ } | {
34
+ type: "linearGradient";
35
+ p0: [number, number];
36
+ p1: [number, number];
37
+ stops: ColorStop[];
38
+ extend: "pad" | "repeat" | "reflect";
39
+ } | {
40
+ type: "radialGradient";
41
+ c0: [number, number, number];
42
+ c1: [number, number, number];
43
+ stops: ColorStop[];
44
+ extend: "pad" | "repeat" | "reflect";
45
+ };
46
+ export type Affine = [number, number, number, number, number, number];
47
+ export interface ColorGlyphLayer {
48
+ glyphId: number;
49
+ paint: Paint;
50
+ transform?: Affine;
51
+ }
52
+ /** Sorts x-intervals and unions the overlapping ones. */
53
+ export declare function mergeSpans(spans: Array<[number, number]>): Array<[number, number]>;
1
54
  export declare class TTFParser {
2
55
  private data;
3
56
  unitsPerEm: number;
4
57
  ascent: number;
5
58
  descent: number;
59
+ lineGap: number;
60
+ private underlinePositionRaw;
61
+ private underlineThicknessRaw;
62
+ private xHeightRaw;
63
+ private capHeightRaw;
64
+ private cachedDecoration?;
6
65
  bbox: [number, number, number, number];
7
66
  private numGlyphs;
8
67
  private numHMetrics;
68
+ private indexToLocFormat;
9
69
  private advanceWidths;
10
70
  private cmap;
11
71
  private cmapGroups;
12
72
  private tables;
13
- constructor(data: Buffer);
14
- getData(): Buffer;
73
+ private colrBase;
74
+ private colrLayersOffset;
75
+ private palette;
76
+ private colrBaseV1;
77
+ private colrLayerListOffset;
78
+ private kernPairs;
79
+ private hasKerning;
80
+ private gposPairPos;
81
+ private gsubTable?;
82
+ constructor(data: Uint8Array);
83
+ getData(): Uint8Array;
15
84
  glyphCount(): number;
16
85
  glyphWidths(): number[];
17
86
  reverseCmap(): Map<number, number>;
18
87
  private toGlyphSpace;
88
+ /** The font's `GSUB`, or undefined when it has none. Parsed once, on demand. */
89
+ gsub(): GsubTable | undefined;
19
90
  getGlyphIndex(codePoint: number): number;
20
91
  getAdvanceWidth(glyphIndex: number): number;
92
+ /** Font units -> points at `fontSize`; the one scaling rule for shaped and plain advances alike. */
93
+ unitsToPoints(units: number, fontSize: number): number;
21
94
  getCharWidth(char: string, fontSize: number): number;
22
95
  getStringWidth(text: string, fontSize: number): number;
96
+ private readDecorationMetrics;
97
+ /**
98
+ * Underline / strikethrough geometry, as fractions of the em.
99
+ *
100
+ * A font without `post` (rare) gets the classic 10% below the baseline at 5% thickness - the same
101
+ * numbers all 14 standard AFMs happen to declare, so it is a measured convention rather than an
102
+ * invention. A font whose `OS/2` predates version 2 has no x- or cap-height, so we MEASURE them off
103
+ * the outlines of `x` and `H` instead of guessing.
104
+ */
105
+ decoration(): FontDecoration;
106
+ /** The highest ON-CURVE point of a code point's outline, in font units; 0 for a missing glyph.
107
+ * A quadratic's control point may sit above the curve, so it is not a bound - and `x`/`H` have
108
+ * flat tops in any face where this fallback matters. */
109
+ private outlineTop;
110
+ /**
111
+ * Where a glyph's INK crosses a horizontal band, as x-intervals in font units (pen origin at 0).
112
+ * This is what lets an underline step around a descender ("skip-ink"), the way a browser does.
113
+ *
114
+ * Scanline fill: sample a few horizontal lines across the band, find every place the outline
115
+ * crosses them, and pair the crossings up into filled spans. A handful of scanlines is plenty -
116
+ * the band is a few percent of the em tall, and a descender stem does not wander inside it.
117
+ *
118
+ * `yTop` / `yBottom` are in font units, y UP from the baseline (so both are negative under it).
119
+ * Returns [] for a glyph with no outline (a space, an unmapped code point, a composite we cannot
120
+ * decompose) - the caller then leaves the line unbroken there, which is the safe direction.
121
+ */
122
+ inkSpansInBand(codePoint: number, yTop: number, yBottom: number): Array<[number, number]>;
123
+ /** True if the font declares any horizontal kerning (kern table or GPOS). */
124
+ kerns(): boolean;
125
+ private kernCache;
126
+ /** Kerning between two glyphs, in em/1000 (the standard-14 unit); 0 if the pair is not kerned.
127
+ * Negative tightens, matching the AFM sign. GPOS wins over the legacy `kern` table when both
128
+ * exist (it is what a modern shaper uses, and can carry more pairs). */
129
+ getKerning(leftGid: number, rightGid: number): number;
130
+ private readKern;
131
+ private readGpos;
132
+ private gposKern;
133
+ private static valueRecordSize;
134
+ private xAdvance;
135
+ private coverageIndex;
136
+ private classOf;
23
137
  private table;
24
138
  private readTableDirectory;
25
139
  private readHmtx;
26
140
  private readCmap;
27
141
  private readCmapFormat4;
28
142
  private readCmapFormat12;
143
+ hasGlyfOutlines(): boolean;
144
+ private glyfRange;
145
+ getGlyphPath(glyphId: number): GlyphPathCommand[];
146
+ private parseSimpleGlyph;
147
+ private readCoordinates;
148
+ private contourToCommands;
149
+ hasColorGlyphs(): boolean;
150
+ getColorGlyph(glyphId: number): ColorGlyphLayer[] | null;
151
+ private walkColrLayers;
152
+ private resolveFill;
153
+ private readColorLine;
154
+ private paletteColor;
155
+ private u24;
156
+ private f2dot14;
157
+ private i32;
158
+ private readAffine;
159
+ private readColr;
160
+ private readCpal;
29
161
  }