reamkit 1.21.0 → 1.23.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/dist/esm/core/bytes.d.ts +22 -4
- package/dist/esm/core/bytes.js +73 -5
- package/dist/esm/core/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +78 -0
- package/dist/esm/core/drawingml/chart-geometry.js +11 -5
- package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
- package/dist/esm/core/drawingml/chart-parser.js +23 -1
- package/dist/esm/core/drawingml/colors.d.ts +30 -4
- package/dist/esm/core/drawingml/colors.js +45 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +64 -1
- package/dist/esm/core/fonts/families.d.ts +10 -0
- package/dist/esm/core/fonts/families.js +44 -0
- package/dist/esm/core/fonts/index.d.ts +3 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
- package/dist/esm/core/fonts/remote-fonts.js +114 -8
- package/dist/esm/core/fonts/scripts.d.ts +26 -0
- package/dist/esm/core/fonts/scripts.js +177 -0
- package/dist/esm/core/metafile/blit.d.ts +33 -0
- package/dist/esm/core/metafile/blit.js +67 -0
- package/dist/esm/core/metafile/dib.d.ts +61 -0
- package/dist/esm/core/metafile/dib.js +205 -0
- package/dist/esm/core/metafile/emf.js +139 -24
- package/dist/esm/core/metafile/picture.d.ts +12 -1
- package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
- package/dist/esm/core/metafile/symbol-fonts.js +154 -0
- package/dist/esm/core/metafile/wmf.js +183 -10
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +88 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/print-model.js +3 -1
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- package/dist/esm/excel/styles-parser.js +1 -1
- package/dist/esm/excel/xls/biff-reader.js +53 -18
- package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
- package/dist/esm/excel/xls/biff-styles.js +9 -7
- package/dist/esm/excel/xls/escher.js +90 -24
- package/dist/esm/excel/xlsx-reader.d.ts +1 -1
- package/dist/esm/excel/xlsx-reader.js +3 -3
- package/dist/esm/layout/page-doc.d.ts +77 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +467 -76
- package/dist/esm/pdf/shading.d.ts +19 -0
- package/dist/esm/pdf/shading.js +84 -11
- package/dist/esm/pdf/styled-page-emitter.js +647 -444
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
- package/dist/esm/pptx/embedded-fonts.js +104 -0
- package/dist/esm/pptx/ole-preview.d.ts +10 -0
- package/dist/esm/pptx/ole-preview.js +52 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +136 -5
- package/dist/esm/pptx/placeholder-cascade.js +260 -27
- package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
- package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
- package/dist/esm/pptx/ppt/ppt-text.js +576 -137
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +271 -41
- package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
- package/dist/esm/pptx/preset-table-styles.js +27 -0
- package/dist/esm/pptx/slide-parser.d.ts +78 -10
- package/dist/esm/pptx/slide-parser.js +396 -95
- package/dist/esm/pptx/sp-helpers.d.ts +2 -1
- package/dist/esm/pptx/sp-helpers.js +22 -6
- package/dist/esm/pptx/table-style.d.ts +64 -0
- package/dist/esm/pptx/table-style.js +203 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/document-parser.d.ts +7 -1
- package/dist/esm/word/document-parser.js +6 -6
- package/dist/esm/word/docx-reader.js +8 -5
- package/dist/esm/word/docx-to-pdf.d.ts +8 -7
- package/dist/esm/word/docx-to-pdf.js +25 -7
- package/dist/esm/word/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +173 -15
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +6 -6
- package/dist/esm/word/paragraph-properties.d.ts +2 -1
- package/dist/esm/word/paragraph-properties.js +2 -2
- package/dist/esm/word/run-properties.d.ts +5 -2
- package/dist/esm/word/run-properties.js +13 -8
- package/dist/esm/word/styles-parser.d.ts +2 -1
- package/dist/esm/word/styles-parser.js +12 -12
- package/dist/esm/word/table-parser.js +3 -3
- package/dist/esm/word/theme-fonts.d.ts +10 -0
- package/dist/esm/word/theme-fonts.js +28 -0
- package/package.json +1 -1
- /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveFamilyStyle } from "../core/fonts/remote-fonts.js";
|
|
2
|
+
import { scriptForCodepoint } from "../core/fonts/scripts.js";
|
|
2
3
|
import { shapeText } from "../core/font/opentype-layout.js";
|
|
3
4
|
import { createFontMeasure } from "../core/font/measure.js";
|
|
4
5
|
import { halfPtToPt, pt } from "../core/ir/units.js";
|
|
@@ -948,10 +949,11 @@ function layoutBodyElement(el, options, fontResources, imageResources, contentWi
|
|
|
948
949
|
if (el.kind === "paragraph") return layoutParagraphBlock(el.paragraph, options, fontResources, imageResources, contentWidth);
|
|
949
950
|
if (el.kind === "table") return layoutTableBlock(el.table, options, fontResources, imageResources, contentWidth);
|
|
950
951
|
if (el.kind === "image") {
|
|
951
|
-
const
|
|
952
|
-
|
|
952
|
+
const res = el.image.resource ? imageResources?.get(el.image.resource) : void 0;
|
|
953
|
+
const meta = res?.metafile;
|
|
954
|
+
return meta ? layoutMetafileBlock(el.image, meta, res.metafileImages, options, fontResources, contentWidth, maxHeight, box) : layoutImageBlock(el.image, imageResources, contentWidth, maxHeight, box);
|
|
953
955
|
}
|
|
954
|
-
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight);
|
|
956
|
+
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight, imageResources);
|
|
955
957
|
return layoutShapeBlock(el.shape, options, fontResources, imageResources, contentWidth, maxHeight, box);
|
|
956
958
|
}
|
|
957
959
|
function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
|
|
@@ -999,6 +1001,7 @@ function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
|
|
|
999
1001
|
resourceName: res?.resourceName ?? "",
|
|
1000
1002
|
...image.outline ? { outline: image.outline } : {},
|
|
1001
1003
|
...image.wash ? { wash: image.wash } : {},
|
|
1004
|
+
...image.alpha !== void 0 && image.alpha < 1 ? { alpha: image.alpha } : {},
|
|
1002
1005
|
...image.crop ? { crop: image.crop } : {},
|
|
1003
1006
|
...image.rotation60k ? { rotationDeg: image.rotation60k / 6e4 } : {},
|
|
1004
1007
|
...image.flipH ? { flipH: true } : {},
|
|
@@ -1026,9 +1029,9 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1026
1029
|
const fillGradient = shape.fill.kind === "gradient" ? shape.fill.gradient : void 0;
|
|
1027
1030
|
const fillImage = shape.fill.kind === "picture" && shape.fill.imageResource !== void 0 ? imageResources?.get(shape.fill.imageResource) : void 0;
|
|
1028
1031
|
const fillImageResourceName = fillImage?.resourceName;
|
|
1029
|
-
const fillImageTile = shape.fill.kind === "picture" && shape.fill.tiled === true && fillImage?.prepared ? {
|
|
1030
|
-
widthPt: fillImage.prepared.widthPx * 72 / 96,
|
|
1031
|
-
heightPt: fillImage.prepared.heightPx * 72 / 96
|
|
1032
|
+
const fillImageTile = shape.fill.kind === "picture" && shape.fill.tiled === true && fillImage?.prepared ? shape.fill.tileSizePt ?? {
|
|
1033
|
+
widthPt: fillImage.prepared.widthPx * 72 / 96 * (shape.fill.tileScale?.sx ?? 1),
|
|
1034
|
+
heightPt: fillImage.prepared.heightPx * 72 / 96 * (shape.fill.tileScale?.sy ?? 1)
|
|
1032
1035
|
} : void 0;
|
|
1033
1036
|
const fillColorHex = shape.fill.kind === "solid" ? shape.fill.colorHex : fillGradient ? gradientToSolid(fillGradient) : void 0;
|
|
1034
1037
|
const stroke = buildStroke(shape.line);
|
|
@@ -1073,7 +1076,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1073
1076
|
continue;
|
|
1074
1077
|
}
|
|
1075
1078
|
if (el.kind === "chart") {
|
|
1076
|
-
const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth);
|
|
1079
|
+
const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth, void 0, imageResources);
|
|
1077
1080
|
const line = {
|
|
1078
1081
|
tokens: [],
|
|
1079
1082
|
contentWidthPt: laid.widthPt,
|
|
@@ -1185,6 +1188,8 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1185
1188
|
...fillImageResourceName ? { fillImageResourceName } : {},
|
|
1186
1189
|
...fillImageTile ? { fillImageTile } : {},
|
|
1187
1190
|
...fillImageResourceName && shape.fill.imageCrop ? { fillImageCrop: shape.fill.imageCrop } : {},
|
|
1191
|
+
...fillImageResourceName && shape.fill.imageFillRect ? { fillImageRect: shape.fill.imageFillRect } : {},
|
|
1192
|
+
...fillImageResourceName && shape.fill.duotone ? { fillImageDuotone: shape.fill.duotone } : {},
|
|
1188
1193
|
...fillColorHex ? { fillColorHex } : {},
|
|
1189
1194
|
...fillGradient ? { fillGradient } : {},
|
|
1190
1195
|
...shape.fill.alpha !== void 0 && shape.fill.alpha < 1 ? { fillAlpha: shape.fill.alpha } : {},
|
|
@@ -1222,11 +1227,11 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1222
1227
|
* frame. So one is turned into the other rather than growing a block kind, a
|
|
1223
1228
|
* pagination arm and an emitter of its own.
|
|
1224
1229
|
*/
|
|
1225
|
-
function layoutMetafileBlock(image, pic, options, fontResources, contentWidth, maxHeight, box) {
|
|
1230
|
+
function layoutMetafileBlock(image, pic, blitted, options, fontResources, contentWidth, maxHeight, box) {
|
|
1226
1231
|
const placed = layoutImageBlock(image, void 0, contentWidth, maxHeight, box);
|
|
1227
1232
|
const widthPt = placed.widthPt;
|
|
1228
1233
|
const heightPt = placed.heightPt;
|
|
1229
|
-
const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
|
|
1234
|
+
const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources, image.colorChange, blitted), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
|
|
1230
1235
|
const pp = image.paragraphProperties;
|
|
1231
1236
|
return {
|
|
1232
1237
|
kind: "chart",
|
|
@@ -1253,6 +1258,7 @@ function rotateDrawing(layout, deg, cx, cy) {
|
|
|
1253
1258
|
});
|
|
1254
1259
|
return {
|
|
1255
1260
|
shapes: layout.shapes.map((sh) => ({
|
|
1261
|
+
...sh.seq !== void 0 ? { seq: sh.seq } : {},
|
|
1256
1262
|
...sh,
|
|
1257
1263
|
paths: sh.paths.map((path) => ({
|
|
1258
1264
|
...path,
|
|
@@ -1289,7 +1295,16 @@ function rotateDrawing(layout, deg, cx, cy) {
|
|
|
1289
1295
|
y: p.y,
|
|
1290
1296
|
rotationDeg: (t.rotationDeg ?? 0) - deg
|
|
1291
1297
|
};
|
|
1292
|
-
})
|
|
1298
|
+
}),
|
|
1299
|
+
...layout.images ? { images: layout.images.map((img) => {
|
|
1300
|
+
const c = at(img.x + img.width / 2, img.y + img.height / 2);
|
|
1301
|
+
return {
|
|
1302
|
+
...img,
|
|
1303
|
+
x: c.x - img.width / 2,
|
|
1304
|
+
y: c.y - img.height / 2,
|
|
1305
|
+
rotationDeg: (img.rotationDeg ?? 0) + deg
|
|
1306
|
+
};
|
|
1307
|
+
}) } : {}
|
|
1293
1308
|
};
|
|
1294
1309
|
}
|
|
1295
1310
|
/**
|
|
@@ -1297,16 +1312,47 @@ function rotateDrawing(layout, deg, cx, cy) {
|
|
|
1297
1312
|
* `heightPt` one and turned y-up about its bottom-left corner — the frame both
|
|
1298
1313
|
* a chart block and an inline picture token are drawn in.
|
|
1299
1314
|
*/
|
|
1300
|
-
function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
1315
|
+
function metafileDrawing(pic, widthPt, heightPt, options, fontResources, colorChange, blitted) {
|
|
1316
|
+
const recolour = (hex) => {
|
|
1317
|
+
if (hex === void 0 || colorChange === void 0) return hex;
|
|
1318
|
+
if (hex.toUpperCase() !== colorChange.fromHex.toUpperCase()) return hex;
|
|
1319
|
+
return colorChange.transparent ? null : colorChange.toHex;
|
|
1320
|
+
};
|
|
1301
1321
|
const sx = widthPt / pic.width;
|
|
1302
1322
|
const sy = heightPt / pic.height;
|
|
1303
1323
|
const mapX = (x) => (x - pic.left) * sx;
|
|
1304
1324
|
const mapY = (y) => heightPt - (y - pic.top) * sy;
|
|
1305
1325
|
const shapes = [];
|
|
1306
1326
|
const texts = [];
|
|
1327
|
+
const images = [];
|
|
1328
|
+
let seq = 0;
|
|
1329
|
+
let blit = 0;
|
|
1307
1330
|
for (const prim of pic.prims) {
|
|
1331
|
+
if (prim.kind === "image") {
|
|
1332
|
+
const resourceName = blitted?.[blit++] ?? "";
|
|
1333
|
+
if (resourceName === "") {
|
|
1334
|
+
seq++;
|
|
1335
|
+
continue;
|
|
1336
|
+
}
|
|
1337
|
+
images.push({
|
|
1338
|
+
seq: seq++,
|
|
1339
|
+
resourceName,
|
|
1340
|
+
x: mapX(prim.x),
|
|
1341
|
+
y: mapY(prim.y + prim.height),
|
|
1342
|
+
width: prim.width * sx,
|
|
1343
|
+
height: prim.height * sy
|
|
1344
|
+
});
|
|
1345
|
+
continue;
|
|
1346
|
+
}
|
|
1308
1347
|
if (prim.kind === "path") {
|
|
1348
|
+
const fill = recolour(prim.fillColorHex);
|
|
1349
|
+
const strokeHex = recolour(prim.stroke?.colorHex);
|
|
1350
|
+
if (fill === null && (prim.stroke === void 0 || strokeHex === null)) {
|
|
1351
|
+
seq++;
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1309
1354
|
shapes.push({
|
|
1355
|
+
seq: seq++,
|
|
1310
1356
|
paths: prim.paths.map((path) => ({
|
|
1311
1357
|
...path,
|
|
1312
1358
|
segments: path.segments.map((seg) => seg.op === "close" ? seg : seg.op === "cubic" ? {
|
|
@@ -1323,23 +1369,29 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
|
1323
1369
|
y: mapY(seg.y)
|
|
1324
1370
|
})
|
|
1325
1371
|
})),
|
|
1326
|
-
...
|
|
1327
|
-
...prim.stroke ? { stroke: {
|
|
1372
|
+
...fill !== void 0 && fill !== null ? { fillColorHex: fill } : {},
|
|
1373
|
+
...prim.stroke && strokeHex !== null ? { stroke: {
|
|
1328
1374
|
...prim.stroke,
|
|
1375
|
+
...strokeHex !== void 0 ? { colorHex: strokeHex } : {},
|
|
1329
1376
|
widthPt: Math.max(.25, prim.stroke.widthPt * sx)
|
|
1330
1377
|
} } : {}
|
|
1331
1378
|
});
|
|
1332
1379
|
continue;
|
|
1333
1380
|
}
|
|
1334
|
-
if (prim.kind !== "text") continue;
|
|
1335
1381
|
const { variant } = options.registry.resolveByStyle(prim.bold === true, prim.italic === true);
|
|
1336
1382
|
const font = fontResources.get(variant);
|
|
1337
1383
|
if (!font) continue;
|
|
1338
1384
|
const sizePt = Math.max(1, prim.sizeLu * sy);
|
|
1339
|
-
const
|
|
1385
|
+
const textHex = recolour(prim.colorHex);
|
|
1386
|
+
if (textHex === null) {
|
|
1387
|
+
seq++;
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
const line = makeChartLabelLine(prim.text, font, sizePt, textHex ?? prim.colorHex);
|
|
1340
1391
|
const shift = prim.alignH === "center" ? -line.contentWidthPt / 2 : prim.alignH === "right" ? -line.contentWidthPt : 0;
|
|
1341
1392
|
const baselineY = mapY(prim.y) - (prim.alignBaseline ? 0 : sizePt * .8);
|
|
1342
1393
|
texts.push({
|
|
1394
|
+
seq: seq++,
|
|
1343
1395
|
line,
|
|
1344
1396
|
x: mapX(prim.x) + shift,
|
|
1345
1397
|
y: baselineY,
|
|
@@ -1348,10 +1400,11 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
|
1348
1400
|
}
|
|
1349
1401
|
return {
|
|
1350
1402
|
shapes,
|
|
1351
|
-
texts
|
|
1403
|
+
texts,
|
|
1404
|
+
...images.length > 0 ? { images } : {}
|
|
1352
1405
|
};
|
|
1353
1406
|
}
|
|
1354
|
-
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight) {
|
|
1407
|
+
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight, imageResources) {
|
|
1355
1408
|
let widthPt = block.width;
|
|
1356
1409
|
let heightPt = block.height;
|
|
1357
1410
|
if (widthPt > contentWidth && widthPt > 0) {
|
|
@@ -1373,11 +1426,20 @@ function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight
|
|
|
1373
1426
|
};
|
|
1374
1427
|
const pp = block.paragraphProperties;
|
|
1375
1428
|
const altText = block.altText ?? chart?.title;
|
|
1429
|
+
const bgRes = chart?.frameFillImage ? imageResources?.get(chart.frameFillImage.resource) : void 0;
|
|
1430
|
+
const bgTile = chart?.frameFillImage?.tiled === true && bgRes?.prepared ? {
|
|
1431
|
+
widthPt: bgRes.prepared.widthPx * 72 / 96,
|
|
1432
|
+
heightPt: bgRes.prepared.heightPx * 72 / 96
|
|
1433
|
+
} : void 0;
|
|
1376
1434
|
return {
|
|
1377
1435
|
kind: "chart",
|
|
1378
1436
|
widthPt,
|
|
1379
1437
|
heightPt,
|
|
1380
1438
|
layout,
|
|
1439
|
+
...bgRes ? { background: {
|
|
1440
|
+
resourceName: bgRes.resourceName,
|
|
1441
|
+
...bgTile ? { tile: bgTile } : {}
|
|
1442
|
+
} } : {},
|
|
1381
1443
|
resolvedAlignment: pp.alignment ?? "left",
|
|
1382
1444
|
spacingBeforePt: pp.spacingBefore ?? 0,
|
|
1383
1445
|
spacingAfterPt: pp.spacingAfter ?? 0,
|
|
@@ -1653,6 +1715,7 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1653
1715
|
}
|
|
1654
1716
|
};
|
|
1655
1717
|
visit(body);
|
|
1718
|
+
for (const chart of options.charts?.values() ?? []) if (chart.frameFillImage) seen.add(chart.frameFillImage.resource);
|
|
1656
1719
|
if (options.pageBackgroundFill?.imageResource !== void 0) seen.add(options.pageBackgroundFill.imageResource);
|
|
1657
1720
|
for (const hf of headersFooters.values()) visit(hf);
|
|
1658
1721
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
@@ -1665,9 +1728,29 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1665
1728
|
if (!bytes) continue;
|
|
1666
1729
|
if (isEmf(bytes) || isWmf(bytes)) {
|
|
1667
1730
|
try {
|
|
1731
|
+
const metafile = isEmf(bytes) ? readEmf(bytes) : readWmf(bytes);
|
|
1732
|
+
const metafileImages = [];
|
|
1733
|
+
for (const prim of metafile.prims) {
|
|
1734
|
+
if (prim.kind !== "image") continue;
|
|
1735
|
+
let blitted;
|
|
1736
|
+
try {
|
|
1737
|
+
blitted = prepareImage(prim.png, { flattenAlpha });
|
|
1738
|
+
} catch {
|
|
1739
|
+
metafileImages.push("");
|
|
1740
|
+
continue;
|
|
1741
|
+
}
|
|
1742
|
+
counter++;
|
|
1743
|
+
const name = `Im${counter}`;
|
|
1744
|
+
metafileImages.push(name);
|
|
1745
|
+
out.set(`${resourceId}#${String(metafileImages.length)}`, {
|
|
1746
|
+
resourceName: name,
|
|
1747
|
+
prepared: blitted
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1668
1750
|
out.set(resourceId, {
|
|
1669
1751
|
resourceName: "",
|
|
1670
|
-
metafile
|
|
1752
|
+
metafile,
|
|
1753
|
+
...metafileImages.length > 0 ? { metafileImages } : {}
|
|
1671
1754
|
});
|
|
1672
1755
|
} catch {}
|
|
1673
1756
|
continue;
|
|
@@ -1688,8 +1771,47 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1688
1771
|
}
|
|
1689
1772
|
function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
|
|
1690
1773
|
const fig = structId !== void 0 ? { structId } : {};
|
|
1691
|
-
const
|
|
1692
|
-
|
|
1774
|
+
const ordered = laid.layout.shapes.some((sh) => sh.seq !== void 0) || (laid.layout.images?.length ?? 0) > 0;
|
|
1775
|
+
const picture = ordered ? { pictureId: nextPictureId++ } : {};
|
|
1776
|
+
const backdrop = [];
|
|
1777
|
+
if (laid.background) {
|
|
1778
|
+
const box = {
|
|
1779
|
+
x,
|
|
1780
|
+
y: pageHeight - (bottomYUp + laid.heightPt),
|
|
1781
|
+
width: laid.widthPt,
|
|
1782
|
+
height: laid.heightPt
|
|
1783
|
+
};
|
|
1784
|
+
const tile = laid.background.tile;
|
|
1785
|
+
const clip = {
|
|
1786
|
+
paths: [rectPath(laid.widthPt, laid.heightPt)],
|
|
1787
|
+
transform: flipTransform([
|
|
1788
|
+
1,
|
|
1789
|
+
0,
|
|
1790
|
+
0,
|
|
1791
|
+
1,
|
|
1792
|
+
x,
|
|
1793
|
+
bottomYUp
|
|
1794
|
+
], pageHeight)
|
|
1795
|
+
};
|
|
1796
|
+
const items = tile ? PageAssembler.tileItems(laid.background.resourceName, tile, box) : [{
|
|
1797
|
+
type: "image",
|
|
1798
|
+
x: pt(box.x),
|
|
1799
|
+
y: pt(box.y),
|
|
1800
|
+
width: pt(box.width),
|
|
1801
|
+
height: pt(box.height),
|
|
1802
|
+
imageResourceName: laid.background.resourceName
|
|
1803
|
+
}];
|
|
1804
|
+
for (const item of items) {
|
|
1805
|
+
if (item.type !== "image") continue;
|
|
1806
|
+
backdrop.push({
|
|
1807
|
+
...item,
|
|
1808
|
+
clip,
|
|
1809
|
+
...fig,
|
|
1810
|
+
...picture
|
|
1811
|
+
});
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
const shapes = laid.layout.shapes.map((sh) => ({
|
|
1693
1815
|
type: "shape",
|
|
1694
1816
|
shape: {
|
|
1695
1817
|
paths: sh.paths,
|
|
@@ -1704,18 +1826,41 @@ function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
|
|
|
1704
1826
|
bottomYUp
|
|
1705
1827
|
], pageHeight)
|
|
1706
1828
|
},
|
|
1707
|
-
...fig
|
|
1708
|
-
|
|
1709
|
-
|
|
1829
|
+
...fig,
|
|
1830
|
+
...picture,
|
|
1831
|
+
seq: sh.seq ?? 0
|
|
1832
|
+
}));
|
|
1833
|
+
const texts = laid.layout.texts.map((t) => ({
|
|
1710
1834
|
type: "line",
|
|
1711
1835
|
line: t.line,
|
|
1712
1836
|
originX: pt(x + t.x),
|
|
1713
1837
|
baselineY: pt(pageHeight - (bottomYUp + t.y)),
|
|
1714
1838
|
...t.rotationDeg ? { rotationDeg: t.rotationDeg } : {},
|
|
1715
|
-
...fig
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
}
|
|
1839
|
+
...fig,
|
|
1840
|
+
...picture,
|
|
1841
|
+
seq: t.seq ?? Number.MAX_SAFE_INTEGER
|
|
1842
|
+
}));
|
|
1843
|
+
const blits = (laid.layout.images ?? []).map((img) => ({
|
|
1844
|
+
type: "image",
|
|
1845
|
+
x: pt(x + img.x),
|
|
1846
|
+
y: pt(pageHeight - (bottomYUp + img.y + img.height)),
|
|
1847
|
+
width: pt(img.width),
|
|
1848
|
+
height: pt(img.height),
|
|
1849
|
+
imageResourceName: img.resourceName,
|
|
1850
|
+
...img.rotationDeg ? { rotationDeg: img.rotationDeg } : {},
|
|
1851
|
+
...fig,
|
|
1852
|
+
...picture,
|
|
1853
|
+
seq: img.seq ?? 0
|
|
1854
|
+
}));
|
|
1855
|
+
const all = [
|
|
1856
|
+
...shapes,
|
|
1857
|
+
...texts,
|
|
1858
|
+
...blits
|
|
1859
|
+
];
|
|
1860
|
+
if (ordered) all.sort((a, b) => a.seq - b.seq);
|
|
1861
|
+
return [...backdrop, ...all.map(({ seq: _seq, ...item }) => item)];
|
|
1862
|
+
}
|
|
1863
|
+
var nextPictureId = 1;
|
|
1719
1864
|
function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
1720
1865
|
if (sh.textLines.length === 0) return;
|
|
1721
1866
|
if (sh.vertical) {
|
|
@@ -1767,10 +1912,11 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1767
1912
|
}
|
|
1768
1913
|
return;
|
|
1769
1914
|
}
|
|
1915
|
+
const indentLeft = line.resolved.indentLeft + (line.firstLine ? line.resolved.indentFirstLine : 0);
|
|
1770
1916
|
sink.push({
|
|
1771
1917
|
type: "line",
|
|
1772
1918
|
line,
|
|
1773
|
-
originX: pt(x + sh.insetLeftPt + lineOffset),
|
|
1919
|
+
originX: pt(x + sh.insetLeftPt + indentLeft + lineOffset),
|
|
1774
1920
|
baselineY: pt(pageHeight - (textY + lineBaselineOffset(line, line.resolved))),
|
|
1775
1921
|
...figId !== void 0 ? { structId: figId } : {}
|
|
1776
1922
|
});
|
|
@@ -1806,6 +1952,7 @@ function emitCellFloat(cf, ctx, frame) {
|
|
|
1806
1952
|
imageResourceName: cf.block.resourceName,
|
|
1807
1953
|
...cf.block.crop ? { crop: cf.block.crop } : {},
|
|
1808
1954
|
...cf.block.wash ? { wash: cf.block.wash } : {},
|
|
1955
|
+
...cf.block.alpha !== void 0 ? { alpha: cf.block.alpha } : {},
|
|
1809
1956
|
...cf.block.rotationDeg ? { rotationDeg: cf.block.rotationDeg } : {},
|
|
1810
1957
|
...cf.block.flipH ? { flipH: true } : {},
|
|
1811
1958
|
...cf.block.flipV ? { flipV: true } : {}
|
|
@@ -1832,20 +1979,30 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1832
1979
|
sink.push({
|
|
1833
1980
|
...item,
|
|
1834
1981
|
clip,
|
|
1982
|
+
...fig,
|
|
1983
|
+
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {}
|
|
1984
|
+
});
|
|
1985
|
+
}
|
|
1986
|
+
else {
|
|
1987
|
+
const r = sh.fillImageRect;
|
|
1988
|
+
const boxX = x + (r ? r.left * sh.widthPt : 0);
|
|
1989
|
+
const boxW = sh.widthPt * (r ? 1 - r.left - r.right : 1);
|
|
1990
|
+
const boxH = sh.heightPt * (r ? 1 - r.top - r.bottom : 1);
|
|
1991
|
+
const boxTop = pageHeight - (bottomYUp + sh.heightPt) + (r ? r.top * sh.heightPt : 0);
|
|
1992
|
+
sink.push({
|
|
1993
|
+
type: "image",
|
|
1994
|
+
x: pt(boxX),
|
|
1995
|
+
y: pt(boxTop),
|
|
1996
|
+
width: pt(boxW),
|
|
1997
|
+
height: pt(boxH),
|
|
1998
|
+
imageResourceName: sh.fillImageResourceName,
|
|
1999
|
+
...sh.fillImageCrop ? { crop: sh.fillImageCrop } : {},
|
|
2000
|
+
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {},
|
|
2001
|
+
...sh.fillImageDuotone ? { duotone: sh.fillImageDuotone } : {},
|
|
2002
|
+
clip,
|
|
1835
2003
|
...fig
|
|
1836
2004
|
});
|
|
1837
2005
|
}
|
|
1838
|
-
else sink.push({
|
|
1839
|
-
type: "image",
|
|
1840
|
-
x: pt(x),
|
|
1841
|
-
y: pt(pageHeight - (bottomYUp + sh.heightPt)),
|
|
1842
|
-
width: pt(sh.widthPt),
|
|
1843
|
-
height: pt(sh.heightPt),
|
|
1844
|
-
imageResourceName: sh.fillImageResourceName,
|
|
1845
|
-
...sh.fillImageCrop ? { crop: sh.fillImageCrop } : {},
|
|
1846
|
-
clip,
|
|
1847
|
-
...fig
|
|
1848
|
-
});
|
|
1849
2006
|
}
|
|
1850
2007
|
if (sh.markerPaths && sh.stroke) sink.push({
|
|
1851
2008
|
type: "shape",
|
|
@@ -1982,6 +2139,7 @@ function drawBlocksSequentially(blocks, startX, startY, pageHeight, contentWidth
|
|
|
1982
2139
|
imageResourceName: block.resourceName,
|
|
1983
2140
|
...block.crop ? { crop: block.crop } : {},
|
|
1984
2141
|
...block.wash ? { wash: block.wash } : {},
|
|
2142
|
+
...block.alpha !== void 0 ? { alpha: block.alpha } : {},
|
|
1985
2143
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
1986
2144
|
...block.flipH ? { flipH: true } : {},
|
|
1987
2145
|
...block.flipV ? { flipV: true } : {}
|
|
@@ -2080,24 +2238,197 @@ function runFontKeyAndParsed(options, ascii, bold, italic) {
|
|
|
2080
2238
|
}
|
|
2081
2239
|
const byFamily = options.registriesByFamily;
|
|
2082
2240
|
if (byFamily && byFamily.size > 0) {
|
|
2083
|
-
|
|
2241
|
+
const named = resolveFamilyStyle(ascii);
|
|
2242
|
+
let key = named.key;
|
|
2084
2243
|
let reg = byFamily.get(key);
|
|
2085
2244
|
if (!reg) {
|
|
2086
2245
|
key = byFamily.keys().next().value;
|
|
2087
2246
|
reg = byFamily.get(key);
|
|
2088
2247
|
}
|
|
2089
|
-
const
|
|
2248
|
+
const wantBold = bold || named.bold === true;
|
|
2249
|
+
const wantItalic = italic || named.italic === true;
|
|
2250
|
+
const { variant, parsed } = reg.resolveByStyle(wantBold, wantItalic);
|
|
2090
2251
|
return {
|
|
2091
2252
|
fontKey: `${key}:${variant}`,
|
|
2092
|
-
parsed
|
|
2253
|
+
parsed,
|
|
2254
|
+
...syntheticFace(variant, wantBold, wantItalic, named.widthScale)
|
|
2093
2255
|
};
|
|
2094
2256
|
}
|
|
2095
2257
|
const { variant, parsed } = options.registry.resolveByStyle(bold, italic);
|
|
2096
2258
|
return {
|
|
2097
2259
|
fontKey: variant,
|
|
2098
|
-
parsed
|
|
2260
|
+
parsed,
|
|
2261
|
+
...syntheticFace(variant, bold, italic, resolveFamilyStyle(ascii).widthScale)
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
/**
|
|
2265
|
+
* The face a CHARACTER falls back to when the run's own has no glyph for it.
|
|
2266
|
+
*
|
|
2267
|
+
* The curated substitutes are Latin families: Han, Kana, Hangul, Arabic, Thai
|
|
2268
|
+
* and the geometric symbols are a notdef box in every one of them, and 2145
|
|
2269
|
+
* characters of the corpus are exactly those. A face for the character's
|
|
2270
|
+
* writing system is fetched when the document holds one (see `addScriptFonts`),
|
|
2271
|
+
* and this is where a run reaches it — followed by every other family already
|
|
2272
|
+
* loaded, because a glyph one of them happens to carry is still better than a
|
|
2273
|
+
* box.
|
|
2274
|
+
*
|
|
2275
|
+
* Called from BOTH walks that need it — the glyph-subset collection and the
|
|
2276
|
+
* tokenizer — so the face a character is measured, subset and drawn with is one
|
|
2277
|
+
* decision made once.
|
|
2278
|
+
*
|
|
2279
|
+
* @param options The render options (the loaded registries).
|
|
2280
|
+
* @param cp The code point with no glyph in the run's own face.
|
|
2281
|
+
* @param bold Whether the run is bold…
|
|
2282
|
+
* @param italic …and whether it is italic.
|
|
2283
|
+
* @returns The face to draw it with, or `undefined` when nobody has it.
|
|
2284
|
+
*/
|
|
2285
|
+
function fallbackFaceKey(options, cp, bold, italic) {
|
|
2286
|
+
const byFamily = options.registriesByFamily;
|
|
2287
|
+
if (!byFamily || byFamily.size === 0) return void 0;
|
|
2288
|
+
const script = scriptForCodepoint(cp, byFamily.has("jp") ? "jp" : byFamily.has("kr") ? "kr" : "sc");
|
|
2289
|
+
const order = script ? [script] : [];
|
|
2290
|
+
for (const key of byFamily.keys()) if (key !== script) order.push(key);
|
|
2291
|
+
for (const key of order) {
|
|
2292
|
+
const reg = byFamily.get(key);
|
|
2293
|
+
if (!reg) continue;
|
|
2294
|
+
const { variant, parsed } = reg.resolveByStyle(bold, italic);
|
|
2295
|
+
if (parsed.glyphForCodepoint(cp) !== 0) return {
|
|
2296
|
+
fontKey: `${key}:${variant}`,
|
|
2297
|
+
parsed
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
/**
|
|
2302
|
+
* §9.2.2 — the face a request had to settle for, and what is left to draw.
|
|
2303
|
+
*
|
|
2304
|
+
* A registry may hold one face and be asked for four: `FontBytesByVariant`
|
|
2305
|
+
* requires only `regular`, so a caller who supplies a single file (or a script
|
|
2306
|
+
* fallback with no bold cut) had every heading drawn plain. What the file does
|
|
2307
|
+
* not carry, the page draws: a stroke around the glyphs for weight, a shear for
|
|
2308
|
+
* slant — the same two tricks a word processor calls faux bold and faux italic.
|
|
2309
|
+
*
|
|
2310
|
+
* @param variant The face the registry actually gave.
|
|
2311
|
+
* @param bold Whether bold was asked for.
|
|
2312
|
+
* @param italic Whether italic was.
|
|
2313
|
+
* @param widthScale The squeeze a condensed NAME asks for, when it does.
|
|
2314
|
+
* @returns `{ synthetic }` when something is missing, `{}` when nothing is.
|
|
2315
|
+
*/
|
|
2316
|
+
function syntheticFace(variant, bold, italic, widthScale) {
|
|
2317
|
+
const missingBold = bold && variant !== "bold" && variant !== "boldItalic";
|
|
2318
|
+
const missingItalic = italic && variant !== "italic" && variant !== "boldItalic";
|
|
2319
|
+
if (!missingBold && !missingItalic && widthScale === void 0) return {};
|
|
2320
|
+
return { synthetic: {
|
|
2321
|
+
...missingBold ? { bold: true } : {},
|
|
2322
|
+
...missingItalic ? { italic: true } : {},
|
|
2323
|
+
...widthScale !== void 0 ? { widthScale } : {}
|
|
2324
|
+
} };
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* `text` cut into the stretches ONE face draws — the whole string as a single
|
|
2328
|
+
* piece when the run's own face covers it, which is nearly always.
|
|
2329
|
+
*
|
|
2330
|
+
* @param plan The run being tokenized.
|
|
2331
|
+
* @param text The stretch of it to cut.
|
|
2332
|
+
*/
|
|
2333
|
+
function splitByFace(plan, text) {
|
|
2334
|
+
const first = faceOf(plan, text.codePointAt(0) ?? 0);
|
|
2335
|
+
if (!plan.faceFor || plan.faceFor.size === 0) return [{
|
|
2336
|
+
text,
|
|
2337
|
+
face: first
|
|
2338
|
+
}];
|
|
2339
|
+
const out = [];
|
|
2340
|
+
let buf = "";
|
|
2341
|
+
let face = first;
|
|
2342
|
+
for (const ch of text) {
|
|
2343
|
+
const next = faceOf(plan, ch.codePointAt(0));
|
|
2344
|
+
if (buf !== "" && next.font !== face.font) {
|
|
2345
|
+
out.push({
|
|
2346
|
+
text: buf,
|
|
2347
|
+
face
|
|
2348
|
+
});
|
|
2349
|
+
buf = "";
|
|
2350
|
+
}
|
|
2351
|
+
face = next;
|
|
2352
|
+
buf += ch;
|
|
2353
|
+
}
|
|
2354
|
+
if (buf !== "") out.push({
|
|
2355
|
+
text: buf,
|
|
2356
|
+
face
|
|
2357
|
+
});
|
|
2358
|
+
return out;
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* The face a character of a run is drawn with — its own, unless the run carries
|
|
2362
|
+
* a fallback for that code point (see {@link facesForRun}).
|
|
2363
|
+
*/
|
|
2364
|
+
function faceOf(plan, cp) {
|
|
2365
|
+
return plan.faceFor?.get(cp) ?? {
|
|
2366
|
+
font: plan.font,
|
|
2367
|
+
...plan.synthetic ? { synthetic: plan.synthetic } : {}
|
|
2099
2368
|
};
|
|
2100
2369
|
}
|
|
2370
|
+
/**
|
|
2371
|
+
* `text` cut into the stretches ONE face draws, by the same decision the
|
|
2372
|
+
* tokenizer makes — the whole string as a single span when the run's own face
|
|
2373
|
+
* covers it, which is nearly always.
|
|
2374
|
+
*
|
|
2375
|
+
* @param options The render options (the loaded registries).
|
|
2376
|
+
* @param primary The run's own face.
|
|
2377
|
+
* @param resolved Its resolved properties (weight and slant).
|
|
2378
|
+
* @param text The run's text.
|
|
2379
|
+
*/
|
|
2380
|
+
function faceSpans(options, primary, resolved, text) {
|
|
2381
|
+
const out = [];
|
|
2382
|
+
let cur = primary;
|
|
2383
|
+
let buf = "";
|
|
2384
|
+
for (const ch of text) {
|
|
2385
|
+
const cp = ch.codePointAt(0);
|
|
2386
|
+
const face = primary.parsed.glyphForCodepoint(cp) !== 0 ? primary : fallbackFaceKey(options, cp, resolved.bold, resolved.italic) ?? primary;
|
|
2387
|
+
if (buf !== "" && face.fontKey !== cur.fontKey) {
|
|
2388
|
+
out.push({
|
|
2389
|
+
...cur,
|
|
2390
|
+
text: buf
|
|
2391
|
+
});
|
|
2392
|
+
buf = "";
|
|
2393
|
+
}
|
|
2394
|
+
cur = face;
|
|
2395
|
+
buf += ch;
|
|
2396
|
+
}
|
|
2397
|
+
if (buf !== "") out.push({
|
|
2398
|
+
...cur,
|
|
2399
|
+
text: buf
|
|
2400
|
+
});
|
|
2401
|
+
return out;
|
|
2402
|
+
}
|
|
2403
|
+
/**
|
|
2404
|
+
* The face for every character of `text` the run's own cannot draw.
|
|
2405
|
+
*
|
|
2406
|
+
* @param options The render options (the loaded registries).
|
|
2407
|
+
* @param fontResources The faces the document embeds, by key.
|
|
2408
|
+
* @param primary The run's own face.
|
|
2409
|
+
* @param resolved Its resolved properties (weight and slant).
|
|
2410
|
+
* @param text The run's text.
|
|
2411
|
+
* @returns A map from code point to face, or `undefined` when the run's own
|
|
2412
|
+
* face draws all of it.
|
|
2413
|
+
*/
|
|
2414
|
+
function facesForRun(options, fontResources, primary, resolved, text) {
|
|
2415
|
+
let out;
|
|
2416
|
+
for (const ch of text) {
|
|
2417
|
+
const cp = ch.codePointAt(0);
|
|
2418
|
+
if (out?.has(cp) === true || primary.glyphForCodepoint(cp) !== 0) continue;
|
|
2419
|
+
const fallback = fallbackFaceKey(options, cp, resolved.bold, resolved.italic);
|
|
2420
|
+
if (!fallback) continue;
|
|
2421
|
+
const font = fontResources.get(fallback.fontKey);
|
|
2422
|
+
if (!font) continue;
|
|
2423
|
+
out ??= /* @__PURE__ */ new Map();
|
|
2424
|
+
const { variant } = { variant: fallback.fontKey.split(":")[1] ?? "" };
|
|
2425
|
+
out.set(cp, {
|
|
2426
|
+
font,
|
|
2427
|
+
...syntheticFace(variant === "bold" || variant === "boldItalic" || variant === "italic" ? variant : "regular", resolved.bold, resolved.italic)
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
return out;
|
|
2431
|
+
}
|
|
2101
2432
|
function lookupFont(resources, fontKey) {
|
|
2102
2433
|
return resources.get(fontKey) ?? resources.values().next().value;
|
|
2103
2434
|
}
|
|
@@ -2114,8 +2445,22 @@ function collectFontResources(body, headersFooters, options, imageResources) {
|
|
|
2114
2445
|
};
|
|
2115
2446
|
used.set(fontKey, bucket);
|
|
2116
2447
|
}
|
|
2117
|
-
const
|
|
2118
|
-
for (const
|
|
2448
|
+
const text = run.listMarker === true ? markerText(run.text, parsed) : run.text;
|
|
2449
|
+
for (const span of faceSpans(options, {
|
|
2450
|
+
fontKey,
|
|
2451
|
+
parsed
|
|
2452
|
+
}, resolved, text)) {
|
|
2453
|
+
let sink = used.get(span.fontKey);
|
|
2454
|
+
if (!sink) {
|
|
2455
|
+
sink = {
|
|
2456
|
+
parsed: span.parsed,
|
|
2457
|
+
gids: /* @__PURE__ */ new Set()
|
|
2458
|
+
};
|
|
2459
|
+
used.set(span.fontKey, sink);
|
|
2460
|
+
}
|
|
2461
|
+
const shaped = shapeText(span.text, span.parsed.glyphForCodepoint, span.parsed.advanceWidths, span.parsed.ligatures, span.parsed.kerning, span.parsed.joiningForms);
|
|
2462
|
+
for (const g of shaped.gids) sink.gids.add(g);
|
|
2463
|
+
}
|
|
2119
2464
|
if (run.text.includes(" ")) for (const stop of resolveParagraphProperties(para.properties, options.styles).tabs) {
|
|
2120
2465
|
const ch = stop.leader === void 0 ? void 0 : TAB_LEADER_CHARS.get(stop.leader);
|
|
2121
2466
|
if (ch !== void 0) bucket.gids.add(parsed.glyphForCodepoint(ch.codePointAt(0)));
|
|
@@ -2485,7 +2830,7 @@ function tokenizeParagraph(paragraph, options, fontResources, imageResources, co
|
|
|
2485
2830
|
imageWidthPt: widthPt,
|
|
2486
2831
|
imageHeightPt: heightPt,
|
|
2487
2832
|
imageResourceName: res?.resourceName ?? "",
|
|
2488
|
-
...res?.metafile ? { imageMetafile: metafileDrawing(res.metafile, drawBox?.widthPt ?? widthPt, drawBox?.heightPt ?? heightPt, options, fontResources) } : {},
|
|
2833
|
+
...res?.metafile ? { imageMetafile: metafileDrawing(res.metafile, drawBox?.widthPt ?? widthPt, drawBox?.heightPt ?? heightPt, options, fontResources, void 0, res.metafileImages) } : {},
|
|
2489
2834
|
...run.inlineImage.outline ? { imageOutline: run.inlineImage.outline } : {},
|
|
2490
2835
|
...run.inlineImage.shadow ? { imageShadow: run.inlineImage.shadow } : {},
|
|
2491
2836
|
...run.inlineImage.wash ? { imageWash: run.inlineImage.wash } : {},
|
|
@@ -2525,12 +2870,16 @@ function tokenizeParagraph(paragraph, options, fontResources, imageResources, co
|
|
|
2525
2870
|
};
|
|
2526
2871
|
}
|
|
2527
2872
|
const resolvedRun = resolveRunProperties(run.properties, paragraph.properties, options.styles);
|
|
2528
|
-
const { fontKey } = runFontKeyAndParsed(options, resolvedRun.fontFamily.ascii, resolvedRun.bold, resolvedRun.italic);
|
|
2873
|
+
const { fontKey, synthetic } = runFontKeyAndParsed(options, resolvedRun.fontFamily.ascii, resolvedRun.bold, resolvedRun.italic);
|
|
2529
2874
|
const script = SCRIPT_OFFSET[resolvedRun.verticalAlign] ?? 0;
|
|
2875
|
+
const own = lookupFont(fontResources, fontKey);
|
|
2876
|
+
const faceFor = facesForRun(options, fontResources, own.parsed, resolvedRun, run.text);
|
|
2530
2877
|
return {
|
|
2531
2878
|
run,
|
|
2532
2879
|
resolvedRun,
|
|
2533
|
-
font:
|
|
2880
|
+
font: own,
|
|
2881
|
+
...faceFor ? { faceFor } : {},
|
|
2882
|
+
...synthetic ? { synthetic } : {},
|
|
2534
2883
|
fontSizePt: script === 0 ? resolvedRun.fontSizePt : resolvedRun.fontSizePt * SCRIPT_SCALE,
|
|
2535
2884
|
...script === 0 ? {} : { risePt: resolvedRun.fontSizePt * script },
|
|
2536
2885
|
isImage: false,
|
|
@@ -2597,28 +2946,56 @@ function tokenizePlansLtr(plans) {
|
|
|
2597
2946
|
continue;
|
|
2598
2947
|
}
|
|
2599
2948
|
const highlight = (plan.run.commentRangeRefs?.length ?? 0) > 0;
|
|
2600
|
-
for (const t of tokenizeText(plan.run.text))
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2949
|
+
for (const t of tokenizeText(plan.run.text)) for (const piece of splitByFace(plan, t.text)) {
|
|
2950
|
+
const text = plan.run.listMarker === true ? markerText(piece.text, plan.font.parsed) : piece.text;
|
|
2951
|
+
tokens.push({
|
|
2952
|
+
kind: "text",
|
|
2953
|
+
text,
|
|
2954
|
+
isSpace: t.isSpace,
|
|
2955
|
+
...t.tab ? { tab: true } : {},
|
|
2956
|
+
...plan.run.href !== void 0 ? { href: plan.run.href } : {},
|
|
2957
|
+
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
2958
|
+
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
2959
|
+
...plan.run.listMarker ? { listMarker: true } : {},
|
|
2960
|
+
...plan.run.columnBreak ? { columnBreak: true } : {},
|
|
2961
|
+
...highlight ? { highlight: true } : {},
|
|
2962
|
+
resolvedRun: plan.resolvedRun,
|
|
2963
|
+
font: piece.face.font,
|
|
2964
|
+
...piece.face.synthetic ? { synthetic: piece.face.synthetic } : {},
|
|
2965
|
+
fontSizePt: plan.fontSizePt,
|
|
2966
|
+
...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
|
|
2967
|
+
widthPt: measureRunText(plan, text, piece.face),
|
|
2968
|
+
bidiLevel: 0
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2618
2971
|
}
|
|
2619
2972
|
return tokens;
|
|
2620
2973
|
}
|
|
2621
2974
|
/**
|
|
2975
|
+
* A LIST MARKER the font has no glyph for, swapped for the dot every text font
|
|
2976
|
+
* carries.
|
|
2977
|
+
*
|
|
2978
|
+
* §21.1.2.4.5 — a bullet is stated in a face of its own, and the symbol faces
|
|
2979
|
+
* are not alphabets: Wingdings `l` is a filled circle, U+25CF once translated.
|
|
2980
|
+
* The font a document is RENDERED with may have no such character — Roboto does
|
|
2981
|
+
* not — and a missing glyph is a box: 45541_Header wore a row of them down
|
|
2982
|
+
* eleven slides. The marker is the one place where the shape matters more than
|
|
2983
|
+
* the code point, so it takes the nearest thing the font can draw.
|
|
2984
|
+
*
|
|
2985
|
+
* @param text The marker's text.
|
|
2986
|
+
* @param font The font it is set in.
|
|
2987
|
+
* @returns The text to draw.
|
|
2988
|
+
*/
|
|
2989
|
+
function markerText(text, parsed) {
|
|
2990
|
+
let out = "";
|
|
2991
|
+
for (const ch of text) {
|
|
2992
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
2993
|
+
const missing = cp > 127 && parsed.glyphForCodepoint(cp) === 0;
|
|
2994
|
+
out += missing && parsed.glyphForCodepoint(8226) !== 0 ? "•" : ch;
|
|
2995
|
+
}
|
|
2996
|
+
return out;
|
|
2997
|
+
}
|
|
2998
|
+
/**
|
|
2622
2999
|
* §17.3.2.35 — a run's text measured with the space it puts between its
|
|
2623
3000
|
* characters. PDF adds the same amount per glyph through `Tc`, so the width the
|
|
2624
3001
|
* line is broken at and the width the page draws agree.
|
|
@@ -2627,8 +3004,12 @@ function tokenizePlansLtr(plans) {
|
|
|
2627
3004
|
* @param text The token's text.
|
|
2628
3005
|
* @returns The advance width in points.
|
|
2629
3006
|
*/
|
|
2630
|
-
function measureRunText(plan, text) {
|
|
2631
|
-
const
|
|
3007
|
+
function measureRunText(plan, text, face) {
|
|
3008
|
+
const drawn = face ?? {
|
|
3009
|
+
font: plan.font,
|
|
3010
|
+
...plan.synthetic ? { synthetic: plan.synthetic } : {}
|
|
3011
|
+
};
|
|
3012
|
+
const base = drawn.font.measure.textWidthPt(text, plan.fontSizePt) * (drawn.synthetic?.widthScale ?? 1);
|
|
2632
3013
|
const extra = plan.resolvedRun.letterSpacingPt;
|
|
2633
3014
|
return extra === void 0 || extra === 0 ? base : base + extra * [...text].length;
|
|
2634
3015
|
}
|
|
@@ -2675,9 +3056,11 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
2675
3056
|
let bufStart = 0;
|
|
2676
3057
|
let curSpace = false;
|
|
2677
3058
|
let curLevel = -1;
|
|
3059
|
+
let curFace = { font: plan.font };
|
|
2678
3060
|
const flush = (endExclusive) => {
|
|
2679
3061
|
if (endExclusive <= bufStart) return;
|
|
2680
|
-
const
|
|
3062
|
+
const raw = chars.slice(bufStart, endExclusive).join("");
|
|
3063
|
+
const text = plan.run.listMarker === true ? markerText(raw, plan.font.parsed) : raw;
|
|
2681
3064
|
tokens.push({
|
|
2682
3065
|
kind: "text",
|
|
2683
3066
|
text,
|
|
@@ -2689,10 +3072,11 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
2689
3072
|
...plan.run.columnBreak ? { columnBreak: true } : {},
|
|
2690
3073
|
...(plan.run.commentRangeRefs?.length ?? 0) > 0 ? { highlight: true } : {},
|
|
2691
3074
|
resolvedRun: plan.resolvedRun,
|
|
2692
|
-
font:
|
|
3075
|
+
font: curFace.font,
|
|
3076
|
+
...curFace.synthetic ? { synthetic: curFace.synthetic } : {},
|
|
2693
3077
|
fontSizePt: plan.fontSizePt,
|
|
2694
3078
|
...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
|
|
2695
|
-
widthPt: measureRunText(plan, text),
|
|
3079
|
+
widthPt: measureRunText(plan, text, curFace),
|
|
2696
3080
|
bidiLevel: curLevel
|
|
2697
3081
|
});
|
|
2698
3082
|
};
|
|
@@ -2700,14 +3084,17 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
2700
3084
|
const ch = chars[c];
|
|
2701
3085
|
const isSpace = /\s/.test(ch);
|
|
2702
3086
|
const level = realLevels[realIdx] ?? 0;
|
|
3087
|
+
const face = faceOf(plan, ch.codePointAt(0));
|
|
2703
3088
|
if (c === 0) {
|
|
2704
3089
|
curSpace = isSpace;
|
|
2705
3090
|
curLevel = level;
|
|
2706
|
-
|
|
3091
|
+
curFace = face;
|
|
3092
|
+
} else if (isSpace !== curSpace || level !== curLevel || face.font !== curFace.font) {
|
|
2707
3093
|
flush(c);
|
|
2708
3094
|
bufStart = c;
|
|
2709
3095
|
curSpace = isSpace;
|
|
2710
3096
|
curLevel = level;
|
|
3097
|
+
curFace = face;
|
|
2711
3098
|
}
|
|
2712
3099
|
realIdx++;
|
|
2713
3100
|
}
|
|
@@ -3535,10 +3922,10 @@ function measureSingleLine(paragraph, options, fontResources) {
|
|
|
3535
3922
|
let total = 0;
|
|
3536
3923
|
for (const run of paragraph.runs) {
|
|
3537
3924
|
const resolved = resolveRunProperties(run.properties, paragraph.properties, options.styles);
|
|
3538
|
-
const { fontKey } = runFontKeyAndParsed(options, resolved.fontFamily.ascii, resolved.bold, resolved.italic);
|
|
3925
|
+
const { fontKey, synthetic } = runFontKeyAndParsed(options, resolved.fontFamily.ascii, resolved.bold, resolved.italic);
|
|
3539
3926
|
const font = lookupFont(fontResources, fontKey);
|
|
3540
3927
|
const fontSizePt = resolved.fontSizePt;
|
|
3541
|
-
total += font.measure.textWidthPt(run.text, fontSizePt);
|
|
3928
|
+
total += font.measure.textWidthPt(run.text, fontSizePt) * (synthetic?.widthScale ?? 1);
|
|
3542
3929
|
}
|
|
3543
3930
|
return total;
|
|
3544
3931
|
}
|
|
@@ -4328,7 +4715,10 @@ var PageAssembler = class PageAssembler {
|
|
|
4328
4715
|
...this.pageBorderItems(),
|
|
4329
4716
|
...this.columnSeparatorItems(),
|
|
4330
4717
|
...header.commands,
|
|
4331
|
-
...PageAssembler.byZ(this.floatsBehind)
|
|
4718
|
+
...PageAssembler.byZ(this.floatsBehind).map((item) => ({
|
|
4719
|
+
...item,
|
|
4720
|
+
behind: true
|
|
4721
|
+
})),
|
|
4332
4722
|
...this.current,
|
|
4333
4723
|
...PageAssembler.byZ(this.floatsFront),
|
|
4334
4724
|
...this.renderNotesBand(),
|
|
@@ -4701,6 +5091,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4701
5091
|
imageResourceName: block.resourceName,
|
|
4702
5092
|
...block.crop ? { crop: block.crop } : {},
|
|
4703
5093
|
...block.wash ? { wash: block.wash } : {},
|
|
5094
|
+
...block.alpha !== void 0 ? { alpha: block.alpha } : {},
|
|
4704
5095
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
4705
5096
|
...block.flipH ? { flipH: true } : {},
|
|
4706
5097
|
...block.flipV ? { flipV: true } : {},
|