@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,81 +1,119 @@
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.PageRenderer = void 0;
13
- const page_sizes_1 = require("../constants/page-sizes");
14
- const renderer_registry_1 = require("../utils/renderer-registry");
15
- const pdf_config_1 = require("./pdf-config");
16
- const pdf_backend_1 = require("./pdf-backend");
17
- class PageRenderer {
18
- static render(page, objectManager) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- var _a;
21
- const { children, config, header, footer } = page.getProps();
22
- // Header (top band) and footer (bottom band) sit around the body and repeat on every
23
- // physical page; they are placed by `PageElement.calculateLayout` / the page driver.
24
- const renderables = [...(header ? [header] : []), ...children, ...(footer ? [footer] : [])];
25
- // Page geometry (also the MediaBox below). Needed up front because flipping the
26
- // display list to PDF coordinates uses the page height. config is fully resolved
27
- // by the layout pass; fall back to the document default rather than asserting.
28
- let [width, height] = page_sizes_1.pageFormats[(_a = config === null || config === void 0 ? void 0 : config.pageSize) !== null && _a !== void 0 ? _a : page_sizes_1.PageSize.A4];
29
- if ((config === null || config === void 0 ? void 0 : config.orientation) === pdf_config_1.Orientation.landscape) {
30
- [width, height] = [height, width];
1
+ import { pageFormats, PageSize } from "../constants/page-sizes.js";
2
+ import { RendererRegistry } from "../utils/renderer-registry.js";
3
+ import { Orientation } from "./pdf-config.js";
4
+ import { PdfBackend } from "./pdf-backend.js";
5
+ export class PageRenderer {
6
+ static async render(page, objectManager) {
7
+ const { children, config, header, footer } = page.getProps();
8
+ // Header (top band) and footer (bottom band) sit around the body and repeat on every
9
+ // physical page; they are placed by `PageElement.calculateLayout` / the page driver.
10
+ const renderables = [...(header ? [header] : []), ...children, ...(footer ? [footer] : [])];
11
+ // Page geometry (also the MediaBox below). Needed up front because flipping the
12
+ // display list to PDF coordinates uses the page height. config is fully resolved
13
+ // by the layout pass; fall back to the document default rather than asserting.
14
+ let [width, height] = config?.customSize ?? pageFormats[config?.pageSize ?? PageSize.A4];
15
+ if (config?.orientation === Orientation.landscape) {
16
+ [width, height] = [height, width];
17
+ }
18
+ // Collect the whole page as a display list (top-left coordinates), flip it to PDF
19
+ // coordinates at this one seam, then serialize once. Serializing registers the
20
+ // fonts/images used below, so it must run before the resource section.
21
+ const nodes = [];
22
+ for (const element of renderables) {
23
+ const renderer = RendererRegistry.getRenderer(element);
24
+ nodes.push(...(await renderer(element, objectManager)));
25
+ }
26
+ // Accessible tagging: one struct context per page (allocates its StructParents index), threaded into
27
+ // serialize so each drawable node is wrapped in marked content. Undefined = tagging off (byte-identical).
28
+ const structCtx = objectManager.struct.enabled ? objectManager.struct.beginPage() : undefined;
29
+ const flipped = PdfBackend.flipY(nodes, height);
30
+ const pageContent = PdfBackend.serialize(flipped, objectManager, structCtx);
31
+ // Add the page content as a new object (FlateDecode-compressed when enabled). The /Length is
32
+ // computed inside, with an explicit EOL before `endstream` (PDF/A clause 6.1.7.1).
33
+ const contentObjectNumber = objectManager.addContentStream(pageContent);
34
+ // Get the parent object number dynamically (linked with the page object)
35
+ const parentObjectNumber = objectManager.getParentObjectNumber(); // Get parent object number
36
+ // Page object with MediaBox
37
+ // - Get all fonts and add it to the page (reference)
38
+ objectManager.registerFont("Helvetica");
39
+ const fontReferences = [];
40
+ objectManager.getAllFontsRaw().forEach((value, _key) => {
41
+ const fontRef = `/F${value.fontIndex} ${value.resourceIndex} 0 R`;
42
+ fontReferences.push(fontRef);
43
+ });
44
+ // - Get all images and add it to the page (reference)
45
+ const imageReferences = [];
46
+ objectManager.getAllImagesRaw().forEach((value) => {
47
+ const imageRef = `/IM${value} ${value} 0 R`;
48
+ imageReferences.push(imageRef);
49
+ });
50
+ const imageCode = imageReferences.length > 0
51
+ ? "/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /XObject <<\n" +
52
+ imageReferences.join("\n") +
53
+ "\n>>\n"
54
+ : "";
55
+ // - Transparency (ExtGState) references, registered during serialize above
56
+ const extGStateReferences = [];
57
+ objectManager.getAllExtGStatesRaw().forEach((objectNumber, name) => {
58
+ extGStateReferences.push(`/${name} ${objectNumber} 0 R`);
59
+ });
60
+ const extGStateCode = extGStateReferences.length > 0
61
+ ? "/ExtGState <<\n" + extGStateReferences.join("\n") + "\n>>\n"
62
+ : "";
63
+ // - Gradient shadings (color-glyph fills), registered during serialize above
64
+ const shadingReferences = [];
65
+ objectManager.getAllShadingsRaw().forEach((objectNumber, name) => {
66
+ shadingReferences.push(`/${name} ${objectNumber} 0 R`);
67
+ });
68
+ const shadingCode = shadingReferences.length > 0 ? "/Shading <<\n" + shadingReferences.join("\n") + "\n>>\n" : "";
69
+ // Hyperlinks: a `Link` IR node drew nothing into the content stream - here its (already Y-flipped)
70
+ // rect + href become a /Link annotation object. `/Border [0 0 0]` hides the default visible frame;
71
+ // the URL is escaped like any PDF literal string. Refs are collected into the page's /Annots below.
72
+ const num = (n) => Number(n.toFixed(2));
73
+ const annotRefs = [];
74
+ for (const node of flipped) {
75
+ // A form field: build its Widget annotation + register it as an /AcroForm field (the logic lives in
76
+ // forms/acroform.ts), then reference it here in the page /Annots - the same side channel as a link.
77
+ if (node.type === "formfield") {
78
+ annotRefs.push(`${objectManager.acroform.addField(node, objectManager)} 0 R`);
79
+ continue;
31
80
  }
32
- // Collect the whole page as a display list (top-left coordinates), flip it to PDF
33
- // coordinates at this one seam, then serialize once. Serializing registers the
34
- // fonts/images used below, so it must run before the resource section.
35
- const nodes = [];
36
- for (const element of renderables) {
37
- const renderer = renderer_registry_1.RendererRegistry.getRenderer(element);
38
- if (renderer) {
39
- nodes.push(...(yield renderer(element, objectManager)));
40
- }
81
+ if (node.type !== "link")
82
+ continue;
83
+ const rect = `[${num(node.x)} ${num(node.y)} ${num(node.x + node.width)} ${num(node.y + node.height)}]`;
84
+ // Either an external URL (/URI) or an internal named destination (/GoTo, resolved via /Names /Dests).
85
+ // The Link IR guarantees exactly one is set; prefer `dest` when present.
86
+ const action = node.dest !== undefined
87
+ ? `/A << /S /GoTo /D ${objectManager.pdfString(node.dest)} >>`
88
+ : `/A << /S /URI /URI ${objectManager.pdfString(node.href ?? "")} >>`;
89
+ const annot = objectManager.addObject(`<< /Type /Annot /Subtype /Link /Rect ${rect} /Border [0 0 0] ${action} >>`);
90
+ annotRefs.push(`${annot} 0 R`);
91
+ }
92
+ const annotsCode = annotRefs.length > 0 ? ` /Annots [${annotRefs.join(" ")}]` : "";
93
+ // Tagging only: /StructParents links this page's marked content to the ParentTree, /Tabs /S makes the
94
+ // logical structure order the tab/reading order (a PDF/UA requirement).
95
+ const structAttrs = structCtx ? ` /StructParents ${structCtx.structParents} /Tabs /S` : "";
96
+ const pageObject = `<< /Type /Page /Parent ${parentObjectNumber} 0 R /Contents ${contentObjectNumber} 0 R /Resources <<\n/Font <<\n${fontReferences.join("\n")}\n>>\n${imageCode}${extGStateCode}${shadingCode}>>\n/MediaBox [0 0 ${width} ${height}]${structAttrs}${annotsCode} >>`;
97
+ // Add page as new object; register its object number with the struct tree (for /Pg refs), then return it.
98
+ const pageObjNum = objectManager.addObject(pageObject);
99
+ if (structCtx)
100
+ objectManager.struct.setPageObject(structCtx.structParents, pageObjNum);
101
+ // Bookmarks + named destinations: an `Outline`/`Anchor` IR node drew nothing; record it now that the
102
+ // page's object number is known. `node.y` is already Y-flipped to the page-space scroll target.
103
+ // PDFRenderer builds /Outlines and /Names /Dests at the end.
104
+ for (const node of flipped) {
105
+ if (node.type === "outline") {
106
+ objectManager.outline.add({
107
+ title: node.title,
108
+ level: node.level,
109
+ pageObjNum,
110
+ top: node.y,
111
+ });
41
112
  }
42
- const pageContent = pdf_backend_1.PdfBackend.serialize(pdf_backend_1.PdfBackend.flipY(nodes, height), objectManager);
43
- // Add the page content as a new object (FlateDecode-compressed when enabled). The /Length is
44
- // computed inside, with an explicit EOL before `endstream` (PDF/A clause 6.1.7.1).
45
- const contentObjectNumber = objectManager.addContentStream(pageContent);
46
- // Get the parent object number dynamically (linked with the page object)
47
- const parentObjectNumber = objectManager.getParentObjectNumber(); // Get parent object number
48
- // Page object with MediaBox
49
- // - Get all fonts and add it to the page (reference)
50
- objectManager.registerFont("Helvetica");
51
- const fontReferences = [];
52
- objectManager.getAllFontsRaw().forEach((value, _key) => {
53
- const fontRef = `/F${value.fontIndex} ${value.resourceIndex} 0 R`;
54
- fontReferences.push(fontRef);
55
- });
56
- // - Get all images and add it to the page (reference)
57
- const imageReferences = [];
58
- objectManager.getAllImagesRaw().forEach((value) => {
59
- const imageRef = `/IM${value} ${value} 0 R`;
60
- imageReferences.push(imageRef);
61
- });
62
- const imageCode = imageReferences.length > 0
63
- ? "/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /XObject <<\n" +
64
- imageReferences.join("\n") +
65
- "\n>>\n"
66
- : "";
67
- // - Transparency (ExtGState) references, registered during serialize above
68
- const extGStateReferences = [];
69
- objectManager.getAllExtGStatesRaw().forEach((objectNumber, name) => {
70
- extGStateReferences.push(`/${name} ${objectNumber} 0 R`);
71
- });
72
- const extGStateCode = extGStateReferences.length > 0
73
- ? "/ExtGState <<\n" + extGStateReferences.join("\n") + "\n>>\n"
74
- : "";
75
- const pageObject = `<< /Type /Page /Parent ${parentObjectNumber} 0 R /Contents ${contentObjectNumber} 0 R /Resources <<\n/Font <<\n${fontReferences.join("\n")}\n>>\n${imageCode}${extGStateCode}>>\n/MediaBox [0 0 ${width} ${height}] >>`;
76
- // Add page as new object and return the page number
77
- return objectManager.addObject(pageObject);
78
- });
113
+ else if (node.type === "anchor") {
114
+ objectManager.dests.add(node.name, { pageObjNum, top: node.y });
115
+ }
116
+ }
117
+ return pageObjNum;
79
118
  }
80
119
  }
81
- exports.PageRenderer = PageRenderer;
@@ -1,5 +1,6 @@
1
- import { IRNode } from "../ir/display-list";
2
- import { PDFObjectManager } from "../utils/pdf-object-manager";
1
+ import { IRNode } from "../ir/display-list.js";
2
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
3
+ import type { PageStructContext } from "../utils/struct-tree.js";
3
4
  /**
4
5
  * PDF backend - turns display-list primitives into content-stream operators.
5
6
  *
@@ -17,14 +18,34 @@ export declare class PdfBackend {
17
18
  * directly. (image is migrated in a later slice and still arrives pre-flipped.)
18
19
  */
19
20
  static flipY(nodes: IRNode[], pageHeight: number): IRNode[];
20
- /** Serialize a whole display list into one content stream (page-level entry point). */
21
- static serialize(nodes: IRNode[], om: PDFObjectManager): string;
21
+ /** Serialize a whole display list into one content stream (page-level entry point). When a
22
+ * `PageStructContext` is given (accessible tagging on), each drawable node is wrapped in a marked-content
23
+ * sequence (`/Role <</MCID n>> BDC … EMC`, or `/Artifact` when untagged); graphics-state and empty nodes
24
+ * pass through untouched, so untagged output stays byte-identical. */
25
+ /**
26
+ * Every number reaching the backend must be finite. A non-finite coordinate is a layout bug, but
27
+ * silence turns it into a corrupt PDF: `Infinity` is written into the operator stream verbatim, and a
28
+ * viewer then discards everything from that point on - including the footer, which is drawn last. That
29
+ * failure is invisible until somebody opens the file, so we refuse instead.
30
+ *
31
+ * Checks the node's numbers, not the serialized text: a document containing the WORD "Infinity" is
32
+ * perfectly legal and must not trip this.
33
+ */
34
+ private static assertFinite;
35
+ static serialize(nodes: IRNode[], om: PDFObjectManager, struct?: PageStructContext): string;
22
36
  /**
23
37
  * Escapes a string for a PDF literal string `( ... )`. The backslash must be doubled
24
38
  * first, then the parentheses that delimit the string. Without this, a ")" in the
25
39
  * text closes the string early and the remaining characters leak as raw operators.
26
40
  */
27
41
  static escapePdfString(text: string): string;
42
+ /**
43
+ * Builds the `[ ... ]` operand of a `TJ` from a run and its per-gap kern adjustments (em/1000, the
44
+ * sign the font declares - negative tightens). A `TJ` number moves the pen LEFT, so it is the
45
+ * NEGATED kern. Consecutive un-kerned glyphs stay in one encoded chunk, so `[(T) 40 (otal)]` rather
46
+ * than one chunk per glyph. `kerns[i]` is the adjustment AFTER code point `i`.
47
+ */
48
+ static kernedArray(text: string, kerns: number[], encode: (chunk: string) => string): string;
28
49
  /**
29
50
  * Returns the `/GSx gs` operator that selects a transparency state, or `""` when both
30
51
  * alphas are fully opaque. Opaque draws emit nothing here, so output stays
@@ -37,6 +58,12 @@ export declare class PdfBackend {
37
58
  * (kappa ≈ 0.5523). Returns m/l/c/h ops WITHOUT the paint operator.
38
59
  */
39
60
  private static roundedRectPath;
61
+ /**
62
+ * Clamp the four radii into the box. Each is capped at half the box, and two radii sharing an edge
63
+ * are scaled down together when they would overlap - the CSS rule, and what keeps the path from
64
+ * folding back on itself.
65
+ */
66
+ private static clampRadii;
40
67
  /**
41
68
  * Serialize a single display-list node to its content-stream operators.
42
69
  * `om` is used only by primitives that allocate PDF resources (images, fonts).