postext-pdf 0.1.0

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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/__bench__/render.bench.test.d.ts +2 -0
  4. package/dist/__bench__/render.bench.test.d.ts.map +1 -0
  5. package/dist/__bench__/render.bench.test.js +86 -0
  6. package/dist/__bench__/render.bench.test.js.map +1 -0
  7. package/dist/__tests__/accessibility.test.d.ts +2 -0
  8. package/dist/__tests__/accessibility.test.d.ts.map +1 -0
  9. package/dist/__tests__/accessibility.test.js +364 -0
  10. package/dist/__tests__/accessibility.test.js.map +1 -0
  11. package/dist/__tests__/contentsLinks.test.d.ts +2 -0
  12. package/dist/__tests__/contentsLinks.test.d.ts.map +1 -0
  13. package/dist/__tests__/contentsLinks.test.js +131 -0
  14. package/dist/__tests__/contentsLinks.test.js.map +1 -0
  15. package/dist/__tests__/fontCache.test.d.ts +2 -0
  16. package/dist/__tests__/fontCache.test.d.ts.map +1 -0
  17. package/dist/__tests__/fontCache.test.js +42 -0
  18. package/dist/__tests__/fontCache.test.js.map +1 -0
  19. package/dist/__tests__/headerFooter.test.d.ts +2 -0
  20. package/dist/__tests__/headerFooter.test.d.ts.map +1 -0
  21. package/dist/__tests__/headerFooter.test.js +68 -0
  22. package/dist/__tests__/headerFooter.test.js.map +1 -0
  23. package/dist/__tests__/rotatedTable.test.d.ts +2 -0
  24. package/dist/__tests__/rotatedTable.test.d.ts.map +1 -0
  25. package/dist/__tests__/rotatedTable.test.js +112 -0
  26. package/dist/__tests__/rotatedTable.test.js.map +1 -0
  27. package/dist/__tests__/svgVector.test.d.ts +2 -0
  28. package/dist/__tests__/svgVector.test.d.ts.map +1 -0
  29. package/dist/__tests__/svgVector.test.js +322 -0
  30. package/dist/__tests__/svgVector.test.js.map +1 -0
  31. package/dist/__tests__/toUnicode.test.d.ts +2 -0
  32. package/dist/__tests__/toUnicode.test.d.ts.map +1 -0
  33. package/dist/__tests__/toUnicode.test.js +57 -0
  34. package/dist/__tests__/toUnicode.test.js.map +1 -0
  35. package/dist/colors.d.ts +23 -0
  36. package/dist/colors.d.ts.map +1 -0
  37. package/dist/colors.js +47 -0
  38. package/dist/colors.js.map +1 -0
  39. package/dist/fontCache.d.ts +41 -0
  40. package/dist/fontCache.d.ts.map +1 -0
  41. package/dist/fontCache.js +154 -0
  42. package/dist/fontCache.js.map +1 -0
  43. package/dist/fontString.d.ts +14 -0
  44. package/dist/fontString.d.ts.map +1 -0
  45. package/dist/fontString.js +43 -0
  46. package/dist/fontString.js.map +1 -0
  47. package/dist/index.d.ts +6 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +5 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/pdf-backend/blockRender.d.ts +15 -0
  52. package/dist/pdf-backend/blockRender.d.ts.map +1 -0
  53. package/dist/pdf-backend/blockRender.js +244 -0
  54. package/dist/pdf-backend/blockRender.js.map +1 -0
  55. package/dist/pdf-backend/fontHelpers.d.ts +6 -0
  56. package/dist/pdf-backend/fontHelpers.d.ts.map +1 -0
  57. package/dist/pdf-backend/fontHelpers.js +81 -0
  58. package/dist/pdf-backend/fontHelpers.js.map +1 -0
  59. package/dist/pdf-backend/headerFooter.d.ts +15 -0
  60. package/dist/pdf-backend/headerFooter.d.ts.map +1 -0
  61. package/dist/pdf-backend/headerFooter.js +145 -0
  62. package/dist/pdf-backend/headerFooter.js.map +1 -0
  63. package/dist/pdf-backend/index.d.ts +47 -0
  64. package/dist/pdf-backend/index.d.ts.map +1 -0
  65. package/dist/pdf-backend/index.js +227 -0
  66. package/dist/pdf-backend/index.js.map +1 -0
  67. package/dist/pdf-backend/links.d.ts +44 -0
  68. package/dist/pdf-backend/links.d.ts.map +1 -0
  69. package/dist/pdf-backend/links.js +110 -0
  70. package/dist/pdf-backend/links.js.map +1 -0
  71. package/dist/pdf-backend/outlines.d.ts +8 -0
  72. package/dist/pdf-backend/outlines.d.ts.map +1 -0
  73. package/dist/pdf-backend/outlines.js +145 -0
  74. package/dist/pdf-backend/outlines.js.map +1 -0
  75. package/dist/pdf-backend/pageDecorations.d.ts +13 -0
  76. package/dist/pdf-backend/pageDecorations.d.ts.map +1 -0
  77. package/dist/pdf-backend/pageDecorations.js +88 -0
  78. package/dist/pdf-backend/pageDecorations.js.map +1 -0
  79. package/dist/pdf-backend/pageLabels.d.ts +8 -0
  80. package/dist/pdf-backend/pageLabels.d.ts.map +1 -0
  81. package/dist/pdf-backend/pageLabels.js +61 -0
  82. package/dist/pdf-backend/pageLabels.js.map +1 -0
  83. package/dist/pdf-backend/primitives.d.ts +46 -0
  84. package/dist/pdf-backend/primitives.d.ts.map +1 -0
  85. package/dist/pdf-backend/primitives.js +162 -0
  86. package/dist/pdf-backend/primitives.js.map +1 -0
  87. package/dist/pdf-backend/renderResourceBlock.d.ts +87 -0
  88. package/dist/pdf-backend/renderResourceBlock.d.ts.map +1 -0
  89. package/dist/pdf-backend/renderResourceBlock.js +753 -0
  90. package/dist/pdf-backend/renderResourceBlock.js.map +1 -0
  91. package/dist/pdf-backend/structureFlow.d.ts +55 -0
  92. package/dist/pdf-backend/structureFlow.d.ts.map +1 -0
  93. package/dist/pdf-backend/structureFlow.js +180 -0
  94. package/dist/pdf-backend/structureFlow.js.map +1 -0
  95. package/dist/pdf-backend/svgVector.d.ts +144 -0
  96. package/dist/pdf-backend/svgVector.d.ts.map +1 -0
  97. package/dist/pdf-backend/svgVector.js +1455 -0
  98. package/dist/pdf-backend/svgVector.js.map +1 -0
  99. package/dist/pdf-backend/tagging.d.ts +136 -0
  100. package/dist/pdf-backend/tagging.d.ts.map +1 -0
  101. package/dist/pdf-backend/tagging.js +296 -0
  102. package/dist/pdf-backend/tagging.js.map +1 -0
  103. package/dist/woff2.d.ts +11 -0
  104. package/dist/woff2.d.ts.map +1 -0
  105. package/dist/woff2.js +47 -0
  106. package/dist/woff2.js.map +1 -0
  107. package/dist/worker/client.d.ts +30 -0
  108. package/dist/worker/client.d.ts.map +1 -0
  109. package/dist/worker/client.js +112 -0
  110. package/dist/worker/client.js.map +1 -0
  111. package/dist/worker/pdf.worker.d.ts +2 -0
  112. package/dist/worker/pdf.worker.d.ts.map +1 -0
  113. package/dist/worker/pdf.worker.js +67 -0
  114. package/dist/worker/pdf.worker.js.map +1 -0
  115. package/dist/worker/protocol.d.ts +49 -0
  116. package/dist/worker/protocol.d.ts.map +1 -0
  117. package/dist/worker/protocol.js +2 -0
  118. package/dist/worker/protocol.js.map +1 -0
  119. package/package.json +67 -0
