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

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 (139) hide show
  1. package/README.md +3 -3
  2. package/dist/api/args.d.ts +1 -1
  3. package/dist/api/args.js +2 -5
  4. package/dist/api/color.d.ts +4 -4
  5. package/dist/api/color.js +11 -17
  6. package/dist/api/content.d.ts +8 -8
  7. package/dist/api/content.js +23 -24
  8. package/dist/api/descriptor.d.ts +2 -2
  9. package/dist/api/descriptor.js +75 -31
  10. package/dist/api/index.d.ts +8 -8
  11. package/dist/api/index.js +8 -24
  12. package/dist/api/insets.js +4 -8
  13. package/dist/api/layout.d.ts +27 -12
  14. package/dist/api/layout.js +46 -45
  15. package/dist/api/structure.d.ts +60 -13
  16. package/dist/api/structure.js +132 -88
  17. package/dist/api/table.d.ts +5 -5
  18. package/dist/api/table.js +28 -24
  19. package/dist/api/text.d.ts +27 -2
  20. package/dist/api/text.js +45 -27
  21. package/dist/assets/font-data.d.ts +2 -0
  22. package/dist/assets/font-data.js +6 -0
  23. package/dist/assets/font-data.ts +7 -0
  24. package/dist/common/color.js +1 -5
  25. package/dist/constants/page-sizes.js +3 -6
  26. package/dist/constants/pdf-parts.js +1 -4
  27. package/dist/elements/container-element.d.ts +4 -4
  28. package/dist/elements/container-element.js +9 -13
  29. package/dist/elements/image-element.d.ts +18 -2
  30. package/dist/elements/image-element.js +81 -105
  31. package/dist/elements/index.d.ts +12 -10
  32. package/dist/elements/index.js +12 -28
  33. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  34. package/dist/elements/layout/default-text-style-element.js +47 -0
  35. package/dist/elements/layout/deferred-element.d.ts +3 -3
  36. package/dist/elements/layout/deferred-element.js +4 -8
  37. package/dist/elements/layout/expanded-element.d.ts +3 -3
  38. package/dist/elements/layout/expanded-element.js +10 -14
  39. package/dist/elements/layout/padding-element.d.ts +3 -3
  40. package/dist/elements/layout/padding-element.js +9 -14
  41. package/dist/elements/layout/positioned-element.d.ts +44 -0
  42. package/dist/elements/layout/positioned-element.js +61 -0
  43. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  44. package/dist/elements/layout/repeating-header-element.js +8 -12
  45. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  46. package/dist/elements/layout/sized-container-element.js +6 -11
  47. package/dist/elements/line-element.d.ts +3 -3
  48. package/dist/elements/line-element.js +5 -10
  49. package/dist/elements/page-element.d.ts +8 -6
  50. package/dist/elements/page-element.js +31 -23
  51. package/dist/elements/pdf-document-element.d.ts +10 -4
  52. package/dist/elements/pdf-document-element.js +11 -10
  53. package/dist/elements/pdf-element.d.ts +28 -3
  54. package/dist/elements/pdf-element.js +10 -19
  55. package/dist/elements/rectangle-element.d.ts +14 -6
  56. package/dist/elements/rectangle-element.js +44 -21
  57. package/dist/elements/row-element.d.ts +3 -3
  58. package/dist/elements/row-element.js +7 -11
  59. package/dist/elements/text-element.d.ts +37 -11
  60. package/dist/elements/text-element.js +64 -39
  61. package/dist/index.d.ts +3 -3
  62. package/dist/index.js +3 -19
  63. package/dist/ir/display-list.d.ts +22 -3
  64. package/dist/ir/display-list.js +1 -2
  65. package/dist/layout/box-constraints.js +2 -6
  66. package/dist/layout/fragmentation.d.ts +8 -1
  67. package/dist/layout/fragmentation.js +22 -10
  68. package/dist/platform/browser-fs.d.ts +2 -0
  69. package/dist/platform/browser-fs.js +9 -0
  70. package/dist/platform/browser-image.d.ts +5 -0
  71. package/dist/platform/browser-image.js +13 -0
  72. package/dist/platform/node-fs.d.ts +2 -0
  73. package/dist/platform/node-fs.js +10 -0
  74. package/dist/platform/node-image.d.ts +5 -0
  75. package/dist/platform/node-image.js +9 -0
  76. package/dist/renderer/container-renderer.d.ts +3 -3
  77. package/dist/renderer/container-renderer.js +12 -27
  78. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  79. package/dist/renderer/default-text-style-renderer.js +10 -0
  80. package/dist/renderer/deferred-renderer.d.ts +3 -3
  81. package/dist/renderer/deferred-renderer.js +8 -23
  82. package/dist/renderer/expanded-renderer.d.ts +3 -3
  83. package/dist/renderer/expanded-renderer.js +6 -21
  84. package/dist/renderer/image-renderer.d.ts +3 -3
  85. package/dist/renderer/image-renderer.js +77 -75
  86. package/dist/renderer/index.d.ts +10 -10
  87. package/dist/renderer/index.js +10 -26
  88. package/dist/renderer/line-renderer.d.ts +3 -3
  89. package/dist/renderer/line-renderer.js +13 -28
  90. package/dist/renderer/padding-renderer.d.ts +3 -3
  91. package/dist/renderer/padding-renderer.js +6 -21
  92. package/dist/renderer/page-renderer.d.ts +2 -2
  93. package/dist/renderer/page-renderer.js +61 -77
  94. package/dist/renderer/pdf-backend.d.ts +2 -2
  95. package/dist/renderer/pdf-backend.js +34 -17
  96. package/dist/renderer/pdf-config.js +4 -7
  97. package/dist/renderer/pdf-document-class.d.ts +5 -5
  98. package/dist/renderer/pdf-document-class.js +24 -41
  99. package/dist/renderer/pdf-document-renderer.d.ts +3 -3
  100. package/dist/renderer/pdf-document-renderer.js +71 -85
  101. package/dist/renderer/pdf-renderer.d.ts +2 -2
  102. package/dist/renderer/pdf-renderer.js +83 -90
  103. package/dist/renderer/positioned-renderer.d.ts +6 -0
  104. package/dist/renderer/positioned-renderer.js +10 -0
  105. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  106. package/dist/renderer/rectangle-renderer.js +45 -44
  107. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  108. package/dist/renderer/repeating-header-renderer.js +11 -26
  109. package/dist/renderer/row-renderer.d.ts +3 -3
  110. package/dist/renderer/row-renderer.js +12 -27
  111. package/dist/renderer/text-renderer.d.ts +6 -5
  112. package/dist/renderer/text-renderer.js +33 -42
  113. package/dist/text/line-breaker.d.ts +8 -5
  114. package/dist/text/line-breaker.js +67 -16
  115. package/dist/text/text-style.d.ts +25 -0
  116. package/dist/text/text-style.js +29 -0
  117. package/dist/utils/afm-parser.js +3 -13
  118. package/dist/utils/bytes.d.ts +24 -0
  119. package/dist/utils/bytes.js +76 -0
  120. package/dist/utils/flex-layout.d.ts +2 -2
  121. package/dist/utils/flex-layout.js +15 -20
  122. package/dist/utils/font-metrics.d.ts +1 -1
  123. package/dist/utils/font-metrics.js +1 -2
  124. package/dist/utils/font-path.js +3 -6
  125. package/dist/utils/image-helper.d.ts +6 -5
  126. package/dist/utils/image-helper.js +101 -111
  127. package/dist/utils/md5.d.ts +4 -0
  128. package/dist/utils/md5.js +80 -0
  129. package/dist/utils/pdf-object-manager.d.ts +10 -6
  130. package/dist/utils/pdf-object-manager.js +89 -94
  131. package/dist/utils/renderer-registry.js +1 -5
  132. package/dist/utils/ttf-parser.d.ts +2 -2
  133. package/dist/utils/ttf-parser.js +32 -36
  134. package/dist/utils/ttf-subsetter.d.ts +1 -1
  135. package/dist/utils/ttf-subsetter.js +40 -42
  136. package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
  137. package/dist/validators/element-validator.d.ts +2 -2
  138. package/dist/validators/element-validator.js +17 -23
  139. package/package.json +14 -2
