reamkit 1.20.0 → 1.22.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/crypto/offcrypto.d.ts +1 -0
- package/dist/esm/core/crypto/offcrypto.js +2 -1
- package/dist/esm/core/document-model/types.d.ts +60 -0
- 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 +27 -3
- package/dist/esm/core/drawingml/colors.js +30 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/metafile/emf.js +2 -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 +35 -2
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- package/dist/esm/excel/xlsx-reader.d.ts +1 -1
- package/dist/esm/excel/xlsx-reader.js +3 -3
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +38 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.js +174 -49
- 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 +614 -444
- 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 +69 -5
- package/dist/esm/pptx/placeholder-cascade.js +162 -25
- package/dist/esm/pptx/pptx-reader.js +247 -39
- package/dist/esm/pptx/slide-parser.d.ts +72 -10
- package/dist/esm/pptx/slide-parser.js +310 -82
- package/dist/esm/pptx/sp-helpers.js +19 -4
- package/dist/esm/pptx/table-style.d.ts +56 -0
- package/dist/esm/pptx/table-style.js +161 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/docx-reader.js +2 -2
- package/dist/esm/word/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +159 -13
- package/package.json +1 -1
|
@@ -5,30 +5,46 @@ function paintPlan(commands) {
|
|
|
5
5
|
const borders = [];
|
|
6
6
|
const shapes = [];
|
|
7
7
|
const lines = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
const pictures = /* @__PURE__ */ new Map();
|
|
9
|
+
const behind = [];
|
|
10
|
+
for (const c of commands) {
|
|
11
|
+
if (c.behind === true) {
|
|
12
|
+
behind.push(c);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (c.pictureId !== void 0) {
|
|
16
|
+
const group = pictures.get(c.pictureId);
|
|
17
|
+
if (group) group.push(c);
|
|
18
|
+
else pictures.set(c.pictureId, [c]);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
switch (c.type) {
|
|
22
|
+
case "fill":
|
|
23
|
+
fills.push(c);
|
|
24
|
+
break;
|
|
25
|
+
case "image":
|
|
26
|
+
images.push(c);
|
|
27
|
+
break;
|
|
28
|
+
case "border":
|
|
29
|
+
borders.push(c);
|
|
30
|
+
break;
|
|
31
|
+
case "shape":
|
|
32
|
+
shapes.push(c);
|
|
33
|
+
break;
|
|
34
|
+
case "line":
|
|
35
|
+
lines.push(c);
|
|
36
|
+
break;
|
|
37
|
+
default: assertNeverPageItem(c);
|
|
38
|
+
}
|
|
25
39
|
}
|
|
26
40
|
return {
|
|
41
|
+
behind,
|
|
27
42
|
fills,
|
|
28
43
|
images,
|
|
29
44
|
borders,
|
|
30
45
|
shapes,
|
|
31
|
-
lines
|
|
46
|
+
lines,
|
|
47
|
+
pictures: [...pictures.values()]
|
|
32
48
|
};
|
|
33
49
|
}
|
|
34
50
|
function assertNeverPageItem(item) {
|
|
@@ -951,7 +951,7 @@ function layoutBodyElement(el, options, fontResources, imageResources, contentWi
|
|
|
951
951
|
const meta = el.image.resource ? imageResources?.get(el.image.resource)?.metafile : void 0;
|
|
952
952
|
return meta ? layoutMetafileBlock(el.image, meta, options, fontResources, contentWidth, maxHeight, box) : layoutImageBlock(el.image, imageResources, contentWidth, maxHeight, box);
|
|
953
953
|
}
|
|
954
|
-
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight);
|
|
954
|
+
if (el.kind === "chart") return layoutChartBlock(el.chart, options, fontResources, contentWidth, maxHeight, imageResources);
|
|
955
955
|
return layoutShapeBlock(el.shape, options, fontResources, imageResources, contentWidth, maxHeight, box);
|
|
956
956
|
}
|
|
957
957
|
function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
|
|
@@ -999,6 +999,7 @@ function layoutImageBlock(image, imageResources, contentWidth, maxHeight, box) {
|
|
|
999
999
|
resourceName: res?.resourceName ?? "",
|
|
1000
1000
|
...image.outline ? { outline: image.outline } : {},
|
|
1001
1001
|
...image.wash ? { wash: image.wash } : {},
|
|
1002
|
+
...image.alpha !== void 0 && image.alpha < 1 ? { alpha: image.alpha } : {},
|
|
1002
1003
|
...image.crop ? { crop: image.crop } : {},
|
|
1003
1004
|
...image.rotation60k ? { rotationDeg: image.rotation60k / 6e4 } : {},
|
|
1004
1005
|
...image.flipH ? { flipH: true } : {},
|
|
@@ -1073,7 +1074,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1073
1074
|
continue;
|
|
1074
1075
|
}
|
|
1075
1076
|
if (el.kind === "chart") {
|
|
1076
|
-
const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth);
|
|
1077
|
+
const laid = layoutChartBlock(el.chart, options, fontResources, innerWidth, void 0, imageResources);
|
|
1077
1078
|
const line = {
|
|
1078
1079
|
tokens: [],
|
|
1079
1080
|
contentWidthPt: laid.widthPt,
|
|
@@ -1185,6 +1186,8 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1185
1186
|
...fillImageResourceName ? { fillImageResourceName } : {},
|
|
1186
1187
|
...fillImageTile ? { fillImageTile } : {},
|
|
1187
1188
|
...fillImageResourceName && shape.fill.imageCrop ? { fillImageCrop: shape.fill.imageCrop } : {},
|
|
1189
|
+
...fillImageResourceName && shape.fill.imageFillRect ? { fillImageRect: shape.fill.imageFillRect } : {},
|
|
1190
|
+
...fillImageResourceName && shape.fill.duotone ? { fillImageDuotone: shape.fill.duotone } : {},
|
|
1188
1191
|
...fillColorHex ? { fillColorHex } : {},
|
|
1189
1192
|
...fillGradient ? { fillGradient } : {},
|
|
1190
1193
|
...shape.fill.alpha !== void 0 && shape.fill.alpha < 1 ? { fillAlpha: shape.fill.alpha } : {},
|
|
@@ -1226,7 +1229,7 @@ function layoutMetafileBlock(image, pic, options, fontResources, contentWidth, m
|
|
|
1226
1229
|
const placed = layoutImageBlock(image, void 0, contentWidth, maxHeight, box);
|
|
1227
1230
|
const widthPt = placed.widthPt;
|
|
1228
1231
|
const heightPt = placed.heightPt;
|
|
1229
|
-
const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
|
|
1232
|
+
const layout = rotateDrawing(metafileDrawing(pic, widthPt, heightPt, options, fontResources, image.colorChange), (image.rotation60k ?? 0) / 6e4, widthPt / 2, heightPt / 2);
|
|
1230
1233
|
const pp = image.paragraphProperties;
|
|
1231
1234
|
return {
|
|
1232
1235
|
kind: "chart",
|
|
@@ -1253,6 +1256,7 @@ function rotateDrawing(layout, deg, cx, cy) {
|
|
|
1253
1256
|
});
|
|
1254
1257
|
return {
|
|
1255
1258
|
shapes: layout.shapes.map((sh) => ({
|
|
1259
|
+
...sh.seq !== void 0 ? { seq: sh.seq } : {},
|
|
1256
1260
|
...sh,
|
|
1257
1261
|
paths: sh.paths.map((path) => ({
|
|
1258
1262
|
...path,
|
|
@@ -1297,16 +1301,29 @@ function rotateDrawing(layout, deg, cx, cy) {
|
|
|
1297
1301
|
* `heightPt` one and turned y-up about its bottom-left corner — the frame both
|
|
1298
1302
|
* a chart block and an inline picture token are drawn in.
|
|
1299
1303
|
*/
|
|
1300
|
-
function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
1304
|
+
function metafileDrawing(pic, widthPt, heightPt, options, fontResources, colorChange) {
|
|
1305
|
+
const recolour = (hex) => {
|
|
1306
|
+
if (hex === void 0 || colorChange === void 0) return hex;
|
|
1307
|
+
if (hex.toUpperCase() !== colorChange.fromHex.toUpperCase()) return hex;
|
|
1308
|
+
return colorChange.transparent ? null : colorChange.toHex;
|
|
1309
|
+
};
|
|
1301
1310
|
const sx = widthPt / pic.width;
|
|
1302
1311
|
const sy = heightPt / pic.height;
|
|
1303
1312
|
const mapX = (x) => (x - pic.left) * sx;
|
|
1304
1313
|
const mapY = (y) => heightPt - (y - pic.top) * sy;
|
|
1305
1314
|
const shapes = [];
|
|
1306
1315
|
const texts = [];
|
|
1316
|
+
let seq = 0;
|
|
1307
1317
|
for (const prim of pic.prims) {
|
|
1308
1318
|
if (prim.kind === "path") {
|
|
1319
|
+
const fill = recolour(prim.fillColorHex);
|
|
1320
|
+
const strokeHex = recolour(prim.stroke?.colorHex);
|
|
1321
|
+
if (fill === null && (prim.stroke === void 0 || strokeHex === null)) {
|
|
1322
|
+
seq++;
|
|
1323
|
+
continue;
|
|
1324
|
+
}
|
|
1309
1325
|
shapes.push({
|
|
1326
|
+
seq: seq++,
|
|
1310
1327
|
paths: prim.paths.map((path) => ({
|
|
1311
1328
|
...path,
|
|
1312
1329
|
segments: path.segments.map((seg) => seg.op === "close" ? seg : seg.op === "cubic" ? {
|
|
@@ -1323,9 +1340,10 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
|
1323
1340
|
y: mapY(seg.y)
|
|
1324
1341
|
})
|
|
1325
1342
|
})),
|
|
1326
|
-
...
|
|
1327
|
-
...prim.stroke ? { stroke: {
|
|
1343
|
+
...fill !== void 0 && fill !== null ? { fillColorHex: fill } : {},
|
|
1344
|
+
...prim.stroke && strokeHex !== null ? { stroke: {
|
|
1328
1345
|
...prim.stroke,
|
|
1346
|
+
...strokeHex !== void 0 ? { colorHex: strokeHex } : {},
|
|
1329
1347
|
widthPt: Math.max(.25, prim.stroke.widthPt * sx)
|
|
1330
1348
|
} } : {}
|
|
1331
1349
|
});
|
|
@@ -1336,10 +1354,16 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
|
1336
1354
|
const font = fontResources.get(variant);
|
|
1337
1355
|
if (!font) continue;
|
|
1338
1356
|
const sizePt = Math.max(1, prim.sizeLu * sy);
|
|
1339
|
-
const
|
|
1357
|
+
const textHex = recolour(prim.colorHex);
|
|
1358
|
+
if (textHex === null) {
|
|
1359
|
+
seq++;
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
const line = makeChartLabelLine(prim.text, font, sizePt, textHex ?? prim.colorHex);
|
|
1340
1363
|
const shift = prim.alignH === "center" ? -line.contentWidthPt / 2 : prim.alignH === "right" ? -line.contentWidthPt : 0;
|
|
1341
1364
|
const baselineY = mapY(prim.y) - (prim.alignBaseline ? 0 : sizePt * .8);
|
|
1342
1365
|
texts.push({
|
|
1366
|
+
seq: seq++,
|
|
1343
1367
|
line,
|
|
1344
1368
|
x: mapX(prim.x) + shift,
|
|
1345
1369
|
y: baselineY,
|
|
@@ -1351,7 +1375,7 @@ function metafileDrawing(pic, widthPt, heightPt, options, fontResources) {
|
|
|
1351
1375
|
texts
|
|
1352
1376
|
};
|
|
1353
1377
|
}
|
|
1354
|
-
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight) {
|
|
1378
|
+
function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight, imageResources) {
|
|
1355
1379
|
let widthPt = block.width;
|
|
1356
1380
|
let heightPt = block.height;
|
|
1357
1381
|
if (widthPt > contentWidth && widthPt > 0) {
|
|
@@ -1373,11 +1397,20 @@ function layoutChartBlock(block, options, fontResources, contentWidth, maxHeight
|
|
|
1373
1397
|
};
|
|
1374
1398
|
const pp = block.paragraphProperties;
|
|
1375
1399
|
const altText = block.altText ?? chart?.title;
|
|
1400
|
+
const bgRes = chart?.frameFillImage ? imageResources?.get(chart.frameFillImage.resource) : void 0;
|
|
1401
|
+
const bgTile = chart?.frameFillImage?.tiled === true && bgRes?.prepared ? {
|
|
1402
|
+
widthPt: bgRes.prepared.widthPx * 72 / 96,
|
|
1403
|
+
heightPt: bgRes.prepared.heightPx * 72 / 96
|
|
1404
|
+
} : void 0;
|
|
1376
1405
|
return {
|
|
1377
1406
|
kind: "chart",
|
|
1378
1407
|
widthPt,
|
|
1379
1408
|
heightPt,
|
|
1380
1409
|
layout,
|
|
1410
|
+
...bgRes ? { background: {
|
|
1411
|
+
resourceName: bgRes.resourceName,
|
|
1412
|
+
...bgTile ? { tile: bgTile } : {}
|
|
1413
|
+
} } : {},
|
|
1381
1414
|
resolvedAlignment: pp.alignment ?? "left",
|
|
1382
1415
|
spacingBeforePt: pp.spacingBefore ?? 0,
|
|
1383
1416
|
spacingAfterPt: pp.spacingAfter ?? 0,
|
|
@@ -1653,6 +1686,7 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1653
1686
|
}
|
|
1654
1687
|
};
|
|
1655
1688
|
visit(body);
|
|
1689
|
+
for (const chart of options.charts?.values() ?? []) if (chart.frameFillImage) seen.add(chart.frameFillImage.resource);
|
|
1656
1690
|
if (options.pageBackgroundFill?.imageResource !== void 0) seen.add(options.pageBackgroundFill.imageResource);
|
|
1657
1691
|
for (const hf of headersFooters.values()) visit(hf);
|
|
1658
1692
|
for (const note of options.footnotes?.values() ?? []) visit(note);
|
|
@@ -1688,8 +1722,47 @@ function collectImageResources(body, headersFooters, options) {
|
|
|
1688
1722
|
}
|
|
1689
1723
|
function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
|
|
1690
1724
|
const fig = structId !== void 0 ? { structId } : {};
|
|
1691
|
-
const
|
|
1692
|
-
|
|
1725
|
+
const ordered = laid.layout.shapes.some((sh) => sh.seq !== void 0);
|
|
1726
|
+
const picture = ordered ? { pictureId: nextPictureId++ } : {};
|
|
1727
|
+
const backdrop = [];
|
|
1728
|
+
if (laid.background) {
|
|
1729
|
+
const box = {
|
|
1730
|
+
x,
|
|
1731
|
+
y: pageHeight - (bottomYUp + laid.heightPt),
|
|
1732
|
+
width: laid.widthPt,
|
|
1733
|
+
height: laid.heightPt
|
|
1734
|
+
};
|
|
1735
|
+
const tile = laid.background.tile;
|
|
1736
|
+
const clip = {
|
|
1737
|
+
paths: [rectPath(laid.widthPt, laid.heightPt)],
|
|
1738
|
+
transform: flipTransform([
|
|
1739
|
+
1,
|
|
1740
|
+
0,
|
|
1741
|
+
0,
|
|
1742
|
+
1,
|
|
1743
|
+
x,
|
|
1744
|
+
bottomYUp
|
|
1745
|
+
], pageHeight)
|
|
1746
|
+
};
|
|
1747
|
+
const items = tile ? PageAssembler.tileItems(laid.background.resourceName, tile, box) : [{
|
|
1748
|
+
type: "image",
|
|
1749
|
+
x: pt(box.x),
|
|
1750
|
+
y: pt(box.y),
|
|
1751
|
+
width: pt(box.width),
|
|
1752
|
+
height: pt(box.height),
|
|
1753
|
+
imageResourceName: laid.background.resourceName
|
|
1754
|
+
}];
|
|
1755
|
+
for (const item of items) {
|
|
1756
|
+
if (item.type !== "image") continue;
|
|
1757
|
+
backdrop.push({
|
|
1758
|
+
...item,
|
|
1759
|
+
clip,
|
|
1760
|
+
...fig,
|
|
1761
|
+
...picture
|
|
1762
|
+
});
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
const shapes = laid.layout.shapes.map((sh) => ({
|
|
1693
1766
|
type: "shape",
|
|
1694
1767
|
shape: {
|
|
1695
1768
|
paths: sh.paths,
|
|
@@ -1704,18 +1777,25 @@ function chartPageItems(laid, x, bottomYUp, pageHeight, structId) {
|
|
|
1704
1777
|
bottomYUp
|
|
1705
1778
|
], pageHeight)
|
|
1706
1779
|
},
|
|
1707
|
-
...fig
|
|
1708
|
-
|
|
1709
|
-
|
|
1780
|
+
...fig,
|
|
1781
|
+
...picture,
|
|
1782
|
+
seq: sh.seq ?? 0
|
|
1783
|
+
}));
|
|
1784
|
+
const texts = laid.layout.texts.map((t) => ({
|
|
1710
1785
|
type: "line",
|
|
1711
1786
|
line: t.line,
|
|
1712
1787
|
originX: pt(x + t.x),
|
|
1713
1788
|
baselineY: pt(pageHeight - (bottomYUp + t.y)),
|
|
1714
1789
|
...t.rotationDeg ? { rotationDeg: t.rotationDeg } : {},
|
|
1715
|
-
...fig
|
|
1716
|
-
|
|
1717
|
-
|
|
1790
|
+
...fig,
|
|
1791
|
+
...picture,
|
|
1792
|
+
seq: t.seq ?? Number.MAX_SAFE_INTEGER
|
|
1793
|
+
}));
|
|
1794
|
+
const all = [...shapes, ...texts];
|
|
1795
|
+
if (ordered) all.sort((a, b) => a.seq - b.seq);
|
|
1796
|
+
return [...backdrop, ...all.map(({ seq: _seq, ...item }) => item)];
|
|
1718
1797
|
}
|
|
1798
|
+
var nextPictureId = 1;
|
|
1719
1799
|
function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
1720
1800
|
if (sh.textLines.length === 0) return;
|
|
1721
1801
|
if (sh.vertical) {
|
|
@@ -1767,10 +1847,11 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1767
1847
|
}
|
|
1768
1848
|
return;
|
|
1769
1849
|
}
|
|
1850
|
+
const indentLeft = line.resolved.indentLeft + (line.firstLine ? line.resolved.indentFirstLine : 0);
|
|
1770
1851
|
sink.push({
|
|
1771
1852
|
type: "line",
|
|
1772
1853
|
line,
|
|
1773
|
-
originX: pt(x + sh.insetLeftPt + lineOffset),
|
|
1854
|
+
originX: pt(x + sh.insetLeftPt + indentLeft + lineOffset),
|
|
1774
1855
|
baselineY: pt(pageHeight - (textY + lineBaselineOffset(line, line.resolved))),
|
|
1775
1856
|
...figId !== void 0 ? { structId: figId } : {}
|
|
1776
1857
|
});
|
|
@@ -1806,6 +1887,7 @@ function emitCellFloat(cf, ctx, frame) {
|
|
|
1806
1887
|
imageResourceName: cf.block.resourceName,
|
|
1807
1888
|
...cf.block.crop ? { crop: cf.block.crop } : {},
|
|
1808
1889
|
...cf.block.wash ? { wash: cf.block.wash } : {},
|
|
1890
|
+
...cf.block.alpha !== void 0 ? { alpha: cf.block.alpha } : {},
|
|
1809
1891
|
...cf.block.rotationDeg ? { rotationDeg: cf.block.rotationDeg } : {},
|
|
1810
1892
|
...cf.block.flipH ? { flipH: true } : {},
|
|
1811
1893
|
...cf.block.flipV ? { flipV: true } : {}
|
|
@@ -1832,20 +1914,30 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1832
1914
|
sink.push({
|
|
1833
1915
|
...item,
|
|
1834
1916
|
clip,
|
|
1917
|
+
...fig,
|
|
1918
|
+
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {}
|
|
1919
|
+
});
|
|
1920
|
+
}
|
|
1921
|
+
else {
|
|
1922
|
+
const r = sh.fillImageRect;
|
|
1923
|
+
const boxX = x + (r ? r.left * sh.widthPt : 0);
|
|
1924
|
+
const boxW = sh.widthPt * (r ? 1 - r.left - r.right : 1);
|
|
1925
|
+
const boxH = sh.heightPt * (r ? 1 - r.top - r.bottom : 1);
|
|
1926
|
+
const boxTop = pageHeight - (bottomYUp + sh.heightPt) + (r ? r.top * sh.heightPt : 0);
|
|
1927
|
+
sink.push({
|
|
1928
|
+
type: "image",
|
|
1929
|
+
x: pt(boxX),
|
|
1930
|
+
y: pt(boxTop),
|
|
1931
|
+
width: pt(boxW),
|
|
1932
|
+
height: pt(boxH),
|
|
1933
|
+
imageResourceName: sh.fillImageResourceName,
|
|
1934
|
+
...sh.fillImageCrop ? { crop: sh.fillImageCrop } : {},
|
|
1935
|
+
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {},
|
|
1936
|
+
...sh.fillImageDuotone ? { duotone: sh.fillImageDuotone } : {},
|
|
1937
|
+
clip,
|
|
1835
1938
|
...fig
|
|
1836
1939
|
});
|
|
1837
1940
|
}
|
|
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
1941
|
}
|
|
1850
1942
|
if (sh.markerPaths && sh.stroke) sink.push({
|
|
1851
1943
|
type: "shape",
|
|
@@ -1982,6 +2074,7 @@ function drawBlocksSequentially(blocks, startX, startY, pageHeight, contentWidth
|
|
|
1982
2074
|
imageResourceName: block.resourceName,
|
|
1983
2075
|
...block.crop ? { crop: block.crop } : {},
|
|
1984
2076
|
...block.wash ? { wash: block.wash } : {},
|
|
2077
|
+
...block.alpha !== void 0 ? { alpha: block.alpha } : {},
|
|
1985
2078
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
1986
2079
|
...block.flipH ? { flipH: true } : {},
|
|
1987
2080
|
...block.flipV ? { flipV: true } : {}
|
|
@@ -2114,7 +2207,7 @@ function collectFontResources(body, headersFooters, options, imageResources) {
|
|
|
2114
2207
|
};
|
|
2115
2208
|
used.set(fontKey, bucket);
|
|
2116
2209
|
}
|
|
2117
|
-
const shaped = shapeText(run.text, parsed.glyphForCodepoint, parsed.advanceWidths, parsed.ligatures, parsed.kerning, parsed.joiningForms);
|
|
2210
|
+
const shaped = shapeText(run.listMarker === true ? markerText(run.text, parsed) : run.text, parsed.glyphForCodepoint, parsed.advanceWidths, parsed.ligatures, parsed.kerning, parsed.joiningForms);
|
|
2118
2211
|
for (const g of shaped.gids) bucket.gids.add(g);
|
|
2119
2212
|
if (run.text.includes(" ")) for (const stop of resolveParagraphProperties(para.properties, options.styles).tabs) {
|
|
2120
2213
|
const ch = stop.leader === void 0 ? void 0 : TAB_LEADER_CHARS.get(stop.leader);
|
|
@@ -2597,28 +2690,55 @@ function tokenizePlansLtr(plans) {
|
|
|
2597
2690
|
continue;
|
|
2598
2691
|
}
|
|
2599
2692
|
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
|
-
|
|
2693
|
+
for (const t of tokenizeText(plan.run.text)) {
|
|
2694
|
+
const text = plan.run.listMarker === true ? markerText(t.text, plan.font.parsed) : t.text;
|
|
2695
|
+
tokens.push({
|
|
2696
|
+
kind: "text",
|
|
2697
|
+
text,
|
|
2698
|
+
isSpace: t.isSpace,
|
|
2699
|
+
...t.tab ? { tab: true } : {},
|
|
2700
|
+
...plan.run.href !== void 0 ? { href: plan.run.href } : {},
|
|
2701
|
+
...plan.run.footnoteRef !== void 0 ? { footnoteRef: plan.run.footnoteRef } : {},
|
|
2702
|
+
...plan.run.anchor !== void 0 ? { anchor: plan.run.anchor } : {},
|
|
2703
|
+
...plan.run.listMarker ? { listMarker: true } : {},
|
|
2704
|
+
...plan.run.columnBreak ? { columnBreak: true } : {},
|
|
2705
|
+
...highlight ? { highlight: true } : {},
|
|
2706
|
+
resolvedRun: plan.resolvedRun,
|
|
2707
|
+
font: plan.font,
|
|
2708
|
+
fontSizePt: plan.fontSizePt,
|
|
2709
|
+
...plan.risePt !== void 0 ? { risePt: plan.risePt } : {},
|
|
2710
|
+
widthPt: measureRunText(plan, text),
|
|
2711
|
+
bidiLevel: 0
|
|
2712
|
+
});
|
|
2713
|
+
}
|
|
2618
2714
|
}
|
|
2619
2715
|
return tokens;
|
|
2620
2716
|
}
|
|
2621
2717
|
/**
|
|
2718
|
+
* A LIST MARKER the font has no glyph for, swapped for the dot every text font
|
|
2719
|
+
* carries.
|
|
2720
|
+
*
|
|
2721
|
+
* §21.1.2.4.5 — a bullet is stated in a face of its own, and the symbol faces
|
|
2722
|
+
* are not alphabets: Wingdings `l` is a filled circle, U+25CF once translated.
|
|
2723
|
+
* The font a document is RENDERED with may have no such character — Roboto does
|
|
2724
|
+
* not — and a missing glyph is a box: 45541_Header wore a row of them down
|
|
2725
|
+
* eleven slides. The marker is the one place where the shape matters more than
|
|
2726
|
+
* the code point, so it takes the nearest thing the font can draw.
|
|
2727
|
+
*
|
|
2728
|
+
* @param text The marker's text.
|
|
2729
|
+
* @param font The font it is set in.
|
|
2730
|
+
* @returns The text to draw.
|
|
2731
|
+
*/
|
|
2732
|
+
function markerText(text, parsed) {
|
|
2733
|
+
let out = "";
|
|
2734
|
+
for (const ch of text) {
|
|
2735
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
2736
|
+
const missing = cp > 127 && parsed.glyphForCodepoint(cp) === 0;
|
|
2737
|
+
out += missing && parsed.glyphForCodepoint(8226) !== 0 ? "•" : ch;
|
|
2738
|
+
}
|
|
2739
|
+
return out;
|
|
2740
|
+
}
|
|
2741
|
+
/**
|
|
2622
2742
|
* §17.3.2.35 — a run's text measured with the space it puts between its
|
|
2623
2743
|
* characters. PDF adds the same amount per glyph through `Tc`, so the width the
|
|
2624
2744
|
* line is broken at and the width the page draws agree.
|
|
@@ -2677,7 +2797,8 @@ function tokenizePlansBidi(plans, realLevels) {
|
|
|
2677
2797
|
let curLevel = -1;
|
|
2678
2798
|
const flush = (endExclusive) => {
|
|
2679
2799
|
if (endExclusive <= bufStart) return;
|
|
2680
|
-
const
|
|
2800
|
+
const raw = chars.slice(bufStart, endExclusive).join("");
|
|
2801
|
+
const text = plan.run.listMarker === true ? markerText(raw, plan.font.parsed) : raw;
|
|
2681
2802
|
tokens.push({
|
|
2682
2803
|
kind: "text",
|
|
2683
2804
|
text,
|
|
@@ -4328,7 +4449,10 @@ var PageAssembler = class PageAssembler {
|
|
|
4328
4449
|
...this.pageBorderItems(),
|
|
4329
4450
|
...this.columnSeparatorItems(),
|
|
4330
4451
|
...header.commands,
|
|
4331
|
-
...PageAssembler.byZ(this.floatsBehind)
|
|
4452
|
+
...PageAssembler.byZ(this.floatsBehind).map((item) => ({
|
|
4453
|
+
...item,
|
|
4454
|
+
behind: true
|
|
4455
|
+
})),
|
|
4332
4456
|
...this.current,
|
|
4333
4457
|
...PageAssembler.byZ(this.floatsFront),
|
|
4334
4458
|
...this.renderNotesBand(),
|
|
@@ -4701,6 +4825,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
4701
4825
|
imageResourceName: block.resourceName,
|
|
4702
4826
|
...block.crop ? { crop: block.crop } : {},
|
|
4703
4827
|
...block.wash ? { wash: block.wash } : {},
|
|
4828
|
+
...block.alpha !== void 0 ? { alpha: block.alpha } : {},
|
|
4704
4829
|
...block.rotationDeg ? { rotationDeg: block.rotationDeg } : {},
|
|
4705
4830
|
...block.flipH ? { flipH: true } : {},
|
|
4706
4831
|
...block.flipV ? { flipV: true } : {},
|
|
@@ -25,4 +25,23 @@ export declare function shapeBbox(shape: VectorShape): Bbox | undefined;
|
|
|
25
25
|
* @returns A reference to the `/Pattern` object, for a `/Pattern cs /Pn scn` fill.
|
|
26
26
|
*/
|
|
27
27
|
export declare function buildGradientPattern(doc: PdfDocument, gradient: ShapeGradient, bbox: Bbox, ctm: readonly [number, number, number, number, number, number]): PdfRef;
|
|
28
|
+
/**
|
|
29
|
+
* §11.6.5.2 — the luminosity soft mask a gradient with per-stop TRANSPARENCY is
|
|
30
|
+
* painted through.
|
|
31
|
+
*
|
|
32
|
+
* A PDF shading has one colour per point and no alpha, so a gradient that fades
|
|
33
|
+
* out is drawn as the colour shading masked by a second shading of the same
|
|
34
|
+
* geometry whose GREY is the transparency: white where the stop is opaque,
|
|
35
|
+
* black where it is clear. 45541_Footer's master lays a white band down the
|
|
36
|
+
* left of every slide that starts half transparent, and painted flat it covered
|
|
37
|
+
* the artwork behind it.
|
|
38
|
+
*
|
|
39
|
+
* @param doc The document to add the objects to.
|
|
40
|
+
* @param gradient The gradient fill.
|
|
41
|
+
* @param bbox The shape's local-space bounding box.
|
|
42
|
+
* @param ctm The shape's CTM, as the form's `/Matrix`.
|
|
43
|
+
* @returns The mask form XObject, or `undefined` when every stop is opaque or
|
|
44
|
+
* the sweep has no shading type that can carry a mask.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildGradientAlphaMask(doc: PdfDocument, gradient: ShapeGradient, bbox: Bbox, ctm: readonly [number, number, number, number, number, number]): PdfRef | undefined;
|
|
28
47
|
export {};
|
package/dist/esm/pdf/shading.js
CHANGED
|
@@ -49,7 +49,7 @@ function buildGradientPattern(doc, gradient, bbox, ctm) {
|
|
|
49
49
|
Matrix: [...ctm]
|
|
50
50
|
}));
|
|
51
51
|
}
|
|
52
|
-
function axialShading(angleDeg, b, fnRef) {
|
|
52
|
+
function axialShading(angleDeg, b, fnRef, cs = "DeviceRGB") {
|
|
53
53
|
const rad = angleDeg * Math.PI / 180;
|
|
54
54
|
const dx = Math.cos(rad);
|
|
55
55
|
const dy = -Math.sin(rad);
|
|
@@ -70,7 +70,7 @@ function axialShading(angleDeg, b, fnRef) {
|
|
|
70
70
|
}
|
|
71
71
|
return dict({
|
|
72
72
|
ShadingType: 2,
|
|
73
|
-
ColorSpace: name(
|
|
73
|
+
ColorSpace: name(cs),
|
|
74
74
|
Coords: [
|
|
75
75
|
cx + (tmin - cproj) * dx,
|
|
76
76
|
cy + (tmin - cproj) * dy,
|
|
@@ -81,13 +81,13 @@ function axialShading(angleDeg, b, fnRef) {
|
|
|
81
81
|
Extend: [true, true]
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
|
-
function radialShading(b, fnRef, center) {
|
|
84
|
+
function radialShading(b, fnRef, center, cs = "DeviceRGB") {
|
|
85
85
|
const cx = center ? b.minX + center.x * (b.maxX - b.minX) : (b.minX + b.maxX) / 2;
|
|
86
86
|
const cy = center ? b.maxY - center.y * (b.maxY - b.minY) : (b.minY + b.maxY) / 2;
|
|
87
87
|
const r = Math.hypot(b.maxX - b.minX, b.maxY - b.minY) / 2;
|
|
88
88
|
return dict({
|
|
89
89
|
ShadingType: 3,
|
|
90
|
-
ColorSpace: name(
|
|
90
|
+
ColorSpace: name(cs),
|
|
91
91
|
Coords: [
|
|
92
92
|
cx,
|
|
93
93
|
cy,
|
|
@@ -171,6 +171,77 @@ function ps(n) {
|
|
|
171
171
|
const s = n.toFixed(6).replace(/0+$/u, "").replace(/\.$/u, "");
|
|
172
172
|
return s === "" || s === "-0" ? "0" : s;
|
|
173
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* §11.6.5.2 — the luminosity soft mask a gradient with per-stop TRANSPARENCY is
|
|
176
|
+
* painted through.
|
|
177
|
+
*
|
|
178
|
+
* A PDF shading has one colour per point and no alpha, so a gradient that fades
|
|
179
|
+
* out is drawn as the colour shading masked by a second shading of the same
|
|
180
|
+
* geometry whose GREY is the transparency: white where the stop is opaque,
|
|
181
|
+
* black where it is clear. 45541_Footer's master lays a white band down the
|
|
182
|
+
* left of every slide that starts half transparent, and painted flat it covered
|
|
183
|
+
* the artwork behind it.
|
|
184
|
+
*
|
|
185
|
+
* @param doc The document to add the objects to.
|
|
186
|
+
* @param gradient The gradient fill.
|
|
187
|
+
* @param bbox The shape's local-space bounding box.
|
|
188
|
+
* @param ctm The shape's CTM, as the form's `/Matrix`.
|
|
189
|
+
* @returns The mask form XObject, or `undefined` when every stop is opaque or
|
|
190
|
+
* the sweep has no shading type that can carry a mask.
|
|
191
|
+
*/
|
|
192
|
+
function buildGradientAlphaMask(doc, gradient, bbox, ctm) {
|
|
193
|
+
if (!gradient.stops.some((s) => (s.alpha ?? 1) < 1)) return void 0;
|
|
194
|
+
if (gradient.kind === "radial" && gradient.sweep === "rect") return void 0;
|
|
195
|
+
const fn = doc.add(buildAlphaRamp(gradient.stops));
|
|
196
|
+
const shading = gradient.kind === "radial" ? radialShading(bbox, fn, gradient.center, "DeviceGray") : axialShading(gradient.angle ?? 0, bbox, fn, "DeviceGray");
|
|
197
|
+
return doc.add(stream({
|
|
198
|
+
Type: name("XObject"),
|
|
199
|
+
Subtype: name("Form"),
|
|
200
|
+
BBox: [
|
|
201
|
+
bbox.minX,
|
|
202
|
+
bbox.minY,
|
|
203
|
+
bbox.maxX,
|
|
204
|
+
bbox.maxY
|
|
205
|
+
],
|
|
206
|
+
Matrix: [...ctm],
|
|
207
|
+
Group: dict({
|
|
208
|
+
S: name("Transparency"),
|
|
209
|
+
CS: name("DeviceGray")
|
|
210
|
+
}),
|
|
211
|
+
Resources: dict({ Shading: dict({ Sm: doc.add(shading) }) })
|
|
212
|
+
}, new TextEncoder().encode("q /Sm sh Q")));
|
|
213
|
+
}
|
|
214
|
+
function buildAlphaRamp(stopsIn) {
|
|
215
|
+
const stops = normalizeStops(stopsIn);
|
|
216
|
+
if (stops.length <= 2) return dict({
|
|
217
|
+
FunctionType: 2,
|
|
218
|
+
Domain: [0, 1],
|
|
219
|
+
C0: [stops[0].alpha],
|
|
220
|
+
C1: [stops[stops.length - 1].alpha],
|
|
221
|
+
N: 1
|
|
222
|
+
});
|
|
223
|
+
const functions = [];
|
|
224
|
+
const bounds = [];
|
|
225
|
+
const encode = [];
|
|
226
|
+
for (let i = 0; i < stops.length - 1; i++) {
|
|
227
|
+
functions.push(dict({
|
|
228
|
+
FunctionType: 2,
|
|
229
|
+
Domain: [0, 1],
|
|
230
|
+
C0: [stops[i].alpha],
|
|
231
|
+
C1: [stops[i + 1].alpha],
|
|
232
|
+
N: 1
|
|
233
|
+
}));
|
|
234
|
+
if (i > 0) bounds.push(stops[i].offset);
|
|
235
|
+
encode.push(0, 1);
|
|
236
|
+
}
|
|
237
|
+
return dict({
|
|
238
|
+
FunctionType: 3,
|
|
239
|
+
Domain: [0, 1],
|
|
240
|
+
Functions: functions,
|
|
241
|
+
Bounds: bounds,
|
|
242
|
+
Encode: encode
|
|
243
|
+
});
|
|
244
|
+
}
|
|
174
245
|
function buildRamp(stopsIn) {
|
|
175
246
|
const stops = normalizeStops(stopsIn);
|
|
176
247
|
if (stops.length <= 2) return dict({
|
|
@@ -205,19 +276,21 @@ function buildRamp(stopsIn) {
|
|
|
205
276
|
function normalizeStops(stops) {
|
|
206
277
|
const out = stops.map((s) => ({
|
|
207
278
|
offset: Math.max(0, Math.min(1, s.offset)),
|
|
208
|
-
colorHex: s.colorHex
|
|
279
|
+
colorHex: s.colorHex,
|
|
280
|
+
alpha: Math.max(0, Math.min(1, s.alpha ?? 1))
|
|
209
281
|
})).sort((a, b) => a.offset - b.offset);
|
|
210
282
|
if (out.length === 0) return [{
|
|
211
283
|
offset: 0,
|
|
212
|
-
colorHex: "000000"
|
|
284
|
+
colorHex: "000000",
|
|
285
|
+
alpha: 1
|
|
213
286
|
}];
|
|
214
287
|
out[0] = {
|
|
215
|
-
|
|
216
|
-
|
|
288
|
+
...out[0],
|
|
289
|
+
offset: 0
|
|
217
290
|
};
|
|
218
291
|
out[out.length - 1] = {
|
|
219
|
-
|
|
220
|
-
|
|
292
|
+
...out[out.length - 1],
|
|
293
|
+
offset: 1
|
|
221
294
|
};
|
|
222
295
|
return out;
|
|
223
296
|
}
|
|
@@ -235,4 +308,4 @@ function rgb01(hex) {
|
|
|
235
308
|
];
|
|
236
309
|
}
|
|
237
310
|
//#endregion
|
|
238
|
-
export { buildGradientPattern, shapeBbox };
|
|
311
|
+
export { buildGradientAlphaMask, buildGradientPattern, shapeBbox };
|