@@ -0,0 +1,154 @@
1
+ import { fontKey, parseFontString } from './fontString';
2
+ /** True when `bytes` starts with the `OTTO` magic identifying a CFF-flavored
3
+ * OpenType font — the ones pdf-lib cannot subset reliably, so they embed
4
+ * whole (see `preloadFontStrings`). */
5
+ function isCffOpenType(bytes) {
6
+ return (bytes.length >= 4 &&
7
+ bytes[0] === 0x4f && // O
8
+ bytes[1] === 0x54 && // T
9
+ bytes[2] === 0x54 && // T
10
+ bytes[3] === 0x4f // O
11
+ );
12
+ }
13
+ /** pdf-lib builds a CID font's `W` (advance widths) array from the glyphs
14
+ * reachable through the cmap, so a face embedded whole leaves every
15
+ * GSUB-only glyph — the fi/fl ligatures, contextual alternates — at the
16
+ * default 1000-unit advance, and viewers draw "refl eja" with a gap after
17
+ * the ligature (or the next glyph overlapping it). Replace the width
18
+ * computation with one that covers every glyph in the face. */
19
+ export function coverAllGlyphWidths(font) {
20
+ const embedder = font.embedder;
21
+ const face = embedder.font;
22
+ const toPdfUnits = 1000 / face.unitsPerEm;
23
+ embedder.computeWidths = () => {
24
+ const widths = [];
25
+ for (let gid = 0; gid < face.numGlyphs; gid++) {
26
+ widths.push(face.getGlyph(gid).advanceWidth * toPdfUnits);
27
+ }
28
+ return [0, widths];
29
+ };
30
+ }
31
+ /** UTF-16BE hex of a code point sequence, for a CMap `bfchar` destination. */
32
+ function utf16Hex(codePoints) {
33
+ let out = '';
34
+ for (const cp of codePoints) {
35
+ if (cp > 0xffff) {
36
+ const v = cp - 0x10000;
37
+ out += (0xd800 + (v >> 10)).toString(16).padStart(4, '0') + (0xdc00 + (v & 0x3ff)).toString(16).padStart(4, '0');
38
+ }
39
+ else {
40
+ out += cp.toString(16).padStart(4, '0');
41
+ }
42
+ }
43
+ return out;
44
+ }
45
+ /** A ToUnicode CMap (Identity-H codes = glyph ids) for the given glyphs. */
46
+ export function toUnicodeCmap(glyphs) {
47
+ const entries = glyphs
48
+ .filter((g) => g.codePoints.length > 0)
49
+ .sort((a, b) => a.id - b.id)
50
+ .map((g) => `<${g.id.toString(16).padStart(4, '0')}> <${utf16Hex(g.codePoints)}>`);
51
+ let blocks = '';
52
+ for (let i = 0; i < entries.length; i += 100) {
53
+ const chunk = entries.slice(i, i + 100);
54
+ blocks += `${chunk.length} beginbfchar\n${chunk.join('\n')}\nendbfchar\n`;
55
+ }
56
+ return ('/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n' +
57
+ '/CIDSystemInfo <<\n /Registry (Adobe)\n /Ordering (UCS)\n /Supplement 0\n>> def\n' +
58
+ '/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n' +
59
+ '1 begincodespacerange\n<0000><ffff>\nendcodespacerange\n' +
60
+ blocks +
61
+ 'endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend\n');
62
+ }
63
+ /**
64
+ * A fully embedded face gets a ToUnicode map covering only the glyphs its
65
+ * cmap reaches, so a ligature the shaper substitutes (`fi`, `fl`, `ffi`)
66
+ * has no Unicode value: text extraction drops the letters and PDF/UA
67
+ * validators reject the font (ISO 14289-1 §7.21.7). Record every glyph the
68
+ * layout engine produces for the text actually set — its `codePoints` are
69
+ * the characters it stands for, ligatures included — and write the map
70
+ * from the cmap glyphs plus those.
71
+ */
72
+ export function coverAllGlyphUnicode(font) {
73
+ const embedder = font.embedder;
74
+ const face = embedder.font;
75
+ const shaped = new Map();
76
+ const layout = face.layout.bind(face);
77
+ face.layout = (text, features) => {
78
+ const run = layout(text, features);
79
+ for (const g of run.glyphs) {
80
+ if (g.codePoints.length > 0 && !shaped.has(g.id))
81
+ shaped.set(g.id, g.codePoints);
82
+ }
83
+ return run;
84
+ };
85
+ embedder.embedUnicodeCmap = (context) => {
86
+ const glyphs = [...embedder.glyphCache.access()];
87
+ const known = new Set(glyphs.map((g) => g.id));
88
+ for (const [id, codePoints] of shaped)
89
+ if (!known.has(id))
90
+ glyphs.push({ id, codePoints });
91
+ return context.register(context.flateStream(toUnicodeCmap(glyphs)));
92
+ };
93
+ }
94
+ /**
95
+ * Per-document mapping from `family|weight|style` to an embedded pdf-lib
96
+ * font. Entries are populated up-front by `preload()` so that block-level
97
+ * rendering (`get()`) is a sync lookup. A fontString that fails to parse or
98
+ * to load is mapped to `null` and reported back via `missing()`.
99
+ */
100
+ export class FontCache {
101
+ pdfDoc;
102
+ provider;
103
+ map = new Map();
104
+ failed = new Set();
105
+ constructor(pdfDoc, provider) {
106
+ this.pdfDoc = pdfDoc;
107
+ this.provider = provider;
108
+ }
109
+ async preloadFontStrings(fontStrings) {
110
+ const jobs = new Map();
111
+ for (const fs of fontStrings) {
112
+ if (!fs)
113
+ continue;
114
+ const parsed = parseFontString(fs);
115
+ if (!parsed)
116
+ continue;
117
+ const key = fontKey(parsed.family, parsed.weight, parsed.style);
118
+ if (this.map.has(key) || jobs.has(key))
119
+ continue;
120
+ jobs.set(key, { family: parsed.family, weight: parsed.weight, style: parsed.style });
121
+ }
122
+ await Promise.all(Array.from(jobs.entries()).map(async ([key, spec]) => {
123
+ try {
124
+ const bytes = await this.provider(spec.family, spec.weight, spec.style);
125
+ // pdf-lib's CFF subsetter emits a font stream some viewers cannot
126
+ // parse (macOS Preview draws the text in a fallback face), so CFF
127
+ // OpenType (.otf, signature `OTTO`) embeds whole — larger PDF, but
128
+ // every viewer reads it. TrueType fonts subset normally.
129
+ const subset = !isCffOpenType(bytes);
130
+ const font = await this.pdfDoc.embedFont(bytes, { subset });
131
+ if (!subset) {
132
+ coverAllGlyphWidths(font);
133
+ coverAllGlyphUnicode(font);
134
+ }
135
+ this.map.set(key, font);
136
+ }
137
+ catch {
138
+ this.failed.add(`${spec.family} ${spec.weight}${spec.style === 'italic' ? ' italic' : ''}`);
139
+ this.map.set(key, null);
140
+ }
141
+ }));
142
+ }
143
+ get(fontString) {
144
+ const parsed = parseFontString(fontString);
145
+ if (!parsed)
146
+ return null;
147
+ const key = fontKey(parsed.family, parsed.weight, parsed.style);
148
+ return this.map.get(key) ?? null;
149
+ }
150
+ missing() {
151
+ return [...this.failed];
152
+ }
153
+ }
154
+ //# sourceMappingURL=fontCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fontCache.js","sourceRoot":"","sources":["../src/fontCache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export interface ParsedFontString {
2
+ family: string;
3
+ weight: number;
4
+ style: 'normal' | 'italic';
5
+ sizePx: number;
6
+ }
7
+ /**
8
+ * Parse a CSS-canvas font shorthand of the form produced by `buildFontString()`
9
+ * in the `postext` package (e.g. `italic 700 16px "EB Garamond"`). The regex
10
+ * mirrors `html-backend.ts` so exactly the same shapes are accepted.
11
+ */
12
+ export declare function parseFontString(fs: string): ParsedFontString | null;
13
+ export declare function fontKey(family: string, weight: number, style: 'normal' | 'italic'): string;
14
+ //# sourceMappingURL=fontString.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fontString.d.ts","sourceRoot":"","sources":["../src/fontString.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAMnE;AAwBD,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAE1F"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Parse a CSS-canvas font shorthand of the form produced by `buildFontString()`
3
+ * in the `postext` package (e.g. `italic 700 16px "EB Garamond"`). The regex
4
+ * mirrors `html-backend.ts` so exactly the same shapes are accepted.
5
+ */
6
+ export function parseFontString(fs) {
7
+ const cached = parsedFontStrings.get(fs);
8
+ if (cached !== undefined)
9
+ return cached;
10
+ const parsed = parseFontStringUncached(fs);
11
+ parsedFontStrings.set(fs, parsed);
12
+ return parsed;
13
+ }
14
+ // Memoized: parsing runs per rendered text segment but a document only uses
15
+ // a handful of distinct font strings. Results are treated as read-only.
16
+ const parsedFontStrings = new Map();
17
+ function parseFontStringUncached(fs) {
18
+ const m = fs.match(/^(.*?)(\d+(?:\.\d+)?)px\s+(.+)$/);
19
+ if (!m)
20
+ return null;
21
+ const prefix = (m[1] ?? '').trim();
22
+ const sizePx = parseFloat(m[2]);
23
+ const family = (m[3] ?? '').trim().replace(/^['"]|['"]$/g, '');
24
+ let style = 'normal';
25
+ let weight = 400;
26
+ for (const token of prefix.split(/\s+/).filter(Boolean)) {
27
+ if (token === 'italic' || token === 'oblique')
28
+ style = 'italic';
29
+ else if (token === 'bold')
30
+ weight = 700;
31
+ else if (token === 'normal')
32
+ continue;
33
+ else if (/^\d+$/.test(token))
34
+ weight = parseInt(token, 10);
35
+ }
36
+ if (!Number.isFinite(sizePx) || !family)
37
+ return null;
38
+ return { family, weight, style, sizePx };
39
+ }
40
+ export function fontKey(family, weight, style) {
41
+ return `${family}|${weight}|${style}`;
42
+ }
43
+ //# sourceMappingURL=fontString.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fontString.js","sourceRoot":"","sources":["../src/fontString.ts"],"names":[],"mappings":"AAOA;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAU;IACxC,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IACxC,MAAM,MAAM,GAAG,uBAAuB,CAAC,EAAE,CAAC,CAAC;IAC3C,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,4EAA4E;AAC5E,wEAAwE;AACxE,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAmC,CAAC;AAErE,SAAS,uBAAuB,CAAC,EAAU;IACzC,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACtD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC;IACjC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;IAC/D,IAAI,KAAK,GAAwB,QAAQ,CAAC;IAC1C,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,GAAG,QAAQ,CAAC;aAC3D,IAAI,KAAK,KAAK,MAAM;YAAE,MAAM,GAAG,GAAG,CAAC;aACnC,IAAI,KAAK,KAAK,QAAQ;YAAE,SAAS;aACjC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACrD,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,MAAc,EAAE,KAA0B;IAChF,OAAO,GAAG,MAAM,IAAI,MAAM,IAAI,KAAK,EAAE,CAAC;AACxC,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { renderToPdf } from './pdf-backend';
2
+ export type { RenderToPdfOptions, RenderProgress, PdfFontProvider, ResourceBytesProvider } from './pdf-backend';
3
+ export { decompressWoff2 } from './woff2';
4
+ export { svgToVectorDrawing, type VectorDrawing } from './pdf-backend/svgVector';
5
+ export { sniffBytes, rasterizeSvgWithDom, type SvgRasterizer } from './pdf-backend/renderResourceBlock';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,cAAc,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAChH,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,KAAK,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { renderToPdf } from './pdf-backend';
2
+ export { decompressWoff2 } from './woff2';
3
+ export { svgToVectorDrawing } from './pdf-backend/svgVector';
4
+ export { sniffBytes, rasterizeSvgWithDom } from './pdf-backend/renderResourceBlock';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAsB,MAAM,yBAAyB,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAsB,MAAM,mCAAmC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { VDTBlock } from 'postext';
2
+ import { FontCache } from '../fontCache';
3
+ import { type PageCtx } from './primitives';
4
+ import { type ResourceImageMap } from './renderResourceBlock';
5
+ import { LinkRegistry } from './links';
6
+ import type { StructureFlow } from './structureFlow';
7
+ /** Per-document context for resource rendering, threaded through `renderBlock`. */
8
+ export interface ResourceRenderContext {
9
+ images: ResourceImageMap;
10
+ linkRegistry: LinkRegistry;
11
+ /** Structure mapping of an accessible (tagged) render; absent otherwise. */
12
+ structure?: StructureFlow;
13
+ }
14
+ export declare function renderBlock(ctx: PageCtx, block: VDTBlock, columnWidth: number, columnX: number, fontCache: FontCache, resourceCtx?: ResourceRenderContext): void;
15
+ //# sourceMappingURL=blockRender.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockRender.d.ts","sourceRoot":"","sources":["../../src/pdf-backend/blockRender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAuC,MAAM,SAAS,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,KAAK,OAAO,EAAsD,MAAM,cAAc,CAAC;AAGhG,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,mFAAmF;AACnF,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,EAAE,YAAY,CAAC;IAC3B,4EAA4E;IAC5E,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B;AAmPD,wBAAgB,WAAW,CACzB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,QAAQ,EACf,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,CAAC,EAAE,qBAAqB,GAClC,IAAI,CA0DN"}
@@ -0,0 +1,244 @@
1
+ import { setCharacterSpacing } from 'pdf-lib';
2
+ import { parseFontString } from '../fontString';
3
+ import { drawLinePx, drawSwatchPx, drawTextPx, colorFromHex } from './primitives';
4
+ import { pickSegmentColor, pickSegmentFont } from './fontHelpers';
5
+ import { renderHeaderFooterSlot } from './headerFooter';
6
+ import { renderResourceBlock, } from './renderResourceBlock';
7
+ import { tagArtifact, tagContent } from './tagging';
8
+ function renderMathRender(ctx, render, topLeftXPx, topLeftYPx, fallbackColor) {
9
+ if (!render.paths.length || render.viewBox.width <= 0 || render.viewBox.height <= 0)
10
+ return;
11
+ const { scale: pxToPt, pageHeightPt } = ctx;
12
+ const pxPerVb = render.widthPx / render.viewBox.width;
13
+ const S = pxPerVb * pxToPt;
14
+ const x = topLeftXPx * pxToPt - render.viewBox.minX * S;
15
+ const y = pageHeightPt - topLeftYPx * pxToPt + render.viewBox.minY * S;
16
+ for (const path of render.paths) {
17
+ const color = path.fill === 'currentColor' ? fallbackColor : colorFromHex(path.fill, ctx.colorSpace);
18
+ ctx.page.drawSvgPath(path.d, { x, y, scale: S, color });
19
+ }
20
+ }
21
+ function renderMathSegment(ctx, seg, xPx, baselinePx, fallbackColor) {
22
+ if (!seg.mathRender)
23
+ return;
24
+ renderMathRender(ctx, seg.mathRender, xPx, baselinePx - seg.mathRender.ascentPx, fallbackColor);
25
+ }
26
+ /**
27
+ * Paint a line's segments left to right starting at `startX`. When
28
+ * `justifiedSpaceWidth` is set, spaces advance by it instead of their
29
+ * measured width. `:ref` segments record a link annotation rectangle so the
30
+ * reference is clickable in the final PDF.
31
+ *
32
+ * In a tagged render (`elem` set) the text joins `elem`, each inline formula
33
+ * gets its own `Formula` element (alt text = its TeX) and each ref a `Link`
34
+ * element; word spaces are painted as real space glyphs so text extraction
35
+ * never has to infer them from the gaps of a justified line.
36
+ */
37
+ function renderSegments(ctx, segments, startX, baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, justifiedSpaceWidth) {
38
+ let x = startX;
39
+ for (const seg of segments) {
40
+ if (seg.kind === 'space') {
41
+ if (ctx.tags && seg.text) {
42
+ tagContent(ctx, elem);
43
+ drawTextPx(ctx, seg.text, x, baseline, blockFont, blockSize, blockColor);
44
+ }
45
+ x += justifiedSpaceWidth ?? seg.width;
46
+ continue;
47
+ }
48
+ if (seg.kind === 'math') {
49
+ if (elem) {
50
+ const formula = elem.type === 'Formula' ? elem : elem.child('Formula', { alt: seg.mathRender?.tex ?? '' });
51
+ tagContent(ctx, formula);
52
+ }
53
+ renderMathSegment(ctx, seg, x, baseline, blockColor);
54
+ x += seg.width;
55
+ continue;
56
+ }
57
+ if (seg.kind === 'swatch') {
58
+ tagContent(ctx, elem);
59
+ drawSwatchPx(ctx, x, baseline, seg.width, seg.swatch?.color, blockColor);
60
+ x += seg.width;
61
+ continue;
62
+ }
63
+ const fontStr = seg.fontString ?? pickSegmentFont(!!seg.bold, !!seg.italic, block);
64
+ const font = fontCache.get(fontStr) ?? blockFont;
65
+ const size = parseFontString(fontStr)?.sizePx ?? blockSize;
66
+ const colorHex = seg.color
67
+ ?? (seg.refResourceId !== undefined && block.refColor
68
+ ? block.refColor
69
+ : pickSegmentColor(!!seg.bold, !!seg.italic, block));
70
+ const color = colorHex === block.color ? blockColor : colorFromHex(colorHex, ctx.colorSpace);
71
+ const link = seg.refResourceId !== undefined && elem ? elem.child('Link') : undefined;
72
+ tagContent(ctx, link ?? elem);
73
+ drawTextPx(ctx, seg.text, x, baseline + (seg.baselineShift ?? 0), font, size, color);
74
+ if (seg.refResourceId !== undefined && linkRegistry) {
75
+ const { scale, pageHeightPt } = ctx;
76
+ const x1 = x * scale;
77
+ const x2 = (x + seg.width) * scale;
78
+ const y2 = pageHeightPt - line.bbox.y * scale;
79
+ const y1 = pageHeightPt - (line.bbox.y + line.bbox.height) * scale;
80
+ linkRegistry.addLink(ctx.page, [x1, y1, x2, y2], seg.refResourceId, link ? { elem: link, contents: seg.text } : undefined);
81
+ }
82
+ x += seg.width;
83
+ }
84
+ }
85
+ /** Column-balancing tracking: the block was measured with extra advance
86
+ * after every glyph, so paint it with the matching character spacing
87
+ * (`Tc`, in points at the page scale) and reset it afterwards. */
88
+ function renderLine(ctx, line, block, columnWidth, columnX, fontCache, linkRegistry, elem) {
89
+ const tracked = block.letterSpacing !== undefined && block.letterSpacing > 0;
90
+ if (tracked)
91
+ ctx.page.pushOperators(setCharacterSpacing(block.letterSpacing * ctx.scale));
92
+ renderLineText(ctx, line, block, columnWidth, columnX, fontCache, linkRegistry, elem);
93
+ if (tracked)
94
+ ctx.page.pushOperators(setCharacterSpacing(0));
95
+ }
96
+ function renderLineText(ctx, line, block, columnWidth, columnX, fontCache, linkRegistry, elem) {
97
+ const blockFont = fontCache.get(block.fontString);
98
+ if (!blockFont)
99
+ return;
100
+ const blockSize = parseFontString(block.fontString)?.sizePx ?? 0;
101
+ const blockColor = colorFromHex(block.color, ctx.colorSpace);
102
+ const lineIndent = line.bbox.x - columnX;
103
+ const effectiveWidth = columnWidth - lineIndent;
104
+ const segments = line.segments;
105
+ // Last lines render ragged at natural width — except when overfull:
106
+ // Knuth-Plass may accept a final line wider than the measure on the
107
+ // assumption that its inter-word glue shrinks (TeX glue-setting semantics),
108
+ // so honor that by compressing the spaces to fit the measure exactly.
109
+ if (block.textAlign === 'justify' && segments && segments.length > 0) {
110
+ let wordWidth = 0;
111
+ let naturalWidth = 0;
112
+ let spaceCount = 0;
113
+ for (const seg of segments) {
114
+ if (seg.kind === 'space')
115
+ spaceCount++;
116
+ else
117
+ wordWidth += seg.width;
118
+ naturalWidth += seg.width;
119
+ }
120
+ if (spaceCount > 0 && ((!line.isLastLine && !line.ragged) || naturalWidth > effectiveWidth)) {
121
+ const justifiedSpaceWidth = (effectiveWidth - wordWidth) / spaceCount;
122
+ renderSegments(ctx, segments, line.bbox.x, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem, justifiedSpaceWidth);
123
+ return;
124
+ }
125
+ }
126
+ if ((block.textAlign === 'center' || block.textAlign === 'right') && segments) {
127
+ let contentWidth = 0;
128
+ for (const seg of segments)
129
+ contentWidth += seg.width;
130
+ const slack = Math.max(0, effectiveWidth - contentWidth);
131
+ const startX = line.bbox.x + (block.textAlign === 'center' ? slack / 2 : slack);
132
+ renderSegments(ctx, segments, startX, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem);
133
+ return;
134
+ }
135
+ // Ragged (left-aligned) rendering — also used for last lines of justified
136
+ // blocks. Segments are needed when any of them styles differently from the
137
+ // block (bold/italic/math/ref/own font or colour); otherwise one drawTextPx
138
+ // paints the line.
139
+ if (segments && segments.some((s) => s.bold || s.italic || s.kind === 'math' || s.kind === 'swatch' || s.refResourceId !== undefined || s.fontString !== undefined || s.color !== undefined || s.baselineShift !== undefined)) {
140
+ renderSegments(ctx, segments, line.bbox.x, line.baseline, line, block, blockFont, blockSize, blockColor, fontCache, linkRegistry, elem);
141
+ return;
142
+ }
143
+ tagContent(ctx, elem);
144
+ const plainX = block.textAlign === 'right' ? line.bbox.x + Math.max(0, effectiveWidth - line.bbox.width) : line.bbox.x;
145
+ drawTextPx(ctx, line.text, plainX, line.baseline, blockFont, blockSize, blockColor);
146
+ }
147
+ function renderBullet(ctx, block, fontCache, elem) {
148
+ if (!block.bulletText ||
149
+ !block.bulletFontString ||
150
+ block.bulletOffsetX === undefined) {
151
+ return;
152
+ }
153
+ const firstLine = block.lines[0];
154
+ if (!firstLine)
155
+ return;
156
+ const font = fontCache.get(block.bulletFontString);
157
+ if (!font)
158
+ return;
159
+ const size = parseFontString(block.bulletFontString)?.sizePx ?? 0;
160
+ const colorHex = block.bulletColor ?? block.color;
161
+ const color = colorFromHex(colorHex, ctx.colorSpace);
162
+ // Canvas uses `textBaseline='middle'` at bulletY; pdf-lib draws from the
163
+ // alphabetic baseline. Shift the baseline down by ~0.3em so the em-square
164
+ // midline aligns at bulletY, matching canvas placement within hinting tolerance.
165
+ const midY = block.bulletY ?? firstLine.baseline;
166
+ const baselinePx = midY + size * 0.3;
167
+ tagContent(ctx, elem);
168
+ drawTextPx(ctx, block.bulletText, block.bulletOffsetX, baselinePx, font, size, color);
169
+ // Ordered-list separator styled apart from the number (own font/colour).
170
+ if (block.separatorText && block.separatorX !== undefined) {
171
+ const sepFontString = block.separatorFontString ?? block.bulletFontString;
172
+ const sepFont = fontCache.get(sepFontString);
173
+ if (!sepFont)
174
+ return;
175
+ const sepSize = parseFontString(sepFontString)?.sizePx ?? size;
176
+ const sepColor = colorFromHex(block.separatorColor ?? colorHex, ctx.colorSpace);
177
+ drawTextPx(ctx, block.separatorText, block.separatorX, midY + sepSize * 0.3, sepFont, sepSize, sepColor);
178
+ }
179
+ }
180
+ function renderStrikethrough(ctx, block) {
181
+ if (!block.strikethroughText)
182
+ return;
183
+ tagArtifact(ctx, { type: 'Layout' });
184
+ const color = colorFromHex(block.color, ctx.colorSpace);
185
+ const thickness = Math.max(1, block.lines[0]?.bbox.height ? block.lines[0].bbox.height * 0.05 : 1);
186
+ for (const line of block.lines) {
187
+ const y = line.baseline - line.bbox.height * 0.28;
188
+ drawLinePx(ctx, line.bbox.x, y, line.bbox.x + line.bbox.width, y, color, thickness);
189
+ }
190
+ }
191
+ /** Annotation rectangle of a block's box, in PDF points. */
192
+ function rectOfBlock(ctx, block) {
193
+ const { scale, pageHeightPt } = ctx;
194
+ const { x, y, width, height } = block.bbox;
195
+ return [x * scale, pageHeightPt - (y + height) * scale, (x + width) * scale, pageHeightPt - y * scale];
196
+ }
197
+ export function renderBlock(ctx, block, columnWidth, columnX, fontCache, resourceCtx) {
198
+ if (block.hidden)
199
+ return;
200
+ const structure = resourceCtx?.structure;
201
+ const linkRegistry = resourceCtx?.linkRegistry;
202
+ // A row of the contents links to the page it lists: the whole row is
203
+ // the annotation, its text the `Link` element in a tagged render.
204
+ const targetPage = block.tocEntry?.pageIndex ?? block.tocPart?.pageIndex;
205
+ if (block.designOverlay) {
206
+ // A heading's advanced design or a callout frame: the overlay's text is
207
+ // the heading / the callout title, its boxes and icons are decoration.
208
+ let link;
209
+ const textElem = structure
210
+ ? () => link ?? (targetPage !== undefined ? (link = structure.blockElem(block).child('Link')) : structure.blockElem(block))
211
+ : undefined;
212
+ renderHeaderFooterSlot(ctx, block.designOverlay, fontCache, resourceCtx?.images, textElem ? { text: textElem, artifact: { type: 'Layout' } } : undefined);
213
+ if (targetPage !== undefined && linkRegistry) {
214
+ const contents = block.tocPart ? `${block.tocPart.number} ${block.tocPart.title}`.trim() : block.lines.map((l) => l.text).join(' ');
215
+ linkRegistry.addPageLink(ctx.page, rectOfBlock(ctx, block), targetPage, link ? { elem: link, contents } : undefined);
216
+ }
217
+ return;
218
+ }
219
+ if (block.type === 'resource') {
220
+ renderResourceBlock(ctx, block, fontCache, resourceCtx?.images ?? new Map(), resourceCtx?.linkRegistry, structure);
221
+ return;
222
+ }
223
+ const blockElem = structure && (block.lines.length > 0 || block.bulletText) ? structure.blockElem(block) : undefined;
224
+ const link = targetPage !== undefined && blockElem ? blockElem.child('Link') : undefined;
225
+ const elem = link ?? blockElem;
226
+ if (block.type === 'listItem') {
227
+ renderBullet(ctx, block, fontCache, structure?.bulletElem(block) ?? elem);
228
+ }
229
+ // Justify against the block's own measure (see the canvas backend): blocks
230
+ // inside callouts are narrower than their column.
231
+ void columnWidth;
232
+ void columnX;
233
+ for (const line of block.lines) {
234
+ renderLine(ctx, line, block, block.bbox.width, block.bbox.x, fontCache, linkRegistry, elem);
235
+ }
236
+ if (targetPage !== undefined && linkRegistry) {
237
+ const contents = block.lines.map((l) => l.text).join(' ');
238
+ linkRegistry.addPageLink(ctx.page, rectOfBlock(ctx, block), targetPage, link ? { elem: link, contents } : undefined);
239
+ }
240
+ if (block.strikethroughText) {
241
+ renderStrikethrough(ctx, block);
242
+ }
243
+ }
244
+ //# sourceMappingURL=blockRender.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blockRender.js","sourceRoot":"","sources":["../../src/pdf-backend/blockRender.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { VDTDocument, VDTBlock } from 'postext';
2
+ /** Collect every fontString referenced anywhere in the VDT. */
3
+ export declare function collectFontStrings(doc: VDTDocument): string[];
4
+ export declare function pickSegmentFont(bold: boolean, italic: boolean, block: VDTBlock): string;
5
+ export declare function pickSegmentColor(bold: boolean, italic: boolean, block: VDTBlock): string;
6
+ //# sourceMappingURL=fontHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fontHelpers.d.ts","sourceRoot":"","sources":["../../src/pdf-backend/fontHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAErD,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,EAAE,CAoD7D;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,QAAQ,GACd,MAAM,CAKR;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,OAAO,EACf,KAAK,EAAE,QAAQ,GACd,MAAM,CAIR"}
@@ -0,0 +1,81 @@
1
+ /** Collect every fontString referenced anywhere in the VDT. */
2
+ export function collectFontStrings(doc) {
3
+ const out = new Set();
4
+ // Floated resources live on their page's float band, not in doc.blocks.
5
+ const blocks = [...doc.blocks];
6
+ for (const page of doc.pages) {
7
+ if (page.floats)
8
+ blocks.push(...page.floats);
9
+ }
10
+ for (const block of blocks) {
11
+ // Design overlays (advanced heading designs, callout titles/icons).
12
+ if (block.designOverlay) {
13
+ for (const b of block.designOverlay.blocks) {
14
+ if (b.kind === 'text')
15
+ out.add(b.fontString);
16
+ }
17
+ }
18
+ if (block.fontString)
19
+ out.add(block.fontString);
20
+ if (block.boldFontString)
21
+ out.add(block.boldFontString);
22
+ if (block.italicFontString)
23
+ out.add(block.italicFontString);
24
+ if (block.boldItalicFontString)
25
+ out.add(block.boldItalicFontString);
26
+ if (block.bulletFontString)
27
+ out.add(block.bulletFontString);
28
+ if (block.separatorFontString)
29
+ out.add(block.separatorFontString);
30
+ // Resource caption + table cell fonts (issue #49).
31
+ const rb = block.resourceBlock;
32
+ if (rb) {
33
+ out.add(rb.captionFontString);
34
+ out.add(rb.captionBoldFontString);
35
+ out.add(rb.captionItalicFontString);
36
+ out.add(rb.captionBoldItalicFontString);
37
+ out.add(rb.noteFontString);
38
+ out.add(rb.noteBoldFontString);
39
+ out.add(rb.noteItalicFontString);
40
+ out.add(rb.noteBoldItalicFontString);
41
+ if (rb.table) {
42
+ out.add(rb.table.fontString);
43
+ out.add(rb.table.boldFontString);
44
+ out.add(rb.table.italicFontString);
45
+ out.add(rb.table.boldItalicFontString);
46
+ out.add(rb.table.headerFontString);
47
+ out.add(rb.table.headerBoldFontString);
48
+ out.add(rb.table.headerItalicFontString);
49
+ out.add(rb.table.headerBoldItalicFontString);
50
+ }
51
+ }
52
+ }
53
+ for (const page of doc.pages) {
54
+ for (const slot of [page.header, page.footer, page.openerBand]) {
55
+ if (!slot)
56
+ continue;
57
+ for (const b of slot.blocks) {
58
+ if (b.kind === 'text')
59
+ out.add(b.fontString);
60
+ }
61
+ }
62
+ }
63
+ return [...out];
64
+ }
65
+ export function pickSegmentFont(bold, italic, block) {
66
+ if (bold && italic && block.boldItalicFontString)
67
+ return block.boldItalicFontString;
68
+ if (bold && block.boldFontString)
69
+ return block.boldFontString;
70
+ if (italic && block.italicFontString)
71
+ return block.italicFontString;
72
+ return block.fontString;
73
+ }
74
+ export function pickSegmentColor(bold, italic, block) {
75
+ if (bold && block.boldColor)
76
+ return block.boldColor;
77
+ if (italic && block.italicColor)
78
+ return block.italicColor;
79
+ return block.color;
80
+ }
81
+ //# sourceMappingURL=fontHelpers.js.map