reamkit 1.30.0 → 1.31.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 (78) hide show
  1. package/README.md +60 -24
  2. package/dist/esm/core/converter/project.js +3 -1
  3. package/dist/esm/core/crypto/offcrypto.js +1 -1
  4. package/dist/esm/core/document-model/index.d.ts +1 -1
  5. package/dist/esm/core/document-model/types.d.ts +63 -0
  6. package/dist/esm/core/font/index.d.ts +2 -0
  7. package/dist/esm/core/font/ttf-build.d.ts +113 -0
  8. package/dist/esm/core/font/ttf-build.js +1224 -0
  9. package/dist/esm/core/font/ttf-subset.d.ts +19 -0
  10. package/dist/esm/core/font/ttf-subset.js +14 -1
  11. package/dist/esm/core/fonts/provider.d.ts +17 -0
  12. package/dist/esm/core/fonts/provider.js +27 -2
  13. package/dist/esm/core/fonts/remote-fonts.js +8 -1
  14. package/dist/esm/core/ir/flow.d.ts +71 -1
  15. package/dist/esm/core/numbering/index.d.ts +1 -1
  16. package/dist/esm/core/numbering/state.d.ts +11 -1
  17. package/dist/esm/core/numbering/state.js +10 -1
  18. package/dist/esm/core/style-cascade/resolver.js +35 -4
  19. package/dist/esm/core/style-cascade/types.d.ts +19 -1
  20. package/dist/esm/core/style-cascade/types.js +3 -0
  21. package/dist/esm/index.d.ts +2 -2
  22. package/dist/esm/layout/page-doc.d.ts +10 -3
  23. package/dist/esm/layout/styled-layout.d.ts +48 -7
  24. package/dist/esm/layout/styled-layout.js +881 -119
  25. package/dist/esm/layout/turned-section.d.ts +38 -0
  26. package/dist/esm/layout/turned-section.js +193 -0
  27. package/dist/esm/pdf/styled-page-emitter.js +78 -2
  28. package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
  29. package/dist/esm/pdf-reader/cff-outline.js +169 -21
  30. package/dist/esm/pdf-reader/content.d.ts +53 -0
  31. package/dist/esm/pdf-reader/content.js +9 -1
  32. package/dist/esm/pdf-reader/display.d.ts +36 -0
  33. package/dist/esm/pdf-reader/display.js +66 -1
  34. package/dist/esm/pdf-reader/document.js +5 -1
  35. package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
  36. package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
  37. package/dist/esm/pdf-reader/encodings.d.ts +8 -0
  38. package/dist/esm/pdf-reader/encodings.js +25 -3
  39. package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
  40. package/dist/esm/pdf-reader/face-outlines.js +362 -0
  41. package/dist/esm/pdf-reader/figures.d.ts +52 -0
  42. package/dist/esm/pdf-reader/figures.js +433 -0
  43. package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
  44. package/dist/esm/pdf-reader/flow-build.js +345 -26
  45. package/dist/esm/pdf-reader/font.js +321 -36
  46. package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
  47. package/dist/esm/pdf-reader/glyf-outline.js +135 -1
  48. package/dist/esm/pdf-reader/glyph-names.js +154 -1
  49. package/dist/esm/pdf-reader/layout.d.ts +93 -0
  50. package/dist/esm/pdf-reader/layout.js +1703 -214
  51. package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
  52. package/dist/esm/pdf-reader/page-numbers.js +167 -0
  53. package/dist/esm/pdf-reader/tagged.js +182 -23
  54. package/dist/esm/pdf-reader/text.d.ts +6 -3
  55. package/dist/esm/pdf-reader/text.js +98 -9
  56. package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
  57. package/dist/esm/pdf-reader/type1-outline.js +63 -8
  58. package/dist/esm/pdf-reader/vector.js +71 -1
  59. package/dist/esm/word/doc/doc-reader.js +6 -2
  60. package/dist/esm/word/doc/doc-text.d.ts +6 -0
  61. package/dist/esm/word/doc/doc-text.js +19 -1
  62. package/dist/esm/word/document-parser.d.ts +2 -2
  63. package/dist/esm/word/document-parser.js +11 -1
  64. package/dist/esm/word/docx-reader.js +5 -3
  65. package/dist/esm/word/docx-writer.js +207 -21
  66. package/dist/esm/word/drawing-parser.d.ts +5 -3
  67. package/dist/esm/word/drawing-parser.js +49 -8
  68. package/dist/esm/word/font-embed.d.ts +30 -0
  69. package/dist/esm/word/font-embed.js +173 -0
  70. package/dist/esm/word/font-table.d.ts +10 -0
  71. package/dist/esm/word/font-table.js +13 -1
  72. package/dist/esm/word/index.js +1 -1
  73. package/dist/esm/word/numbering-parser.d.ts +3 -1
  74. package/dist/esm/word/numbering-parser.js +2 -1
  75. package/dist/esm/word/paragraph-properties.d.ts +7 -6
  76. package/dist/esm/word/paragraph-properties.js +14 -2
  77. package/dist/esm/word/run-properties.js +26 -0
  78. package/package.json +8 -3