@@ -1,43 +1,29 @@
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.PDFDocumentRenderer = void 0;
13
- const page_element_1 = require("../elements/page-element");
14
- const box_constraints_1 = require("../layout/box-constraints");
15
- const fragmentation_1 = require("../layout/fragmentation");
16
- const page_renderer_1 = require("./page-renderer");
17
- class PDFDocumentRenderer {
18
- static render(document, objectManager, ctx) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- const pageNumbers = [];
21
- // Add the pages object first... we need its object number (resources). The count is
22
- // a placeholder; it is replaced below with the real (post-pagination) page count.
23
- const pagesObject = `<< /Type /Pages /Kids [] /Count ${document.getProps().children.length} >>`;
24
- const pagesObjectNumber = objectManager.addObject(pagesObject);
25
- // Now set the given object number all its childs
26
- objectManager.setParentObjectNumber(pagesObjectNumber);
27
- // The page driver: each logical PageElement may produce SEVERAL physical PDF pages
28
- // when its content overflows (Slice 0: whole children reflow to the next page).
29
- for (let page of document.getProps().children) {
30
- const numbers = yield PDFDocumentRenderer.renderLogicalPage(page, objectManager, ctx);
31
- pageNumbers.push(...numbers);
32
- }
33
- // We must update the pages object with the real physical page numbers and count.
34
- const updatedPagesObject = `<< /Type /Pages /Kids [${pageNumbers
35
- .map((num) => `${num} 0 R`)
36
- .join(" ")}] /Count ${pageNumbers.length} >>`;
37
- // Now we must replace it in the object manager
38
- objectManager.replaceObject(pagesObjectNumber, updatedPagesObject);
39
- return pagesObjectNumber;
40
- });
1
+ import { layoutPageBands, PageElement } from "../elements/page-element.js";
2
+ import { BoxConstraints } from "../layout/box-constraints.js";
3
+ import { isFragmentable } from "../layout/fragmentation.js";
4
+ import { PageRenderer } from "./page-renderer.js";
5
+ export class PDFDocumentRenderer {
6
+ static async render(document, objectManager, ctx) {
7
+ const pageNumbers = [];
8
+ // Add the pages object first... we need its object number (resources). The count is
9
+ // a placeholder; it is replaced below with the real (post-pagination) page count.
10
+ const pagesObject = `<< /Type /Pages /Kids [] /Count ${document.getProps().children.length} >>`;
11
+ const pagesObjectNumber = objectManager.addObject(pagesObject);
12
+ // Now set the given object number all its childs
13
+ objectManager.setParentObjectNumber(pagesObjectNumber);
14
+ // The page driver: each logical PageElement may produce SEVERAL physical PDF pages
15
+ // when its content overflows (Slice 0: whole children reflow to the next page).
16
+ for (let page of document.getProps().children) {
17
+ const numbers = await PDFDocumentRenderer.renderLogicalPage(page, objectManager, ctx);
18
+ pageNumbers.push(...numbers);
19
+ }
20
+ // We must update the pages object with the real physical page numbers and count.
21
+ const updatedPagesObject = `<< /Type /Pages /Kids [${pageNumbers
22
+ .map((num) => `${num} 0 R`)
23
+ .join(" ")}] /Count ${pageNumbers.length} >>`;
24
+ // Now we must replace it in the object manager
25
+ objectManager.replaceObject(pagesObjectNumber, updatedPagesObject);
26
+ return pagesObjectNumber;
41
27
  }
42
28
  /**
43
29
  * Renders one logical page, paginating it into one or more physical pages.
@@ -46,59 +32,59 @@ class PDFDocumentRenderer {
46
32
  * fragmentation context (a Container). Anything else renders as a single page on the
47
33
  * unchanged path, so non-overflowing documents stay byte-identical to pre-Slice-0.
48
34
  */
49
- static renderLogicalPage(page, objectManager, ctx) {
50
- return __awaiter(this, void 0, void 0, function* () {
51
- const { children, config, header, footer } = page.getProps();
52
- if (children.length !== 1 || !(0, fragmentation_1.isFragmentable)(children[0])) {
53
- return [yield page_renderer_1.PageRenderer.render(page, objectManager)];
35
+ static async renderLogicalPage(page, objectManager, ctx) {
36
+ const { children, config, header, footer } = page.getProps();
37
+ if (children.length !== 1 || !isFragmentable(children[0])) {
38
+ return [await PageRenderer.render(page, objectManager)];
39
+ }
40
+ // Header/footer repeat on every physical page, so the body only ever flows into the
41
+ // band between them. Resolve that band once (config is already merged by pass 1).
42
+ const pageCtx = {
43
+ metrics: ctx.metrics,
44
+ pageConfig: config,
45
+ textStyle: ctx.textStyle,
46
+ onOverflow: ctx.onOverflow,
47
+ };
48
+ const { bodyWidth: width, bodyHeight: height } = layoutPageBands(config, header, footer, pageCtx);
49
+ const numbers = [];
50
+ let region = children[0];
51
+ let isFirstRegion = true;
52
+ while (region) {
53
+ if (!isFragmentable(region)) {
54
+ // A non-fragmentable remainder is placed whole on its own page.
55
+ numbers.push(await PDFDocumentRenderer.renderPhysicalPage(config, region, header, footer, objectManager, ctx));
56
+ break;
54
57
  }
55
- // Header/footer repeat on every physical page, so the body only ever flows into the
56
- // band between them. Resolve that band once (config is already merged by pass 1).
57
- const pageCtx = { metrics: ctx.metrics, pageConfig: config };
58
- const { bodyWidth: width, bodyHeight: height } = (0, page_element_1.layoutPageBands)(config, header, footer, pageCtx);
59
- const numbers = [];
60
- let region = children[0];
61
- let isFirstRegion = true;
62
- while (region) {
63
- if (!(0, fragmentation_1.isFragmentable)(region)) {
64
- // A non-fragmentable remainder is placed whole on its own page.
65
- numbers.push(yield PDFDocumentRenderer.renderPhysicalPage(config, region, header, footer, objectManager, ctx));
66
- break;
67
- }
68
- const { fitted, remainder } = region.fragment(height, width, ctx);
69
- // Everything fits on one page: render the ORIGINAL page so output is unchanged.
70
- // Measuring inside fragment() laid the children out at the origin to size them, so
71
- // re-run the page layout first to restore their real positions (deterministic).
72
- if (isFirstRegion && remainder === null) {
73
- page.calculateLayout(new box_constraints_1.BoxConstraints(), { x: 0, y: 0 }, ctx);
74
- numbers.push(yield page_renderer_1.PageRenderer.render(page, objectManager));
75
- break;
76
- }
77
- if (fitted) {
78
- numbers.push(yield PDFDocumentRenderer.renderPhysicalPage(config, fitted, header, footer, objectManager, ctx));
79
- }
80
- region = remainder;
81
- isFirstRegion = false;
58
+ const { fitted, remainder } = region.fragment(height, width, ctx);
59
+ // Everything fits on one page: render the ORIGINAL page so output is unchanged.
60
+ // Measuring inside fragment() laid the children out at the origin to size them, so
61
+ // re-run the page layout first to restore their real positions (deterministic).
62
+ if (isFirstRegion && remainder === null) {
63
+ page.calculateLayout(new BoxConstraints(), { x: 0, y: 0 }, ctx);
64
+ numbers.push(await PageRenderer.render(page, objectManager));
65
+ break;
82
66
  }
83
- return numbers;
84
- });
67
+ if (fitted) {
68
+ numbers.push(await PDFDocumentRenderer.renderPhysicalPage(config, fitted, header, footer, objectManager, ctx));
69
+ }
70
+ region = remainder;
71
+ isFirstRegion = false;
72
+ }
73
+ return numbers;
85
74
  }
86
75
  /**
87
76
  * Lays out one fragment on a fresh page of the same geometry and renders it. The
88
77
  * header/footer are attached to every physical page so they repeat; `PageElement`
89
78
  * re-places them and the body in the band between.
90
79
  */
91
- static renderPhysicalPage(config, content, header, footer, objectManager, ctx) {
92
- return __awaiter(this, void 0, void 0, function* () {
93
- const physicalPage = new page_element_1.PageElement({
94
- config,
95
- header,
96
- footer,
97
- children: [content],
98
- });
99
- physicalPage.calculateLayout(new box_constraints_1.BoxConstraints(), { x: 0, y: 0 }, ctx);
100
- return page_renderer_1.PageRenderer.render(physicalPage, objectManager);
80
+ static async renderPhysicalPage(config, content, header, footer, objectManager, ctx) {
81
+ const physicalPage = new PageElement({
82
+ config,
83
+ header,
84
+ footer,
85
+ children: [content],
101
86
  });
87
+ physicalPage.calculateLayout(new BoxConstraints(), { x: 0, y: 0 }, ctx);
88
+ return PageRenderer.render(physicalPage, objectManager);
102
89
  }
103
90
  }
104
- exports.PDFDocumentRenderer = PDFDocumentRenderer;
@@ -1,5 +1,5 @@
1
- import { PDFDocumentElement } from "../elements/pdf-document-element";
2
- import { PDFObjectManager } from "../utils/pdf-object-manager";
1
+ import { PDFDocumentElement } from "../elements/pdf-document-element.js";
2
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
3
3
  export declare class PDFRenderer {
4
4
  static render(document: PDFDocumentElement, objectManager: PDFObjectManager): Promise<string>;
5
5
  }
@@ -1,92 +1,85 @@
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.PDFRenderer = void 0;
13
- const pdf_document_renderer_1 = require("./pdf-document-renderer");
14
- const renderer_registry_1 = require("../utils/renderer-registry");
15
- const elements_1 = require("../elements");
16
- const text_renderer_1 = require("./text-renderer");
17
- const container_element_1 = require("../elements/container-element");
18
- const rectangle_element_1 = require("../elements/rectangle-element");
19
- const row_element_1 = require("../elements/row-element");
20
- const container_renderer_1 = require("./container-renderer");
21
- const rectangle_renderer_1 = require("./rectangle-renderer");
22
- const row_renderer_1 = require("./row-renderer");
23
- const expanded_renderer_1 = require("./expanded-renderer");
24
- const padding_renderer_1 = require("./padding-renderer");
25
- const image_renderer_1 = require("./image-renderer");
26
- const line_renderer_1 = require("./line-renderer");
27
- const repeating_header_element_1 = require("../elements/layout/repeating-header-element");
28
- const repeating_header_renderer_1 = require("./repeating-header-renderer");
29
- const deferred_element_1 = require("../elements/layout/deferred-element");
30
- const deferred_renderer_1 = require("./deferred-renderer");
31
- const box_constraints_1 = require("../layout/box-constraints");
32
- class PDFRenderer {
33
- static render(document, objectManager) {
34
- return __awaiter(this, void 0, void 0, function* () {
35
- // Register all Renderer
36
- renderer_registry_1.RendererRegistry.register(elements_1.TextElement, text_renderer_1.TextRenderer.render);
37
- renderer_registry_1.RendererRegistry.register(container_element_1.ContainerElement, container_renderer_1.ContainerRenderer.render);
38
- renderer_registry_1.RendererRegistry.register(row_element_1.RowElement, row_renderer_1.RowRenderer.render);
39
- renderer_registry_1.RendererRegistry.register(rectangle_element_1.RectangleElement, rectangle_renderer_1.RectangleRenderer.render);
40
- renderer_registry_1.RendererRegistry.register(elements_1.ExpandedElement, expanded_renderer_1.ExpandedRenderer.render);
41
- renderer_registry_1.RendererRegistry.register(elements_1.PaddingElement, padding_renderer_1.PaddingRenderer.render);
42
- renderer_registry_1.RendererRegistry.register(elements_1.ImageElement, image_renderer_1.ImageRenderer.render);
43
- renderer_registry_1.RendererRegistry.register(elements_1.LineElement, line_renderer_1.LineRenderer.render);
44
- renderer_registry_1.RendererRegistry.register(repeating_header_element_1.RepeatingHeaderElement, repeating_header_renderer_1.RepeatingHeaderRenderer.render);
45
- renderer_registry_1.RendererRegistry.register(deferred_element_1.DeferredElement, deferred_renderer_1.DeferredRenderer.render);
46
- let pdfContent = "";
47
- // Header: version line + the PDF/A binary marker (the object manager owns it so its length
48
- // matches the xref offset calculation).
49
- pdfContent += objectManager.getHeader();
50
- // Layout pass: thread the context explicitly. The seed page config is the document
51
- // default; each PageElement overrides it for its own subtree.
52
- const ctx = {
53
- metrics: objectManager,
54
- pageConfig: objectManager.getPDFConfig(),
55
- };
56
- document.calculateLayout(new box_constraints_1.BoxConstraints(), { x: 0, y: 0 }, ctx);
57
- // Render pages and contents (the driver paginates overflowing pages).
58
- yield pdf_document_renderer_1.PDFDocumentRenderer.render(document, objectManager, ctx);
59
- // Add the catalog. XMP metadata (/Metadata) and embedded files (/AF + /Names/EmbeddedFiles)
60
- // are added only when present; with neither, the catalog is byte-identical to before.
61
- const catalogParts = [`/Type /Catalog /Pages ${objectManager.getParentObjectNumber()} 0 R`];
62
- const xmp = objectManager.getXmpMetadata();
63
- if (xmp) {
64
- const metadataObject = objectManager.addObject(`<< /Type /Metadata /Subtype /XML /Length ${xmp.length} >>\nstream\n${xmp}\nendstream`);
65
- catalogParts.push(`/Metadata ${metadataObject} 0 R`);
66
- }
67
- const outputIntent = objectManager.getOutputIntent();
68
- if (outputIntent) {
69
- catalogParts.push(`/OutputIntents [${outputIntent} 0 R]`);
70
- }
71
- const attachments = objectManager.getAttachments();
72
- if (attachments.length > 0) {
73
- const names = attachments.map((a) => `(${a.name}) ${a.filespec} 0 R`).join(" ");
74
- const af = attachments.map((a) => `${a.filespec} 0 R`).join(" ");
75
- catalogParts.push(`/AF [${af}]`, `/Names << /EmbeddedFiles << /Names [${names}] >> >>`);
76
- }
77
- const catalogObject = `<< ${catalogParts.join(" ")} >>`;
78
- objectManager.addObject(catalogObject);
79
- // Now that the render pass has revealed which glyphs each embedded font uses, fill the reserved
80
- // font objects with the subset font program (must happen before the objects are serialized).
81
- objectManager.finalizeCustomFonts();
82
- // Add rendered objects
83
- pdfContent += objectManager.getRenderedObjects();
84
- // Add XRef table and trailer
85
- const startxref = pdfContent.length;
86
- pdfContent += objectManager.getXRefTable();
87
- pdfContent += objectManager.getTrailerAndXRef(startxref);
88
- return pdfContent;
89
- });
1
+ import { PDFDocumentRenderer } from "./pdf-document-renderer.js";
2
+ import { RendererRegistry } from "../utils/renderer-registry.js";
3
+ import { DefaultTextStyleElement, ExpandedElement, ImageElement, LineElement, PaddingElement, TextElement, } from "../elements/index.js";
4
+ import { TextRenderer } from "./text-renderer.js";
5
+ import { ContainerElement } from "../elements/container-element.js";
6
+ import { RectangleElement } from "../elements/rectangle-element.js";
7
+ import { RowElement } from "../elements/row-element.js";
8
+ import { ContainerRenderer } from "./container-renderer.js";
9
+ import { RectangleRenderer } from "./rectangle-renderer.js";
10
+ import { RowRenderer } from "./row-renderer.js";
11
+ import { ExpandedRenderer } from "./expanded-renderer.js";
12
+ import { PaddingRenderer } from "./padding-renderer.js";
13
+ import { DefaultTextStyleRenderer } from "./default-text-style-renderer.js";
14
+ import { ImageRenderer } from "./image-renderer.js";
15
+ import { LineRenderer } from "./line-renderer.js";
16
+ import { RepeatingHeaderElement } from "../elements/layout/repeating-header-element.js";
17
+ import { RepeatingHeaderRenderer } from "./repeating-header-renderer.js";
18
+ import { DeferredElement } from "../elements/layout/deferred-element.js";
19
+ import { DeferredRenderer } from "./deferred-renderer.js";
20
+ import { PositionedElement } from "../elements/layout/positioned-element.js";
21
+ import { PositionedRenderer } from "./positioned-renderer.js";
22
+ import { BoxConstraints } from "../layout/box-constraints.js";
23
+ import { DEFAULT_TEXT_STYLE, mergeTextStyle } from "../text/text-style.js";
24
+ export class PDFRenderer {
25
+ static async render(document, objectManager) {
26
+ // Register all Renderer
27
+ RendererRegistry.register(TextElement, TextRenderer.render);
28
+ RendererRegistry.register(ContainerElement, ContainerRenderer.render);
29
+ RendererRegistry.register(RowElement, RowRenderer.render);
30
+ RendererRegistry.register(RectangleElement, RectangleRenderer.render);
31
+ RendererRegistry.register(ExpandedElement, ExpandedRenderer.render);
32
+ RendererRegistry.register(PaddingElement, PaddingRenderer.render);
33
+ RendererRegistry.register(DefaultTextStyleElement, DefaultTextStyleRenderer.render);
34
+ RendererRegistry.register(ImageElement, ImageRenderer.render);
35
+ RendererRegistry.register(LineElement, LineRenderer.render);
36
+ RendererRegistry.register(RepeatingHeaderElement, RepeatingHeaderRenderer.render);
37
+ RendererRegistry.register(DeferredElement, DeferredRenderer.render);
38
+ RendererRegistry.register(PositionedElement, PositionedRenderer.render);
39
+ let pdfContent = "";
40
+ // Header: version line + the PDF/A binary marker (the object manager owns it so its length
41
+ // matches the xref offset calculation).
42
+ pdfContent += objectManager.getHeader();
43
+ // Layout pass: thread the context explicitly. The seed page config is the document
44
+ // default; each PageElement overrides it for its own subtree.
45
+ const ctx = {
46
+ metrics: objectManager,
47
+ pageConfig: objectManager.getPDFConfig(),
48
+ textStyle: mergeTextStyle(DEFAULT_TEXT_STYLE, document.getDefaultTextStyle()),
49
+ onOverflow: objectManager.getOverflowPolicy(),
50
+ };
51
+ document.calculateLayout(new BoxConstraints(), { x: 0, y: 0 }, ctx);
52
+ // Render pages and contents (the driver paginates overflowing pages).
53
+ await PDFDocumentRenderer.render(document, objectManager, ctx);
54
+ // Add the catalog. XMP metadata (/Metadata) and embedded files (/AF + /Names/EmbeddedFiles)
55
+ // are added only when present; with neither, the catalog is byte-identical to before.
56
+ const catalogParts = [`/Type /Catalog /Pages ${objectManager.getParentObjectNumber()} 0 R`];
57
+ const xmp = objectManager.getXmpMetadata();
58
+ if (xmp) {
59
+ const metadataObject = objectManager.addObject(`<< /Type /Metadata /Subtype /XML /Length ${xmp.length} >>\nstream\n${xmp}\nendstream`);
60
+ catalogParts.push(`/Metadata ${metadataObject} 0 R`);
61
+ }
62
+ const outputIntent = objectManager.getOutputIntent();
63
+ if (outputIntent) {
64
+ catalogParts.push(`/OutputIntents [${outputIntent} 0 R]`);
65
+ }
66
+ const attachments = objectManager.getAttachments();
67
+ if (attachments.length > 0) {
68
+ const names = attachments.map((a) => `(${a.name}) ${a.filespec} 0 R`).join(" ");
69
+ const af = attachments.map((a) => `${a.filespec} 0 R`).join(" ");
70
+ catalogParts.push(`/AF [${af}]`, `/Names << /EmbeddedFiles << /Names [${names}] >> >>`);
71
+ }
72
+ const catalogObject = `<< ${catalogParts.join(" ")} >>`;
73
+ objectManager.addObject(catalogObject);
74
+ // Now that the render pass has revealed which glyphs each embedded font uses, fill the reserved
75
+ // font objects with the subset font program (must happen before the objects are serialized).
76
+ objectManager.finalizeCustomFonts();
77
+ // Add rendered objects
78
+ pdfContent += objectManager.getRenderedObjects();
79
+ // Add XRef table and trailer
80
+ const startxref = pdfContent.length;
81
+ pdfContent += objectManager.getXRefTable();
82
+ pdfContent += objectManager.getTrailerAndXRef(startxref);
83
+ return pdfContent;
90
84
  }
91
85
  }
92
- exports.PDFRenderer = PDFRenderer;
@@ -0,0 +1,6 @@
1
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
2
+ import { PositionedElement } from "../elements/layout/positioned-element.js";
3
+ import { IRNode } from "../ir/display-list.js";
4
+ export declare class PositionedRenderer {
5
+ static render(positionedElement: PositionedElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
6
+ }
@@ -0,0 +1,10 @@
1
+ import { RendererRegistry } from "../utils/renderer-registry.js";
2
+ export class PositionedRenderer {
3
+ static async render(positionedElement, objectManager) {
4
+ // The child was already placed (by the frame) during layout; just emit its IR. It is drawn
5
+ // after the frame's flow content, so it paints on top.
6
+ const { child } = positionedElement.getProps();
7
+ const renderer = RendererRegistry.getRenderer(child);
8
+ return renderer ? renderer(child, objectManager) : [];
9
+ }
10
+ }
@@ -1,6 +1,6 @@
1
- import { PDFObjectManager } from "../utils/pdf-object-manager";
2
- import { RectangleElement } from "../elements/rectangle-element";
3
- import { IRNode } from "../ir/display-list";
1
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
2
+ import { RectangleElement } from "../elements/rectangle-element.js";
3
+ import { IRNode } from "../ir/display-list.js";
4
4
  export declare class RectangleRenderer {
5
5
  static render(rectangleElement: RectangleElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
6
6
  /** One `line` node per present side, along the box edges (top-left coordinates). */
@@ -1,48 +1,50 @@
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.RectangleRenderer = void 0;
13
- const renderer_registry_1 = require("../utils/renderer-registry");
14
- class RectangleRenderer {
15
- static render(rectangleElement, objectManager) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const { x, y, width, height, children, color, backgroundColor, borderWidth, radius, sideBorders, } = rectangleElement.getProps();
18
- const h = height;
19
- const nodes = [];
20
- if (sideBorders) {
21
- // Per-side borders: a fill-only box (no stroke), then a line per present side
22
- // (sharp corners). This is what lets cells draw grid lines.
23
- if (backgroundColor) {
24
- nodes.push({ type: "rect", x, y, width, height: h, strokeWidth: 0, fill: backgroundColor });
25
- }
26
- nodes.push(...RectangleRenderer.sideLines(x, y, width, h, borderWidth, sideBorders));
27
- }
28
- else {
29
- // The box itself becomes a display-list primitive. A background means a filled box;
30
- // otherwise it is stroked only. (Unchanged path - byte-identical.)
31
- const node = Object.assign(Object.assign({ type: "rect", x,
32
- y,
33
- width, height: h, stroke: color, strokeWidth: borderWidth }, (backgroundColor ? { fill: backgroundColor } : {})), (radius ? { radius } : {}));
34
- nodes.push(node);
1
+ import { RendererRegistry } from "../utils/renderer-registry.js";
2
+ export class RectangleRenderer {
3
+ static async render(rectangleElement, objectManager) {
4
+ const { x, y, width, height, children, color, backgroundColor, borderWidth, radius, sideBorders, overflow, } = rectangleElement.getProps();
5
+ const h = height;
6
+ const nodes = [];
7
+ if (sideBorders) {
8
+ // Per-side borders: a fill-only box (no stroke), then a line per present side
9
+ // (sharp corners). This is what lets cells draw grid lines.
10
+ if (backgroundColor) {
11
+ nodes.push({ type: "rect", x, y, width, height: h, strokeWidth: 0, fill: backgroundColor });
35
12
  }
36
- // Children follow the box (Rectangle is also a container).
37
- if (children)
38
- for (const child of children) {
39
- const renderer = renderer_registry_1.RendererRegistry.getRenderer(child);
40
- if (renderer) {
41
- nodes.push(...(yield renderer(child, objectManager)));
42
- }
13
+ nodes.push(...RectangleRenderer.sideLines(x, y, width, h, borderWidth, sideBorders));
14
+ }
15
+ else {
16
+ // The box itself becomes a display-list primitive. A background means a filled box;
17
+ // otherwise it is stroked only. (Unchanged path - byte-identical.)
18
+ const node = {
19
+ type: "rect",
20
+ x,
21
+ y,
22
+ width,
23
+ height: h,
24
+ stroke: color,
25
+ strokeWidth: borderWidth,
26
+ ...(backgroundColor ? { fill: backgroundColor } : {}),
27
+ ...(radius ? { radius } : {}),
28
+ };
29
+ nodes.push(node);
30
+ }
31
+ // Children follow the box (Rectangle is also a container). With overflow: "hidden" they are
32
+ // wrapped in a clip to the (rounded) box rect, so a Positioned child is cropped at the edge
33
+ // instead of spilling over. Default "visible" emits no clip - byte-identical.
34
+ const clip = overflow === "hidden";
35
+ if (clip) {
36
+ nodes.push({ type: "clip-push", x, y, width, height: h, ...(radius ? { radius } : {}) });
37
+ }
38
+ if (children)
39
+ for (const child of children) {
40
+ const renderer = RendererRegistry.getRenderer(child);
41
+ if (renderer) {
42
+ nodes.push(...(await renderer(child, objectManager)));
43
43
  }
44
- return nodes;
45
- });
44
+ }
45
+ if (clip)
46
+ nodes.push({ type: "clip-pop" });
47
+ return nodes;
46
48
  }
47
49
  /** One `line` node per present side, along the box edges (top-left coordinates). */
48
50
  static sideLines(x, y, width, height, strokeWidth, sides) {
@@ -58,4 +60,3 @@ class RectangleRenderer {
58
60
  return lines;
59
61
  }
60
62
  }
61
- exports.RectangleRenderer = RectangleRenderer;
@@ -1,6 +1,6 @@
1
- import { PDFObjectManager } from "../utils/pdf-object-manager";
2
- import { RepeatingHeaderElement } from "../elements/layout/repeating-header-element";
3
- import { IRNode } from "../ir/display-list";
1
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
2
+ import { RepeatingHeaderElement } from "../elements/layout/repeating-header-element.js";
3
+ import { IRNode } from "../ir/display-list.js";
4
4
  export declare class RepeatingHeaderRenderer {
5
5
  static render(element: RepeatingHeaderElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
6
6
  }
@@ -1,28 +1,13 @@
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.RepeatingHeaderRenderer = void 0;
13
- const renderer_registry_1 = require("../utils/renderer-registry");
14
- class RepeatingHeaderRenderer {
15
- static render(element, objectManager) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const { header, body } = element.getProps();
18
- const nodes = [];
19
- for (const child of [header, body]) {
20
- const renderer = renderer_registry_1.RendererRegistry.getRenderer(child);
21
- if (renderer)
22
- nodes.push(...(yield renderer(child, objectManager)));
23
- }
24
- return nodes;
25
- });
1
+ import { RendererRegistry } from "../utils/renderer-registry.js";
2
+ export class RepeatingHeaderRenderer {
3
+ static async render(element, objectManager) {
4
+ const { header, body } = element.getProps();
5
+ const nodes = [];
6
+ for (const child of [header, body]) {
7
+ const renderer = RendererRegistry.getRenderer(child);
8
+ if (renderer)
9
+ nodes.push(...(await renderer(child, objectManager)));
10
+ }
11
+ return nodes;
26
12
  }
27
13
  }
28
- exports.RepeatingHeaderRenderer = RepeatingHeaderRenderer;
@@ -1,6 +1,6 @@
1
- import { PDFObjectManager } from "../utils/pdf-object-manager";
2
- import { RowElement } from "../elements/row-element";
3
- import { IRNode } from "../ir/display-list";
1
+ import { PDFObjectManager } from "../utils/pdf-object-manager.js";
2
+ import { RowElement } from "../elements/row-element.js";
3
+ import { IRNode } from "../ir/display-list.js";
4
4
  export declare class RowRenderer {
5
5
  static render(rowElement: RowElement, objectManager: PDFObjectManager): Promise<IRNode[]>;
6
6
  }
@@ -1,30 +1,15 @@
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.RowRenderer = void 0;
13
- const renderer_registry_1 = require("../utils/renderer-registry");
14
- class RowRenderer {
15
- static render(rowElement, objectManager) {
16
- return __awaiter(this, void 0, void 0, function* () {
17
- const { children } = rowElement.getProps();
18
- const nodes = [];
19
- if (children)
20
- for (const child of children) {
21
- const renderer = renderer_registry_1.RendererRegistry.getRenderer(child);
22
- if (renderer) {
23
- nodes.push(...(yield renderer(child, objectManager)));
24
- }
1
+ import { RendererRegistry } from "../utils/renderer-registry.js";
2
+ export class RowRenderer {
3
+ static async render(rowElement, objectManager) {
4
+ const { children } = rowElement.getProps();
5
+ const nodes = [];
6
+ if (children)
7
+ for (const child of children) {
8
+ const renderer = RendererRegistry.getRenderer(child);
9
+ if (renderer) {
10
+ nodes.push(...(await renderer(child, objectManager)));
25
11
  }
26
- return nodes;
27
- });
12
+ }
13
+ return nodes;
28
14
  }
29
15
  }
30
- exports.RowRenderer = RowRenderer;