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.
- package/README.md +60 -24
- package/dist/esm/core/converter/project.js +3 -1
- package/dist/esm/core/crypto/offcrypto.js +1 -1
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +63 -0
- package/dist/esm/core/font/index.d.ts +2 -0
- package/dist/esm/core/font/ttf-build.d.ts +113 -0
- package/dist/esm/core/font/ttf-build.js +1224 -0
- package/dist/esm/core/font/ttf-subset.d.ts +19 -0
- package/dist/esm/core/font/ttf-subset.js +14 -1
- package/dist/esm/core/fonts/provider.d.ts +17 -0
- package/dist/esm/core/fonts/provider.js +27 -2
- package/dist/esm/core/fonts/remote-fonts.js +8 -1
- package/dist/esm/core/ir/flow.d.ts +71 -1
- package/dist/esm/core/numbering/index.d.ts +1 -1
- package/dist/esm/core/numbering/state.d.ts +11 -1
- package/dist/esm/core/numbering/state.js +10 -1
- package/dist/esm/core/style-cascade/resolver.js +35 -4
- package/dist/esm/core/style-cascade/types.d.ts +19 -1
- package/dist/esm/core/style-cascade/types.js +3 -0
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/layout/page-doc.d.ts +10 -3
- package/dist/esm/layout/styled-layout.d.ts +48 -7
- package/dist/esm/layout/styled-layout.js +881 -119
- package/dist/esm/layout/turned-section.d.ts +38 -0
- package/dist/esm/layout/turned-section.js +193 -0
- package/dist/esm/pdf/styled-page-emitter.js +78 -2
- package/dist/esm/pdf-reader/cff-outline.d.ts +27 -0
- package/dist/esm/pdf-reader/cff-outline.js +169 -21
- package/dist/esm/pdf-reader/content.d.ts +53 -0
- package/dist/esm/pdf-reader/content.js +9 -1
- package/dist/esm/pdf-reader/display.d.ts +36 -0
- package/dist/esm/pdf-reader/display.js +66 -1
- package/dist/esm/pdf-reader/document.js +5 -1
- package/dist/esm/pdf-reader/embedded-fonts.d.ts +2 -1
- package/dist/esm/pdf-reader/embedded-fonts.js +32 -2
- package/dist/esm/pdf-reader/encodings.d.ts +8 -0
- package/dist/esm/pdf-reader/encodings.js +25 -3
- package/dist/esm/pdf-reader/face-outlines.d.ts +78 -0
- package/dist/esm/pdf-reader/face-outlines.js +362 -0
- package/dist/esm/pdf-reader/figures.d.ts +52 -0
- package/dist/esm/pdf-reader/figures.js +433 -0
- package/dist/esm/pdf-reader/flow-build.d.ts +131 -5
- package/dist/esm/pdf-reader/flow-build.js +345 -26
- package/dist/esm/pdf-reader/font.js +321 -36
- package/dist/esm/pdf-reader/glyf-outline.d.ts +33 -0
- package/dist/esm/pdf-reader/glyf-outline.js +135 -1
- package/dist/esm/pdf-reader/glyph-names.js +154 -1
- package/dist/esm/pdf-reader/layout.d.ts +93 -0
- package/dist/esm/pdf-reader/layout.js +1703 -214
- package/dist/esm/pdf-reader/page-numbers.d.ts +53 -0
- package/dist/esm/pdf-reader/page-numbers.js +167 -0
- package/dist/esm/pdf-reader/tagged.js +182 -23
- package/dist/esm/pdf-reader/text.d.ts +6 -3
- package/dist/esm/pdf-reader/text.js +98 -9
- package/dist/esm/pdf-reader/type1-outline.d.ts +11 -0
- package/dist/esm/pdf-reader/type1-outline.js +63 -8
- package/dist/esm/pdf-reader/vector.js +71 -1
- package/dist/esm/word/doc/doc-reader.js +6 -2
- package/dist/esm/word/doc/doc-text.d.ts +6 -0
- package/dist/esm/word/doc/doc-text.js +19 -1
- package/dist/esm/word/document-parser.d.ts +2 -2
- package/dist/esm/word/document-parser.js +11 -1
- package/dist/esm/word/docx-reader.js +5 -3
- package/dist/esm/word/docx-writer.js +207 -21
- package/dist/esm/word/drawing-parser.d.ts +5 -3
- package/dist/esm/word/drawing-parser.js +49 -8
- package/dist/esm/word/font-embed.d.ts +30 -0
- package/dist/esm/word/font-embed.js +173 -0
- package/dist/esm/word/font-table.d.ts +10 -0
- package/dist/esm/word/font-table.js +13 -1
- package/dist/esm/word/index.js +1 -1
- package/dist/esm/word/numbering-parser.d.ts +3 -1
- package/dist/esm/word/numbering-parser.js +2 -1
- package/dist/esm/word/paragraph-properties.d.ts +7 -6
- package/dist/esm/word/paragraph-properties.js +14 -2
- package/dist/esm/word/run-properties.js +26 -0
- package/package.json +8 -3
|
@@ -33,14 +33,22 @@ function paragraphBlock(text, outlineLevel) {
|
|
|
33
33
|
* them up to "78110"; in 7-point footnotes the same space is half as wide
|
|
34
34
|
* again as the page's, and pushes their lines over.
|
|
35
35
|
*
|
|
36
|
+
* A space between two words one text markup marks is marked with them: the
|
|
37
|
+
* band a highlighter lays runs across the gap. comments.pdf highlights two
|
|
38
|
+
* lines on its sixth page, and with its spaces left bare the band came back
|
|
39
|
+
* broken at every word.
|
|
40
|
+
*
|
|
36
41
|
* @param before The span the space follows, where there is one.
|
|
42
|
+
* @param after What follows the space, where anything does.
|
|
37
43
|
* @returns The space.
|
|
38
44
|
*/
|
|
39
|
-
function spaceAfter(before) {
|
|
45
|
+
function spaceAfter(before, after) {
|
|
46
|
+
const markup = before?.markup;
|
|
40
47
|
return {
|
|
41
48
|
text: " ",
|
|
42
49
|
...before?.sizePt !== void 0 ? { sizePt: before.sizePt } : {},
|
|
43
|
-
...before?.fontName !== void 0 ? { fontName: before.fontName } : {}
|
|
50
|
+
...before?.fontName !== void 0 ? { fontName: before.fontName } : {},
|
|
51
|
+
...markup !== void 0 && after?.markup !== void 0 && sameMarkup(markup, after.markup) ? { markup } : {}
|
|
44
52
|
};
|
|
45
53
|
}
|
|
46
54
|
/**
|
|
@@ -53,7 +61,7 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
53
61
|
const merged = [];
|
|
54
62
|
for (const s of spans) {
|
|
55
63
|
const last = merged[merged.length - 1];
|
|
56
|
-
if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic && last.script === s.script && sameMarkup(last.markup, s.markup)) last.text += s.text;
|
|
64
|
+
if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic && last.script === s.script && last.widthScale === s.widthScale && sameMarkup(last.markup, s.markup)) last.text += s.text;
|
|
57
65
|
else merged.push({
|
|
58
66
|
text: s.text,
|
|
59
67
|
...s.href !== void 0 ? { href: s.href } : {},
|
|
@@ -64,7 +72,8 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
64
72
|
...s.bold !== void 0 ? { bold: s.bold } : {},
|
|
65
73
|
...s.italic !== void 0 ? { italic: s.italic } : {},
|
|
66
74
|
...s.script !== void 0 ? { script: s.script } : {},
|
|
67
|
-
...s.markup !== void 0 ? { markup: s.markup } : {}
|
|
75
|
+
...s.markup !== void 0 ? { markup: s.markup } : {},
|
|
76
|
+
...s.widthScale !== void 0 ? { widthScale: s.widthScale } : {}
|
|
68
77
|
});
|
|
69
78
|
}
|
|
70
79
|
const runs = merged.map((m) => ({
|
|
@@ -98,7 +107,8 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
|
|
|
98
107
|
...r.markup?.highlightHex !== void 0 ? { shadingColorHex: r.markup.highlightHex } : {},
|
|
99
108
|
...r.markup?.underline !== void 0 ? { underline: r.markup.underline } : {},
|
|
100
109
|
...r.markup?.underlineHex !== void 0 ? { underlineColorHex: r.markup.underlineHex } : {},
|
|
101
|
-
...r.markup?.strike === true ? { strike: true } : {}
|
|
110
|
+
...r.markup?.strike === true ? { strike: true } : {},
|
|
111
|
+
...r.widthScale !== void 0 ? { widthScale: r.widthScale } : {}
|
|
102
112
|
},
|
|
103
113
|
...r.href ? { href: r.href } : {}
|
|
104
114
|
}))
|
|
@@ -181,10 +191,6 @@ function imageBlock(image, resources, alt, frame, zOrder, behind = false) {
|
|
|
181
191
|
* @returns A shape carrying the text, anchored where the glyphs were.
|
|
182
192
|
*/
|
|
183
193
|
function positionedText(spans, box, frame, zOrder, rotation60k) {
|
|
184
|
-
const paragraph = paragraphFromRuns(spans, void 0, {
|
|
185
|
-
spacingLine: pt(Math.max(1, box.height)),
|
|
186
|
-
spacingLineRule: "exact"
|
|
187
|
-
});
|
|
188
194
|
return {
|
|
189
195
|
kind: "shape",
|
|
190
196
|
shape: {
|
|
@@ -200,22 +206,134 @@ function positionedText(spans, box, frame, zOrder, rotation60k) {
|
|
|
200
206
|
offsetPt: pt(Math.max(0, frame.top - box.y - box.height))
|
|
201
207
|
}
|
|
202
208
|
},
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
209
|
+
...lineBox(spans, box, rotation60k),
|
|
210
|
+
paragraphProperties: FLOAT_CARRIER
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
/** A line of text in a box of its own, sized to the box, which nobody sees. */
|
|
215
|
+
function lineBox(spans, box, rotation60k, noWrap = false) {
|
|
216
|
+
const paragraph = paragraphFromRuns(spans, void 0, {
|
|
217
|
+
spacingLine: pt(Math.max(1, box.height)),
|
|
218
|
+
spacingLineRule: "exact"
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
width: pt(Math.max(1, box.width)),
|
|
222
|
+
height: pt(Math.max(1, box.height)),
|
|
223
|
+
...rotation60k !== void 0 ? { transform: { rotation60k } } : {},
|
|
224
|
+
geometry: {
|
|
225
|
+
kind: "preset",
|
|
226
|
+
preset: "rect"
|
|
227
|
+
},
|
|
228
|
+
fill: { kind: "none" },
|
|
229
|
+
text: {
|
|
230
|
+
content: [paragraph],
|
|
231
|
+
insetLeft: pt(0),
|
|
232
|
+
insetTop: pt(0),
|
|
233
|
+
insetRight: pt(0),
|
|
234
|
+
insetBottom: pt(0),
|
|
235
|
+
...noWrap ? { noWrap: true } : {}
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/** A path of a figure, drawn where the page drew it. */
|
|
240
|
+
function vectorMember(v) {
|
|
241
|
+
const el = shapeBlock(v);
|
|
242
|
+
if (el.kind !== "shape") throw new Error("a path is drawn as a shape");
|
|
243
|
+
return {
|
|
244
|
+
shape: el.shape,
|
|
245
|
+
left: v.minX,
|
|
246
|
+
top: v.maxY
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* A picture of a figure: a box filled with it (§20.1.8.14), which is what a
|
|
251
|
+
* `pic:pic` inside a group is — the shadows comments.pdf lays under each of
|
|
252
|
+
* its boxes.
|
|
253
|
+
*/
|
|
254
|
+
function imageMember(image, resources) {
|
|
255
|
+
const turned = image.rotationDeg !== void 0 || image.flipV === true;
|
|
256
|
+
return {
|
|
257
|
+
shape: {
|
|
258
|
+
width: pt(image.widthPt),
|
|
259
|
+
height: pt(image.heightPt),
|
|
260
|
+
...turned ? { transform: {
|
|
261
|
+
...image.rotationDeg !== void 0 ? { rotation60k: Math.round(-image.rotationDeg * 6e4) } : {},
|
|
262
|
+
...image.flipV === true ? { flipV: true } : {}
|
|
263
|
+
} } : {},
|
|
206
264
|
geometry: {
|
|
207
265
|
kind: "preset",
|
|
208
266
|
preset: "rect"
|
|
209
267
|
},
|
|
210
|
-
fill: {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
insetRight: pt(0),
|
|
216
|
-
insetBottom: pt(0)
|
|
268
|
+
fill: {
|
|
269
|
+
kind: "picture",
|
|
270
|
+
imageResource: resources.put(image.bytes),
|
|
271
|
+
...image.crop ? { imageCrop: image.crop } : {},
|
|
272
|
+
...image.alpha !== void 0 ? { alpha: image.alpha } : {}
|
|
217
273
|
},
|
|
218
|
-
paragraphProperties:
|
|
274
|
+
paragraphProperties: {}
|
|
275
|
+
},
|
|
276
|
+
left: image.x,
|
|
277
|
+
top: image.y + image.heightPt
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* A label of a figure: a line of its words, in a box as wide as they are.
|
|
282
|
+
* The box never wraps — set in a face a little wider than the page's, one
|
|
283
|
+
* word would break in two.
|
|
284
|
+
*/
|
|
285
|
+
function labelMember(spans, box, rotation60k) {
|
|
286
|
+
return {
|
|
287
|
+
shape: {
|
|
288
|
+
...lineBox(spans, box, rotation60k, true),
|
|
289
|
+
paragraphProperties: {}
|
|
290
|
+
},
|
|
291
|
+
left: box.x,
|
|
292
|
+
top: box.y + box.height
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** The box a figure's parts stand in, on the page (y-up). */
|
|
296
|
+
function membersBox(members) {
|
|
297
|
+
return {
|
|
298
|
+
left: Math.min(...members.map((m) => m.left)),
|
|
299
|
+
top: Math.max(...members.map((m) => m.top)),
|
|
300
|
+
right: Math.max(...members.map((m) => m.left + m.shape.width)),
|
|
301
|
+
bottom: Math.min(...members.map((m) => m.top - m.shape.height))
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* §20.5.2.17 — a figure as the one drawing it is: a group holding its paths,
|
|
306
|
+
* its pictures and its labels at their places in it, set in a paragraph of
|
|
307
|
+
* its own. An inline drawing takes the room it is tall (a line holding
|
|
308
|
+
* nothing but a picture is the picture's height in Word), so the text after
|
|
309
|
+
* it follows it, and the figure goes with its paragraph wherever the text
|
|
310
|
+
* puts that.
|
|
311
|
+
*
|
|
312
|
+
* @param members Its parts, in the order they are painted.
|
|
313
|
+
* @param properties The paragraph it stands in.
|
|
314
|
+
*/
|
|
315
|
+
function figureBlock(members, properties) {
|
|
316
|
+
const box = membersBox(members);
|
|
317
|
+
return {
|
|
318
|
+
kind: "shape",
|
|
319
|
+
shape: {
|
|
320
|
+
width: pt(box.right - box.left),
|
|
321
|
+
height: pt(box.top - box.bottom),
|
|
322
|
+
children: members.map((m) => ({
|
|
323
|
+
shape: m.shape,
|
|
324
|
+
xPt: pt(m.left - box.left),
|
|
325
|
+
yPt: pt(box.top - m.top)
|
|
326
|
+
})),
|
|
327
|
+
geometry: {
|
|
328
|
+
kind: "custom",
|
|
329
|
+
custom: {
|
|
330
|
+
pathWidth: 0,
|
|
331
|
+
pathHeight: 0,
|
|
332
|
+
commands: []
|
|
333
|
+
}
|
|
334
|
+
},
|
|
335
|
+
fill: { kind: "none" },
|
|
336
|
+
paragraphProperties: properties
|
|
219
337
|
}
|
|
220
338
|
};
|
|
221
339
|
}
|
|
@@ -332,10 +450,10 @@ function shapeBlock(v, frame, zOrder, behind = false) {
|
|
|
332
450
|
* this single geometry — a known approximation, still far better than a fixed
|
|
333
451
|
* `A4`. Returns `undefined` when there is no usable first-page box.
|
|
334
452
|
*/
|
|
335
|
-
function sectionFromPdfPages(pages) {
|
|
453
|
+
function sectionFromPdfPages(pages, display) {
|
|
336
454
|
const first = pages[0];
|
|
337
455
|
if (!first) return void 0;
|
|
338
|
-
const shown = displayOf(first);
|
|
456
|
+
const shown = display ?? displayOf(first);
|
|
339
457
|
const width = shown.width;
|
|
340
458
|
const height = shown.height;
|
|
341
459
|
if (!(width > 0 && height > 0)) return void 0;
|
|
@@ -356,6 +474,102 @@ function sectionFromPdfPages(pages) {
|
|
|
356
474
|
};
|
|
357
475
|
}
|
|
358
476
|
/**
|
|
477
|
+
* §17.6.20 — a section read in a page's text frame (see `textFrameOf`), set
|
|
478
|
+
* back on the sheet the page is shown on, its lines running down it (`tbRl`).
|
|
479
|
+
*
|
|
480
|
+
* The frame is the sheet turned back a quarter, so its measurements carry
|
|
481
|
+
* over edge for edge: the frame's left margin is where each line starts, the
|
|
482
|
+
* sheet's top one; its top margin is where the first line stands, the
|
|
483
|
+
* sheet's right one.
|
|
484
|
+
*
|
|
485
|
+
* @param section The section as the frame measured it.
|
|
486
|
+
* @param display The geometry its pages were read in.
|
|
487
|
+
* @returns The section on the sheet, or the section unchanged for a page read
|
|
488
|
+
* on its sheet.
|
|
489
|
+
*/
|
|
490
|
+
function sectionOnSheet(section, display) {
|
|
491
|
+
const sheet = display?.sheet;
|
|
492
|
+
if (!section || !sheet) return section;
|
|
493
|
+
const m = section.margins;
|
|
494
|
+
return {
|
|
495
|
+
...section,
|
|
496
|
+
pageSize: {
|
|
497
|
+
width: pt(sheet.width),
|
|
498
|
+
height: pt(sheet.height),
|
|
499
|
+
orientation: sheet.width > sheet.height ? "landscape" : "portrait"
|
|
500
|
+
},
|
|
501
|
+
...m ? { margins: {
|
|
502
|
+
...m,
|
|
503
|
+
top: m.left,
|
|
504
|
+
right: m.top,
|
|
505
|
+
bottom: m.right,
|
|
506
|
+
left: m.bottom
|
|
507
|
+
} } : {},
|
|
508
|
+
textDirection: "tbRl"
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* A mark anchored to a page read in its text frame, set on the SHEET the page
|
|
513
|
+
* is shown on: where the page drew it, turned with the page.
|
|
514
|
+
*
|
|
515
|
+
* Word lays a `tbRl` section's text down the sheet but stands a drawing
|
|
516
|
+
* anchored to the page at its offsets on the sheet, upright (§17.6.20) — so a
|
|
517
|
+
* picture the frame placed is carried onto the sheet, and turned a quarter
|
|
518
|
+
* clockwise as the words around it are.
|
|
519
|
+
*
|
|
520
|
+
* @param el A body element, anchored or not.
|
|
521
|
+
* @param sheetWidth The sheet's width, which is the frame's height.
|
|
522
|
+
* @returns The element, anchored on the sheet.
|
|
523
|
+
*/
|
|
524
|
+
function floatOntoSheet(el, sheetWidth) {
|
|
525
|
+
const onto = (float, width, height) => {
|
|
526
|
+
if (float.posH?.relativeFrom !== "page" || float.posV?.relativeFrom !== "page") return void 0;
|
|
527
|
+
const cx = (float.posH.offsetPt ?? 0) + width / 2;
|
|
528
|
+
const cy = (float.posV.offsetPt ?? 0) + height / 2;
|
|
529
|
+
return {
|
|
530
|
+
...float,
|
|
531
|
+
posH: {
|
|
532
|
+
relativeFrom: "page",
|
|
533
|
+
offsetPt: pt(sheetWidth - cy - width / 2)
|
|
534
|
+
},
|
|
535
|
+
posV: {
|
|
536
|
+
relativeFrom: "page",
|
|
537
|
+
offsetPt: pt(cx - height / 2)
|
|
538
|
+
}
|
|
539
|
+
};
|
|
540
|
+
};
|
|
541
|
+
const quarter = (rotation60k) => ((rotation60k ?? 0) + 90 * 6e4) % (360 * 6e4);
|
|
542
|
+
if (el.kind === "image" && el.image.float) {
|
|
543
|
+
const float = onto(el.image.float, el.image.width, el.image.height);
|
|
544
|
+
if (!float) return el;
|
|
545
|
+
return {
|
|
546
|
+
...el,
|
|
547
|
+
image: {
|
|
548
|
+
...el.image,
|
|
549
|
+
float,
|
|
550
|
+
rotation60k: quarter(el.image.rotation60k)
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
}
|
|
554
|
+
if (el.kind === "shape" && el.shape.float) {
|
|
555
|
+
const float = onto(el.shape.float, el.shape.width, el.shape.height);
|
|
556
|
+
if (!float) return el;
|
|
557
|
+
const rotation60k = quarter(el.shape.transform?.rotation60k);
|
|
558
|
+
return {
|
|
559
|
+
...el,
|
|
560
|
+
shape: {
|
|
561
|
+
...el.shape,
|
|
562
|
+
float,
|
|
563
|
+
transform: {
|
|
564
|
+
...el.shape.transform,
|
|
565
|
+
rotation60k
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
}
|
|
570
|
+
return el;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
359
573
|
* §8.4.3.6 — a page's dash pattern as DrawingML states one (§20.1.8.21
|
|
360
574
|
* `a:custDash`): dash and gap in turn, as multiples of the pen's width.
|
|
361
575
|
*
|
|
@@ -579,24 +793,129 @@ function withMeasuredMargins(section, shown, pageRuns, pageMarks = [], foot = []
|
|
|
579
793
|
};
|
|
580
794
|
}
|
|
581
795
|
/**
|
|
796
|
+
* The runs set in a face the page KERNED or LIGATED, marked so (see
|
|
797
|
+
* `pageSpacing`, `FaceOutlines.ligatures`): a word processor kerns nothing a
|
|
798
|
+
* run does not ask it to, and set unkerned, a line kerned on the page runs
|
|
799
|
+
* longer than it did there; a ligature the embedded face carries is formed
|
|
800
|
+
* where the run asks for its face's ligatures.
|
|
801
|
+
*
|
|
802
|
+
* @param blocks The blocks to mark, tables and text boxes within them too.
|
|
803
|
+
* @param typeset Run font name → what its runs ask for.
|
|
804
|
+
* @returns The blocks, their runs in those faces asking for it.
|
|
805
|
+
*/
|
|
806
|
+
function typesetRuns(blocks, typeset) {
|
|
807
|
+
if (typeset.size === 0) return [...blocks];
|
|
808
|
+
const shape = (s) => ({
|
|
809
|
+
...s,
|
|
810
|
+
...s.text ? { text: {
|
|
811
|
+
...s.text,
|
|
812
|
+
content: typesetRuns(s.text.content, typeset)
|
|
813
|
+
} } : {},
|
|
814
|
+
...s.children ? { children: s.children.map((child) => ({
|
|
815
|
+
...child,
|
|
816
|
+
shape: shape(child.shape)
|
|
817
|
+
})) } : {}
|
|
818
|
+
});
|
|
819
|
+
return blocks.map((el) => {
|
|
820
|
+
if (el.kind === "paragraph") {
|
|
821
|
+
const runs = el.paragraph.runs.map((run) => {
|
|
822
|
+
const face = run.properties.fontFamily?.ascii;
|
|
823
|
+
const asked = face !== void 0 ? typeset.get(face) : void 0;
|
|
824
|
+
return asked ? {
|
|
825
|
+
...run,
|
|
826
|
+
properties: {
|
|
827
|
+
...run.properties,
|
|
828
|
+
...asked
|
|
829
|
+
}
|
|
830
|
+
} : run;
|
|
831
|
+
});
|
|
832
|
+
return {
|
|
833
|
+
...el,
|
|
834
|
+
paragraph: {
|
|
835
|
+
...el.paragraph,
|
|
836
|
+
runs
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
if (el.kind === "table") {
|
|
841
|
+
const rows = el.table.rows.map((row) => ({
|
|
842
|
+
...row,
|
|
843
|
+
cells: row.cells.map((cell) => ({
|
|
844
|
+
...cell,
|
|
845
|
+
content: typesetRuns(cell.content, typeset)
|
|
846
|
+
}))
|
|
847
|
+
}));
|
|
848
|
+
return {
|
|
849
|
+
...el,
|
|
850
|
+
table: {
|
|
851
|
+
...el.table,
|
|
852
|
+
rows
|
|
853
|
+
}
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
if (el.kind === "shape") return {
|
|
857
|
+
...el,
|
|
858
|
+
shape: shape(el.shape)
|
|
859
|
+
};
|
|
860
|
+
return el;
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* What each face's runs ask for: kerning where the page kerned the face, and
|
|
865
|
+
* its standard ligatures where the page drew one of them (the ligatures the
|
|
866
|
+
* face's embedded font then forms are exactly the ones the page drew).
|
|
867
|
+
*
|
|
868
|
+
* @param kerned The run font names of the faces the page kerned.
|
|
869
|
+
* @param faceOutlines Run font name → the face's outlines, ligatures among them.
|
|
870
|
+
*/
|
|
871
|
+
function typesetting(kerned, faceOutlines) {
|
|
872
|
+
const out = /* @__PURE__ */ new Map();
|
|
873
|
+
for (const face of kerned) out.set(face, { kerningMinPt: KERN_FROM_PT });
|
|
874
|
+
for (const [face, outlines] of faceOutlines ?? []) if (outlines.ligatures && outlines.ligatures.size > 0) out.set(face, {
|
|
875
|
+
...out.get(face),
|
|
876
|
+
ligatures: "standard"
|
|
877
|
+
});
|
|
878
|
+
return out;
|
|
879
|
+
}
|
|
880
|
+
/** §17.3.2.19 — kerned from one point up: at every size a page is set in. */
|
|
881
|
+
var KERN_FROM_PT = pt(1);
|
|
882
|
+
/**
|
|
582
883
|
* Assemble the final {@link FlowDoc} for a reconstruction: the body elements
|
|
583
884
|
* with their styles resolved against the empty style sheet, the lifted-image
|
|
584
885
|
* resource store, and the optional page {@link SectionProperties}. Shared by
|
|
585
886
|
* both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
|
|
586
887
|
* path EP4).
|
|
587
888
|
*/
|
|
588
|
-
function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts, sections = [], headersFooters, faceFamilies) {
|
|
889
|
+
function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts, sections = [], headersFooters, faceFamilies, faceOutlines, kerned = /* @__PURE__ */ new Set()) {
|
|
890
|
+
const typeset = typesetting(kerned, faceOutlines);
|
|
891
|
+
const bands = headersFooters && typeset.size > 0 ? new Map([...headersFooters].map(([id, blocks]) => [id, typesetRuns(blocks, typeset)])) : headersFooters;
|
|
589
892
|
return {
|
|
590
893
|
kind: "flow",
|
|
591
|
-
body: resolveBodyStyles(
|
|
894
|
+
body: resolveBodyStyles(typesetRuns(body, typeset), RECONSTRUCTION_SHEET),
|
|
592
895
|
sections,
|
|
593
|
-
...
|
|
896
|
+
...bands && bands.size > 0 ? { headersFooters: bands } : {},
|
|
594
897
|
...section ? { section } : {},
|
|
595
898
|
...embeddedFonts && embeddedFonts.size > 0 ? { embeddedFonts } : {},
|
|
596
899
|
...faceFamilies && faceFamilies.size > 0 ? { faceFamilies } : {},
|
|
900
|
+
...faceOutlines && faceOutlines.size > 0 ? { faceOutlines } : {},
|
|
901
|
+
compatibilityMode: CURRENT_WORD_LAYOUT,
|
|
597
902
|
styles: EMPTY_STYLE_SHEET,
|
|
598
903
|
resources
|
|
599
904
|
};
|
|
600
905
|
}
|
|
906
|
+
/** [MS-DOCX] `compatibilityMode` 15 — Word 2013's layout, a current Word's. */
|
|
907
|
+
var CURRENT_WORD_LAYOUT = 15;
|
|
908
|
+
/**
|
|
909
|
+
* §17.3.1.44 — the sheet a reconstruction's paragraphs resolve against: the
|
|
910
|
+
* empty one, with widow control off. Every source page opens a page of its
|
|
911
|
+
* own, and the page already broke its paragraphs where it did; where a
|
|
912
|
+
* reconstructed column runs a line long, widow control — on wherever nothing
|
|
913
|
+
* says otherwise — carries a second line over with it, and the column after
|
|
914
|
+
* runs longer still.
|
|
915
|
+
*/
|
|
916
|
+
var RECONSTRUCTION_SHEET = {
|
|
917
|
+
...EMPTY_STYLE_SHEET,
|
|
918
|
+
defaultParagraphProperties: { widowControl: false }
|
|
919
|
+
};
|
|
601
920
|
//#endregion
|
|
602
|
-
export { BASELINE_AT, CARRIER_LINE_PT, GUESSED_MARGIN, NATURAL_LINE_EM, buildFlowDoc, dedupeLosses, imageBlock, paragraphBlock, paragraphFromRuns, positionedText, sectionFromPdfPages, shapeBlock, spaceAfter, textSizeOf, tooSmallToRead, withMeasuredMargins };
|
|
921
|
+
export { ASCENDER, BASELINE_AT, CARRIER_LINE_PT, GUESSED_MARGIN, NATURAL_LINE_EM, buildFlowDoc, dedupeLosses, figureBlock, floatOntoSheet, imageBlock, imageMember, labelMember, membersBox, paragraphBlock, paragraphFromRuns, positionedText, sectionFromPdfPages, sectionOnSheet, shapeBlock, spaceAfter, textSizeOf, tooSmallToRead, vectorMember, withMeasuredMargins };
|