@@ -0,0 +1,362 @@
1
+ import { editableEmbedding } from "../core/font/ttf-build.js";
2
+ import { isRightToLeft } from "./content.js";
3
+ import { ASCENDER, NATURAL_LINE_EM } from "./flow-build.js";
4
+ //#region src/pdf-reader/face-outlines.ts
5
+ /**
6
+ * Fold one content stream's shown codes into the document's.
7
+ *
8
+ * @param into The document's codes, added to.
9
+ * @param from One stream's (`InterpretResult.shown`).
10
+ */
11
+ function addShown(into, from) {
12
+ for (const [font, codes] of from) {
13
+ let set = into.get(font);
14
+ if (!set) into.set(font, set = /* @__PURE__ */ new Set());
15
+ for (const code of codes) set.add(code);
16
+ }
17
+ }
18
+ /**
19
+ * The outlines of every face the pages painted characters in, keyed by the name
20
+ * a run in the face carries.
21
+ *
22
+ * A face is left out where its program cannot be trusted to say what the page
23
+ * showed: where more than a fifth of its characters have no glyph the reader
24
+ * can find, the way to its glyphs is not the one the page took, and a face
25
+ * embedded that way would show the wrong letters in place of a substitute's
26
+ * right ones. A character whose glyph cannot be found is left out alone — a
27
+ * reader draws it in another face.
28
+ *
29
+ * So is a face that shows a script which is SHAPED: an Arabic letter takes one
30
+ * of four forms by its neighbours, and a face rebuilt here carries one glyph
31
+ * per character and none of the rules that choose between them. Nor can it
32
+ * carry the part of such a face it could: ArabicCIDTrueType.pdf maps half its
33
+ * glyphs to presentation forms, which are shaped already, and half to plain
34
+ * letters — embedded, each line came out in two faces, a bold word with light
35
+ * letters in it.
36
+ *
37
+ * @param shown The codes the pages painted, per font.
38
+ * @param spacing How the pages space each face's text apart where they move the
39
+ * pen rather than draw a glyph (see {@link pageSpacing}).
40
+ * @returns Run font name → the face's outlines.
41
+ */
42
+ function faceOutlinesOf(shown, spacing = NO_SPACING) {
43
+ const faces = /* @__PURE__ */ new Map();
44
+ for (const [font, codes] of shown) {
45
+ const program = font.program;
46
+ if (!program || font.name === void 0) continue;
47
+ let face = faces.get(font.name);
48
+ if (!face) {
49
+ face = {
50
+ font,
51
+ program,
52
+ glyphs: /* @__PURE__ */ new Map(),
53
+ ligatures: /* @__PURE__ */ new Map(),
54
+ sought: 0,
55
+ missed: 0,
56
+ shaped: false
57
+ };
58
+ faces.set(font.name, face);
59
+ }
60
+ if (program.fsType !== void 0 && (face.fsType === void 0 || editableEmbedding(face.fsType))) face.fsType = program.fsType;
61
+ for (const code of [...codes].sort((a, b) => a - b)) gather(face, font, program, code);
62
+ }
63
+ const out = /* @__PURE__ */ new Map();
64
+ for (const [name, face] of faces) {
65
+ const outlines = outlinesOf(face, spacing.wordGaps.get(name), spacing.kerning.get(name));
66
+ if (outlines) out.set(name, outlines);
67
+ }
68
+ return out;
69
+ }
70
+ var NO_SPACING = {
71
+ wordGaps: /* @__PURE__ */ new Map(),
72
+ kerning: /* @__PURE__ */ new Map()
73
+ };
74
+ /**
75
+ * §9.4.3 — what the gaps between a face's runs say about how it is spaced.
76
+ *
77
+ * The interpreter emits a run for every string of a `TJ` array, so where the
78
+ * page nudges the pen inside a word — which is how a producer KERNS it — two
79
+ * runs meet with the nudge between them, and the letters on either side are
80
+ * the pair. bigboundingbox.pdf kerns its Calibri by eight pairs in one short
81
+ * line, and set without them the line came out 0.67pt longer than the page's
82
+ * and no longer fit the cell it was measured into. Each pair is the median of
83
+ * every nudge the page gives it.
84
+ *
85
+ * A wider gap is the white between two words, where the page moves the pen
86
+ * instead of showing a space; the face's space is the lower quartile of them,
87
+ * which a justified line's stretched gaps do not reach.
88
+ *
89
+ * @param pages The runs each page set, in the order they were painted.
90
+ * @returns Per face, its word gap and its kerning pairs.
91
+ */
92
+ function pageSpacing(pages) {
93
+ const gaps = /* @__PURE__ */ new Map();
94
+ const nudges = /* @__PURE__ */ new Map();
95
+ const beside = /* @__PURE__ */ new Map();
96
+ for (const runs of pages) for (let i = 1; i < runs.length; i++) {
97
+ const a = runs[i - 1];
98
+ const b = runs[i];
99
+ const name = a.fontName;
100
+ if (name === void 0 || b.fontName !== name || a.angleDeg !== void 0) continue;
101
+ if (b.angleDeg !== void 0 || a.fontSizePt !== b.fontSizePt || !(a.fontSizePt > 0)) continue;
102
+ if (Math.abs(a.y - b.y) > a.fontSizePt * SAME_LINE_EM) continue;
103
+ if (isRightToLeft(a.text) || isRightToLeft(b.text)) continue;
104
+ const left = [...a.text].at(-1);
105
+ const right = [...b.text][0];
106
+ if (left === void 0 || right === void 0) continue;
107
+ const gap = (b.x - a.endX) / a.fontSizePt * 1e3;
108
+ if (/\s/u.test(left) || /\s/u.test(right)) {
109
+ if (gap > MIN_KERN && gap < MAX_KERN) {
110
+ let list = beside.get(name);
111
+ if (!list) beside.set(name, list = []);
112
+ list.push(b.x - a.endX);
113
+ }
114
+ continue;
115
+ }
116
+ if (gap >= MIN_WORD_GAP && gap <= MAX_WORD_GAP) {
117
+ let list = gaps.get(name);
118
+ if (!list) gaps.set(name, list = []);
119
+ list.push(gap);
120
+ } else if (gap > MIN_KERN && gap < MAX_KERN) {
121
+ let pairs = nudges.get(name);
122
+ if (!pairs) nudges.set(name, pairs = /* @__PURE__ */ new Map());
123
+ const pair = `${left}${right}`;
124
+ let list = pairs.get(pair);
125
+ if (!list) pairs.set(pair, list = []);
126
+ list.push([gap, b.x - a.endX]);
127
+ }
128
+ }
129
+ const wordGaps = /* @__PURE__ */ new Map();
130
+ for (const [name, list] of gaps) {
131
+ if (list.length < MIN_GAP_SAMPLES) continue;
132
+ list.sort((p, q) => p - q);
133
+ wordGaps.set(name, list[Math.floor(list.length / 4)]);
134
+ }
135
+ const kerning = /* @__PURE__ */ new Map();
136
+ for (const [name, pairs] of nudges) {
137
+ if (tracked([...pairs.values()].flat().map(([, points]) => points), beside.get(name) ?? [])) continue;
138
+ const kept = /* @__PURE__ */ new Map();
139
+ for (const [pair, list] of pairs) {
140
+ const inEm = median(list.map(([em]) => em));
141
+ const inPt = median(list.map(([, points]) => points));
142
+ if (Math.abs(inEm) < MIN_KERN_VALUE || Math.abs(inPt) < MIN_KERN_PT) continue;
143
+ if (list.length >= 2 && list.every(([, points]) => Math.abs(points - inPt) <= TWIP_PT) || Math.abs(inPt) >= SURE_KERN_PT) kept.set(pair, inEm);
144
+ }
145
+ if (kept.size >= MIN_KERNED_PAIRS) kerning.set(name, kept);
146
+ }
147
+ return {
148
+ wordGaps,
149
+ kerning
150
+ };
151
+ }
152
+ /**
153
+ * Whether a face's nudges are TRACKING rather than kerning: one amount between
154
+ * nearly every two letters, and beside its spaces too, where no face is kerned.
155
+ * bug1157493.pdf sets a line of Courier half a tenth of an em tight, every
156
+ * letter and every space alike; read as kerning pairs, its letters closed up
157
+ * and its spaces did not.
158
+ *
159
+ * @param nudges The face's nudges between letters, in points.
160
+ * @param beside Its nudges beside a space, in points.
161
+ */
162
+ function tracked(nudges, beside) {
163
+ if (beside.length < MIN_TRACKED_SPACES || nudges.length === 0) return false;
164
+ const typical = median([...nudges, ...beside]);
165
+ if (Math.abs(typical) < MIN_KERN_PT) return false;
166
+ const near = (points) => Math.abs(points - typical) <= TWIP_PT;
167
+ const all = [...nudges, ...beside];
168
+ return beside.filter(near).length >= MIN_TRACKED_SPACES && all.filter(near).length >= all.length * TRACKED_SHARE;
169
+ }
170
+ /** How many nudges beside spaces, and what share of all, make a face tracked. */
171
+ var MIN_TRACKED_SPACES = 2;
172
+ var TRACKED_SHARE = .8;
173
+ /**
174
+ * The faces a page KERNED: those with kerning pairs (see {@link pageSpacing},
175
+ * which keeps a face's pairs only where there are enough of them to say it was
176
+ * kerning and not an accident of how its strings were cut).
177
+ *
178
+ * @param spacing How the pages space their faces (see {@link pageSpacing}).
179
+ * @returns The run font names of the kerned faces.
180
+ */
181
+ function kernedFaces(spacing) {
182
+ return new Set(spacing.kerning.keys());
183
+ }
184
+ /** The middle of some numbers: the mean of the middle two where they are even. */
185
+ function median(values) {
186
+ const sorted = [...values].sort((p, q) => p - q);
187
+ const mid = sorted.length / 2;
188
+ return sorted.length % 2 === 1 ? sorted[Math.floor(mid)] : (sorted[mid - 1] + sorted[mid]) / 2;
189
+ }
190
+ /** Two runs within this much of an em of each other's baseline share a line. */
191
+ var SAME_LINE_EM = .1;
192
+ /** A gap between words: wider than a kern, narrower than a column's white. */
193
+ var MIN_WORD_GAP = 100;
194
+ var MAX_WORD_GAP = 600;
195
+ /**
196
+ * A nudge inside a word, in thousandths of an em: kerning tightens a pair by as
197
+ * much as a quarter of an em and opens one by far less — a gap wider than this
198
+ * is a space the page did not draw.
199
+ */
200
+ var MIN_KERN = -250;
201
+ var MAX_KERN = 60;
202
+ /** A nudge smaller than this is the rounding of a producer's positions, not a kern. */
203
+ var MIN_KERN_VALUE = 2;
204
+ /**
205
+ * …and so is one smaller than a twip and a half, in points: Word lays a line
206
+ * out in twips and writes the difference from the face's own widths as a
207
+ * nudge. annotation-highlight.pdf's Calibri is nudged three to six thousandths
208
+ * of an em between letters no kerning table pairs, and taken for kerns they
209
+ * moved its words a fraction of a pixel off the page's.
210
+ */
211
+ var MIN_KERN_PT = .075;
212
+ /** A twip, in points: the grid a Word page's positions are rounded to. */
213
+ var TWIP_PT = .05;
214
+ /**
215
+ * A nudge this wide is a kern seen once: rounding moves a letter a twip or
216
+ * two, and bug793632.pdf's Calibri is nudged two twips either way — "st" in
217
+ * and "on" out — once each, by no kerning at all.
218
+ */
219
+ var SURE_KERN_PT = .15;
220
+ /** How many pairs make a face one the page kerned. */
221
+ var MIN_KERNED_PAIRS = 2;
222
+ /** How many gaps it takes to say how wide a face's space is. */
223
+ var MIN_GAP_SAMPLES = 3;
224
+ /** Read one code's glyph into its face, where it stands for one character or a ligature. */
225
+ function gather(face, font, program, code) {
226
+ const chars = [...font.decode([code])];
227
+ if (chars.length > 1) {
228
+ gatherLigature(face, font, program, code, chars);
229
+ return;
230
+ }
231
+ if (chars.length !== 1) return;
232
+ const char = chars[0];
233
+ if (face.glyphs.has(char) || !embeddable(char)) return;
234
+ if (shaped(char)) {
235
+ face.shaped = true;
236
+ return;
237
+ }
238
+ const blank = WHITE.test(char);
239
+ if (!blank) face.sought++;
240
+ const outline = program.glyph(code);
241
+ if (outline === void 0 || outline.length === 0 && !blank) {
242
+ if (!blank) face.missed++;
243
+ return;
244
+ }
245
+ face.glyphs.set(char, {
246
+ outline,
247
+ advance: font.width(code)
248
+ });
249
+ }
250
+ /**
251
+ * §9.10.2 — a code that stands for a run of letters is a LIGATURE: one glyph
252
+ * the page drew for "fi", "ffl" or Calibri's "tt". The text carries the letters
253
+ * and the rebuilt face the glyph, so a reader that joins them draws what the
254
+ * page drew — set apart, attachment.pdf's "attachment" came out with two
255
+ * crossbars where the page has one.
256
+ *
257
+ * Only letters, and no more than {@link MAX_LIGATURE} of them: a producer that
258
+ * maps a glyph to a longer string — a logo to a company's name — has not drawn
259
+ * a ligature.
260
+ */
261
+ function gatherLigature(face, font, program, code, chars) {
262
+ const key = chars.join("");
263
+ if (chars.length > MAX_LIGATURE || face.ligatures.has(key)) return;
264
+ if (!chars.every((c) => /^\p{L}$/u.test(c) && !shaped(c))) return;
265
+ const outline = program.glyph(code);
266
+ if (outline === void 0 || outline.length === 0) return;
267
+ face.ligatures.set(key, {
268
+ outline,
269
+ advance: font.width(code)
270
+ });
271
+ }
272
+ /** The most letters one ligature joins: ffi, ffl. */
273
+ var MAX_LIGATURE = 3;
274
+ /** A face's gathered glyphs as {@link FaceOutlines}, where it is one to embed. */
275
+ function outlinesOf(face, gap, kerning) {
276
+ if (face.shaped || face.sought === 0 || face.missed > face.sought * MAX_MISSED_SHARE) return;
277
+ const glyphs = new Map(face.glyphs);
278
+ const program = face.program;
279
+ if (!glyphs.has(" ")) glyphs.set(" ", {
280
+ outline: [],
281
+ advance: spaceAdvance(face, gap)
282
+ });
283
+ if (!glyphs.has("\xA0")) glyphs.set("\xA0", glyphs.get(" "));
284
+ const { yMin, yMax } = extent(glyphs);
285
+ const pairs = new Map([...kerning ?? []].filter(([pair]) => [...pair].every((c) => glyphs.has(c))));
286
+ const ligatures = new Map([...face.ligatures].filter(([letters]) => [...letters].every((c) => glyphs.has(c))));
287
+ return {
288
+ glyphs,
289
+ ...pairs.size > 0 ? { kerning: pairs } : {},
290
+ ...ligatures.size > 0 ? { ligatures } : {},
291
+ ...face.fsType !== void 0 ? { fsType: face.fsType } : {},
292
+ bold: face.font.bold === true,
293
+ italic: face.font.italic === true,
294
+ postScriptName: program.postScriptName,
295
+ ascent: Math.max(ASCENDER * 1e3, yMax),
296
+ descent: Math.min((ASCENDER - NATURAL_LINE_EM) * 1e3, yMin),
297
+ ...program.capHeight !== void 0 ? { capHeight: program.capHeight } : {},
298
+ ...program.xHeight !== void 0 ? { xHeight: program.xHeight } : {},
299
+ italicAngle: program.italicAngle,
300
+ fixedPitch: program.fixedPitch
301
+ };
302
+ }
303
+ /** A face may miss no more than this share of the glyphs looked for. */
304
+ var MAX_MISSED_SHARE = .2;
305
+ /**
306
+ * The advance of a space the page never showed: the width the file states for
307
+ * the face's space (see `ContentFont.spaceWidth`), where it states one; the
308
+ * width the program gives its space glyph — which a subset keeps though it
309
+ * drops the outline;
310
+ * the white the page itself leaves between the face's words; the one advance
311
+ * every glyph has, in a fixed-pitch face; a quarter of an em otherwise.
312
+ * bigboundingbox.pdf sets its Calibri in a subset that keeps no space and no
313
+ * way to one, and spaces the words by hand: with a quarter of an em for
314
+ * Calibri's 226 thousandths, "Enter the amount you are paying above" no longer
315
+ * fit its cell.
316
+ */
317
+ function spaceAdvance(face, gap) {
318
+ const width = face.font.spaceWidth;
319
+ if (width !== void 0 && width > 0 && width < 1e3) return width;
320
+ if (face.program.spaceAdvance !== void 0) return face.program.spaceAdvance;
321
+ if (gap !== void 0) return gap;
322
+ if (face.program.fixedPitch) {
323
+ const first = [...face.glyphs.values()].find((g) => g.advance > 0);
324
+ if (first) return first.advance;
325
+ }
326
+ return 250;
327
+ }
328
+ /** How high and how low the glyphs' contours reach, in thousandths of an em. */
329
+ function extent(glyphs) {
330
+ let yMin = 0;
331
+ let yMax = 0;
332
+ for (const glyph of glyphs.values()) for (const seg of glyph.outline) {
333
+ if (seg.op === "close") continue;
334
+ yMin = Math.min(yMin, seg.y * 1e3);
335
+ yMax = Math.max(yMax, seg.y * 1e3);
336
+ }
337
+ return {
338
+ yMin,
339
+ yMax
340
+ };
341
+ }
342
+ /** Whitespace: a glyph that rightly draws nothing. */
343
+ var WHITE = /^\s$/u;
344
+ /** Whether a character is one a face carries at all: not a control or a format character. */
345
+ function embeddable(char) {
346
+ return !/^[\p{Cc}\p{Cf}\p{Cs}\uFFFD]$/u.test(char);
347
+ }
348
+ /**
349
+ * Whether a character is a letter of a script whose glyphs a face's shaping
350
+ * rules choose — which a rebuilt face does not have.
351
+ */
352
+ function shaped(char) {
353
+ const cp = char.codePointAt(0);
354
+ if (cp >= 64336 && cp <= 65023 || cp >= 65136 && cp <= 65279) return false;
355
+ if (cp >= 4352 && cp <= 4607 || cp >= 43360 && cp <= 43391) return true;
356
+ if (cp >= 55216 && cp <= 55295) return true;
357
+ return SHAPED.test(char);
358
+ }
359
+ /** The scripts whose glyphs a face's shaping rules choose. */
360
+ var SHAPED = /\p{Script=Arabic}|\p{Script=Syriac}|\p{Script=Thaana}|\p{Script=Nko}|\p{Script=Mandaic}|\p{Script=Devanagari}|\p{Script=Bengali}|\p{Script=Gurmukhi}|\p{Script=Gujarati}|\p{Script=Oriya}|\p{Script=Tamil}|\p{Script=Telugu}|\p{Script=Kannada}|\p{Script=Malayalam}|\p{Script=Sinhala}|\p{Script=Thai}|\p{Script=Lao}|\p{Script=Tibetan}|\p{Script=Myanmar}|\p{Script=Khmer}|\p{Script=Mongolian}|\p{Script=Javanese}|\p{Script=Balinese}/u;
361
+ //#endregion
362
+ export { addShown, faceOutlinesOf, kernedFaces, pageSpacing };
@@ -0,0 +1,52 @@
1
+ import { TextRun } from './content.js';
2
+ import { PdfImage } from './images.js';
3
+ import { PdfVector } from './vector.js';
4
+ /** One drawing on a page, with the words set on it. Page space, y-up. */
5
+ export interface PageFigure {
6
+ readonly minX: number;
7
+ readonly minY: number;
8
+ readonly maxX: number;
9
+ readonly maxY: number;
10
+ /** The paths that draw it, in no particular order. */
11
+ readonly vectors: ReadonlyArray<PdfVector>;
12
+ /** The pictures it holds. */
13
+ readonly images: ReadonlyArray<PdfImage>;
14
+ /** The words set on it. */
15
+ readonly labels: ReadonlyArray<TextRun>;
16
+ }
17
+ /**
18
+ * The figures a page draws.
19
+ *
20
+ * A figure is paths that stand together — each within half an em of the next —
21
+ * and DRAW something: a curve or a slanted line among them. Straight lines
22
+ * and boxes alone are a ruling, which is a table's or a form's, and a page
23
+ * reads those as text. It has words set on it, or it is only artwork, which
24
+ * the page anchors as it always has; and none of its words run across it
25
+ * line after line, which is prose set on a ground, not a label.
26
+ *
27
+ * @param vectors The page's paths, where the page shows them.
28
+ * @param images The page's pictures, likewise.
29
+ * @param runs The page's text, likewise.
30
+ * @param sheet The page's size.
31
+ * @returns The figures, top of the page first.
32
+ */
33
+ export declare function pageFigures(vectors: ReadonlyArray<PdfVector>, images: ReadonlyArray<PdfImage>, runs: ReadonlyArray<TextRun>, sheet: {
34
+ readonly width: number;
35
+ readonly height: number;
36
+ }): Array<PageFigure>;
37
+ /**
38
+ * Whether a run is lettering the file states no character for: glyphs traced
39
+ * as paths (see `PdfVector.glyph`), and a label only by where they stand.
40
+ *
41
+ * @param run A run of the page's text.
42
+ */
43
+ export declare function tracedRun(run: TextRun): boolean;
44
+ /**
45
+ * A figure's paths with the traced letters painted one after another joined
46
+ * into one: the letters of a label are one shape, where a shape a letter made
47
+ * a chart of six hundred.
48
+ *
49
+ * @param paths The figure's paths, in the order the page painted them.
50
+ * @returns The paths to draw, in that order.
51
+ */
52
+ export declare function joinLetters(paths: ReadonlyArray<PdfVector>): Array<PdfVector>;