reamkit 1.23.0 → 1.24.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/bmp.d.ts +33 -0
- package/dist/esm/core/bmp.js +276 -0
- package/dist/esm/core/document-model/types.d.ts +37 -0
- package/dist/esm/core/drawingml/chart-geometry.js +3 -2
- package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
- package/dist/esm/core/drawingml/diagram/colors.js +125 -0
- package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
- package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
- package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
- package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
- package/dist/esm/core/drawingml/diagram/run.js +50 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
- package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
- package/dist/esm/core/drawingml/preset-geometry.js +116 -6
- package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
- package/dist/esm/core/drawingml/text-warp.js +355 -0
- package/dist/esm/core/drawingml/theme-parser.js +9 -3
- package/dist/esm/core/font/measure.d.ts +12 -0
- package/dist/esm/core/font/measure.js +36 -0
- package/dist/esm/core/images.d.ts +30 -2
- package/dist/esm/core/images.js +121 -5
- package/dist/esm/core/metafile/emf.js +144 -16
- package/dist/esm/core/metafile/picture.d.ts +49 -0
- package/dist/esm/core/metafile/picture.js +70 -1
- package/dist/esm/core/metafile/wmf.js +53 -4
- package/dist/esm/core/ole/escher-blip.js +11 -1
- package/dist/esm/excel/print-model.js +2 -2
- package/dist/esm/excel/sheet-drawing.js +1 -1
- package/dist/esm/excel/sheet-to-flow.js +16 -2
- package/dist/esm/html/html-writer.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +35 -0
- package/dist/esm/layout/page-doc.js +14 -1
- package/dist/esm/layout/styled-layout.js +176 -15
- package/dist/esm/pdf/shading.js +8 -6
- package/dist/esm/pdf/styled-page-emitter.js +42 -3
- package/dist/esm/pdf/vector-graphics.js +1 -1
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/ppt/ppt-reader.js +95 -27
- package/dist/esm/pptx/ppt/ppt-text.d.ts +41 -0
- package/dist/esm/pptx/ppt/ppt-text.js +327 -37
- package/dist/esm/pptx/pptx-reader.js +90 -10
- package/dist/esm/pptx/slide-parser.d.ts +4 -1
- package/dist/esm/pptx/slide-parser.js +99 -13
- package/dist/esm/pptx/sp-helpers.d.ts +7 -3
- package/dist/esm/pptx/sp-helpers.js +45 -7
- package/dist/esm/pptx/table-style.d.ts +7 -0
- package/dist/esm/pptx/table-style.js +59 -7
- package/dist/esm/svg/svg-writer.js +1 -0
- package/dist/esm/word/document-parser.d.ts +4 -1
- package/dist/esm/word/document-parser.js +4 -1
- package/dist/esm/word/docx-reader.js +26 -13
- package/dist/esm/word/docx-writer.js +4 -0
- package/dist/esm/word/drawing-parser.d.ts +20 -0
- package/dist/esm/word/drawing-parser.js +37 -4
- package/dist/esm/word/table-parser.js +3 -0
- package/package.json +1 -1
|
@@ -1030,8 +1030,8 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1030
1030
|
const fillImage = shape.fill.kind === "picture" && shape.fill.imageResource !== void 0 ? imageResources?.get(shape.fill.imageResource) : void 0;
|
|
1031
1031
|
const fillImageResourceName = fillImage?.resourceName;
|
|
1032
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)
|
|
1033
|
+
widthPt: fillImage.prepared.widthPx * 72 / (fillImage.prepared.dpiX ?? 96) * (shape.fill.tileScale?.sx ?? 1),
|
|
1034
|
+
heightPt: fillImage.prepared.heightPx * 72 / (fillImage.prepared.dpiY ?? 96) * (shape.fill.tileScale?.sy ?? 1)
|
|
1035
1035
|
} : void 0;
|
|
1036
1036
|
const fillColorHex = shape.fill.kind === "solid" ? shape.fill.colorHex : fillGradient ? gradientToSolid(fillGradient) : void 0;
|
|
1037
1037
|
const stroke = buildStroke(shape.line);
|
|
@@ -1049,8 +1049,9 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1049
1049
|
const textLineGaps = /* @__PURE__ */ new Map();
|
|
1050
1050
|
let textHeightPt = 0;
|
|
1051
1051
|
const vertical = text?.vertical;
|
|
1052
|
+
const warp = text?.warp;
|
|
1052
1053
|
if (text && text.content.length > 0) {
|
|
1053
|
-
const innerWidth = vertical ? Math.max(1, heightPt - insetTopPt - insetBottomPt) : Math.max(1, widthPt - insetLeftPt - insetRightPt);
|
|
1054
|
+
const innerWidth = warp ? Number.MAX_SAFE_INTEGER : vertical ? Math.max(1, heightPt - insetTopPt - insetBottomPt) : Math.max(1, widthPt - insetLeftPt - insetRightPt);
|
|
1054
1055
|
for (const el of text.content) {
|
|
1055
1056
|
if (el.kind === "image") {
|
|
1056
1057
|
const res = el.image.resource ? imageResources?.get(el.image.resource) : void 0;
|
|
@@ -1143,6 +1144,16 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1143
1144
|
}
|
|
1144
1145
|
}
|
|
1145
1146
|
if (text?.autoFit && !vertical && textLines.length > 0) heightPt = textHeightPt + insetTopPt + insetBottomPt;
|
|
1147
|
+
if (text?.shrinkToFit === true && text.fitToBox !== true && warp === void 0 && textLines.length > 0 && fitPass < MAX_FIT_PASSES) {
|
|
1148
|
+
const innerW = Math.max(1, widthPt - insetLeftPt - insetRightPt);
|
|
1149
|
+
const innerH = Math.max(1, heightPt - insetTopPt - insetBottomPt);
|
|
1150
|
+
const widest = textLines.reduce((a, l) => Math.max(a, l.contentWidthPt), 0);
|
|
1151
|
+
const k = Math.min(1, innerW / Math.max(1, widest), innerH / Math.max(1, textHeightPt));
|
|
1152
|
+
if (Number.isFinite(k) && k > .05 && k < .98) return layoutShapeBlock({
|
|
1153
|
+
...shape,
|
|
1154
|
+
text: scaleTextBody(text, k)
|
|
1155
|
+
}, options, fontResources, imageResources, contentWidth, maxHeight, box, fitPass + 1);
|
|
1156
|
+
}
|
|
1146
1157
|
if (text?.fitToBox === true && textLines.length > 0 && fitPass < MAX_FIT_PASSES) {
|
|
1147
1158
|
const innerW = Math.max(1, widthPt - insetLeftPt - insetRightPt);
|
|
1148
1159
|
const innerH = Math.max(1, heightPt - insetTopPt - insetBottomPt);
|
|
@@ -1166,6 +1177,10 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1166
1177
|
text: scaleTextBody(text, k)
|
|
1167
1178
|
}, options, fontResources, imageResources, contentWidth, maxHeight, box, fitPass + 1);
|
|
1168
1179
|
}
|
|
1180
|
+
const warpInk = warp && textLines.length > 0 ? {
|
|
1181
|
+
above: lineInk(textLines[0]).above,
|
|
1182
|
+
below: lineInk(textLines[textLines.length - 1]).below
|
|
1183
|
+
} : void 0;
|
|
1169
1184
|
const paths = buildShapePaths(shape.geometry, widthPt, heightPt);
|
|
1170
1185
|
const markerPaths = lineEndPaths(paths, shape.line, stroke?.widthPt ?? 0);
|
|
1171
1186
|
const scale = shape.width > 0 ? widthPt / shape.width : 1;
|
|
@@ -1187,6 +1202,7 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1187
1202
|
...markerPaths.length > 0 ? { markerPaths } : {},
|
|
1188
1203
|
...fillImageResourceName ? { fillImageResourceName } : {},
|
|
1189
1204
|
...fillImageTile ? { fillImageTile } : {},
|
|
1205
|
+
...fillImageTile && shape.fill.kind === "picture" && shape.fill.tileFromCentre === true ? { fillImageTileFromCentre: true } : {},
|
|
1190
1206
|
...fillImageResourceName && shape.fill.imageCrop ? { fillImageCrop: shape.fill.imageCrop } : {},
|
|
1191
1207
|
...fillImageResourceName && shape.fill.imageFillRect ? { fillImageRect: shape.fill.imageFillRect } : {},
|
|
1192
1208
|
...fillImageResourceName && shape.fill.duotone ? { fillImageDuotone: shape.fill.duotone } : {},
|
|
@@ -1202,6 +1218,12 @@ function layoutShapeBlock(shape, options, fontResources, imageResources, content
|
|
|
1202
1218
|
spacingBeforePt: pp.spacingBefore ?? 0,
|
|
1203
1219
|
spacingAfterPt: pp.spacingAfter ?? 0,
|
|
1204
1220
|
textLines,
|
|
1221
|
+
...warp && warpInk ? { textWarp: {
|
|
1222
|
+
preset: warp.preset,
|
|
1223
|
+
...warp.adjust !== void 0 ? { adjust: warp.adjust } : {},
|
|
1224
|
+
inkAbovePt: warpInk.above,
|
|
1225
|
+
inkBelowPt: warpInk.below
|
|
1226
|
+
} } : {},
|
|
1205
1227
|
...textCharts.size > 0 ? { textCharts } : {},
|
|
1206
1228
|
...textShapes.size > 0 ? { textShapes } : {},
|
|
1207
1229
|
...textTables.size > 0 ? { textTables } : {},
|
|
@@ -1884,6 +1906,10 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1884
1906
|
}
|
|
1885
1907
|
return;
|
|
1886
1908
|
}
|
|
1909
|
+
if (sh.textWarp) {
|
|
1910
|
+
emitWarpedText(sh, sh.textWarp, x, bottomYUp, sink, pageHeight, figId);
|
|
1911
|
+
return;
|
|
1912
|
+
}
|
|
1887
1913
|
const shapeTop = bottomYUp + sh.heightPt;
|
|
1888
1914
|
const innerWidth = Math.max(1, sh.widthPt - sh.insetLeftPt - sh.insetRightPt);
|
|
1889
1915
|
let textY;
|
|
@@ -1923,6 +1949,65 @@ function emitShapeText(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1923
1949
|
textY -= sh.textLineGaps?.get(i) ?? 0;
|
|
1924
1950
|
});
|
|
1925
1951
|
}
|
|
1952
|
+
/**
|
|
1953
|
+
* §20.1.9.10 — place a WordArt body's lines in the block's own frame and hand
|
|
1954
|
+
* each one the warp that maps that frame onto the shape's box.
|
|
1955
|
+
*
|
|
1956
|
+
* The block is laid out flat: its lines stack by their own heights, each
|
|
1957
|
+
* aligned within the widest of them, and its ink starts at the box's top-left
|
|
1958
|
+
* corner. Nothing here bends anything — the emitter does that, glyph by glyph,
|
|
1959
|
+
* from the two frames this records.
|
|
1960
|
+
*
|
|
1961
|
+
* @param sh The laid-out shape.
|
|
1962
|
+
* @param warp The shape's warp and the block's ink reach.
|
|
1963
|
+
* @param x The shape's left edge on the page.
|
|
1964
|
+
* @param bottomYUp The shape's bottom edge, y-up from the page's bottom.
|
|
1965
|
+
* @param sink Where the line items are pushed.
|
|
1966
|
+
* @param pageHeight The page's height, for the y-up ⇄ top-left conversion.
|
|
1967
|
+
* @param figId The tagged-PDF Figure this text belongs to, when it has one.
|
|
1968
|
+
*/
|
|
1969
|
+
function emitWarpedText(sh, warp, x, bottomYUp, sink, pageHeight, figId) {
|
|
1970
|
+
const boxX = x + sh.insetLeftPt;
|
|
1971
|
+
const boxY = pageHeight - (bottomYUp + sh.heightPt) + sh.insetTopPt;
|
|
1972
|
+
const boxWidth = Math.max(1, sh.widthPt - sh.insetLeftPt - sh.insetRightPt);
|
|
1973
|
+
const boxHeight = Math.max(1, sh.heightPt - sh.insetTopPt - sh.insetBottomPt);
|
|
1974
|
+
const srcWidth = Math.max(1, ...sh.textLines.map((l) => l.contentWidthPt));
|
|
1975
|
+
const baselines = [];
|
|
1976
|
+
let top = 0;
|
|
1977
|
+
sh.textLines.forEach((line, i) => {
|
|
1978
|
+
const h = computeLineHeight(line, line.resolved);
|
|
1979
|
+
baselines.push(top + h - lineBaselineOffset(line, line.resolved));
|
|
1980
|
+
top += h + (sh.textLineGaps?.get(i) ?? 0);
|
|
1981
|
+
});
|
|
1982
|
+
const first = baselines[0] ?? 0;
|
|
1983
|
+
const last = baselines[baselines.length - 1] ?? 0;
|
|
1984
|
+
const srcTop = boxY;
|
|
1985
|
+
const srcHeight = Math.max(1, last - first + warp.inkAbovePt + warp.inkBelowPt);
|
|
1986
|
+
const shift = srcTop + warp.inkAbovePt - first;
|
|
1987
|
+
sh.textLines.forEach((line, i) => {
|
|
1988
|
+
if (sh.textCharts?.has(i) === true || sh.textShapes?.has(i) === true) return;
|
|
1989
|
+
if (sh.textTables?.has(i) === true) return;
|
|
1990
|
+
sink.push({
|
|
1991
|
+
type: "line",
|
|
1992
|
+
line,
|
|
1993
|
+
originX: pt(boxX + alignmentOffset(line.resolved.alignment, line.contentWidthPt, srcWidth)),
|
|
1994
|
+
baselineY: pt(baselines[i] + shift),
|
|
1995
|
+
warp: {
|
|
1996
|
+
preset: warp.preset,
|
|
1997
|
+
...warp.adjust !== void 0 ? { adjust: warp.adjust } : {},
|
|
1998
|
+
boxX: pt(boxX),
|
|
1999
|
+
boxY: pt(boxY),
|
|
2000
|
+
boxWidth: pt(boxWidth),
|
|
2001
|
+
boxHeight: pt(boxHeight),
|
|
2002
|
+
srcX: pt(boxX),
|
|
2003
|
+
srcWidth: pt(srcWidth),
|
|
2004
|
+
srcTop: pt(srcTop),
|
|
2005
|
+
srcHeight: pt(srcHeight)
|
|
2006
|
+
},
|
|
2007
|
+
...figId !== void 0 ? { structId: figId } : {}
|
|
2008
|
+
});
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
1926
2011
|
/** The page a table is being drawn onto, as a cell's floats need to see it. */
|
|
1927
2012
|
function cellAnchorCtx(asm) {
|
|
1928
2013
|
return {
|
|
@@ -1962,6 +2047,19 @@ function emitCellFloat(cf, ctx, frame) {
|
|
|
1962
2047
|
if (float.wrap !== "none") ctx.exclude(float, x, topYUp, cf.block.widthPt, cf.block.heightPt);
|
|
1963
2048
|
}
|
|
1964
2049
|
function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
2050
|
+
const castsUnderPicture = sh.fillImageResourceName !== void 0 ? sh.shadow : void 0;
|
|
2051
|
+
const shadowedFill = castsUnderPicture !== void 0;
|
|
2052
|
+
const group = shadowedFill ? { pictureId: nextPictureId++ } : {};
|
|
2053
|
+
if (castsUnderPicture) sink.push({
|
|
2054
|
+
type: "shape",
|
|
2055
|
+
shape: {
|
|
2056
|
+
paths: sh.paths,
|
|
2057
|
+
shadow: castsUnderPicture,
|
|
2058
|
+
transform: flipTransform(buildShapeTransform(x, bottomYUp, sh.widthPt, sh.heightPt, sh.rotation60k, sh.flipH, sh.flipV), pageHeight)
|
|
2059
|
+
},
|
|
2060
|
+
...group,
|
|
2061
|
+
...figId !== void 0 ? { structId: figId } : {}
|
|
2062
|
+
});
|
|
1965
2063
|
if (sh.fillImageResourceName) {
|
|
1966
2064
|
const clip = {
|
|
1967
2065
|
paths: sh.paths,
|
|
@@ -1974,12 +2072,13 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
1974
2072
|
y: pageHeight - (bottomYUp + sh.heightPt),
|
|
1975
2073
|
width: sh.widthPt,
|
|
1976
2074
|
height: sh.heightPt
|
|
1977
|
-
})) {
|
|
2075
|
+
}, sh.fillImageTileFromCentre === true)) {
|
|
1978
2076
|
if (item.type !== "image") continue;
|
|
1979
2077
|
sink.push({
|
|
1980
2078
|
...item,
|
|
1981
2079
|
clip,
|
|
1982
2080
|
...fig,
|
|
2081
|
+
...group,
|
|
1983
2082
|
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {}
|
|
1984
2083
|
});
|
|
1985
2084
|
}
|
|
@@ -2000,7 +2099,8 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
2000
2099
|
...sh.fillAlpha !== void 0 ? { alpha: sh.fillAlpha } : {},
|
|
2001
2100
|
...sh.fillImageDuotone ? { duotone: sh.fillImageDuotone } : {},
|
|
2002
2101
|
clip,
|
|
2003
|
-
...fig
|
|
2102
|
+
...fig,
|
|
2103
|
+
...group
|
|
2004
2104
|
});
|
|
2005
2105
|
}
|
|
2006
2106
|
}
|
|
@@ -2021,9 +2121,10 @@ function emitShapeItems(sh, x, bottomYUp, sink, pageHeight, figId) {
|
|
|
2021
2121
|
...sh.fillGradient ? { fillGradient: sh.fillGradient } : {},
|
|
2022
2122
|
...sh.fillAlpha !== void 0 ? { fillAlpha: sh.fillAlpha } : {},
|
|
2023
2123
|
...sh.stroke ? { stroke: sh.stroke } : {},
|
|
2024
|
-
...sh.shadow ? { shadow: sh.shadow } : {},
|
|
2124
|
+
...sh.shadow && !shadowedFill ? { shadow: sh.shadow } : {},
|
|
2025
2125
|
transform: flipTransform(buildShapeTransform(x, bottomYUp, sh.widthPt, sh.heightPt, sh.rotation60k, sh.flipH, sh.flipV), pageHeight)
|
|
2026
2126
|
},
|
|
2127
|
+
...group,
|
|
2027
2128
|
...figId !== void 0 ? { structId: figId } : {}
|
|
2028
2129
|
});
|
|
2029
2130
|
for (const child of sh.children ?? []) emitShapeItems(child.laid, x + child.xPt, bottomYUp + sh.heightPt - child.yPt - child.laid.heightPt, sink, pageHeight, figId);
|
|
@@ -3647,6 +3748,30 @@ function alignmentOffset(alignment, lineWidth, available) {
|
|
|
3647
3748
|
return 0;
|
|
3648
3749
|
}
|
|
3649
3750
|
/**
|
|
3751
|
+
* How far a line's INK reaches either side of its baseline — the union of its
|
|
3752
|
+
* glyphs' own bounding boxes, not the line box its font metrics describe. Only
|
|
3753
|
+
* WordArt needs this: it stretches the marks it draws onto its shape, and the
|
|
3754
|
+
* empty band an ascender or descender reserves is not one of them.
|
|
3755
|
+
*
|
|
3756
|
+
* @param line The laid-out line.
|
|
3757
|
+
* @returns Points above the baseline the ink rises, and below it that it drops.
|
|
3758
|
+
*/
|
|
3759
|
+
function lineInk(line) {
|
|
3760
|
+
let above = 0;
|
|
3761
|
+
let below = 0;
|
|
3762
|
+
for (const tok of line.tokens) {
|
|
3763
|
+
if (tok.kind !== "text" || tok.isSpace) continue;
|
|
3764
|
+
const ink = tok.font.measure.textInkPt(tok.text, tok.fontSizePt);
|
|
3765
|
+
const rise = tok.risePt ?? 0;
|
|
3766
|
+
above = Math.max(above, ink.above + rise);
|
|
3767
|
+
below = Math.max(below, ink.below - rise);
|
|
3768
|
+
}
|
|
3769
|
+
return {
|
|
3770
|
+
above,
|
|
3771
|
+
below
|
|
3772
|
+
};
|
|
3773
|
+
}
|
|
3774
|
+
/**
|
|
3650
3775
|
* §17.4.85 `w:vMerge` — a vertical merge is ONE cell, so its continuation rows
|
|
3651
3776
|
* are painted with the START cell's shading. Word writes the fill on the cell
|
|
3652
3777
|
* that opens the merge and nothing on the rest; painting only what is written,
|
|
@@ -4066,7 +4191,9 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
4066
4191
|
const padRightBase = cellMar?.right ?? tableMar?.right ?? DEFAULT_CELL_PADDING_TWIPS * TWIP_TO_PT;
|
|
4067
4192
|
const padLeftPt = padLeftBase + (cell.properties.icon ? CF_ICON_GUTTER_PT : 0);
|
|
4068
4193
|
const padRightPt = padRightBase;
|
|
4194
|
+
const turned = mergeRole === "middle" || mergeRole === "end" ? void 0 : cell.properties.textDirection;
|
|
4069
4195
|
const innerWidth = Math.max(1, widthPt - padLeftPt - padRightPt);
|
|
4196
|
+
const measureWidth = turned ? NO_WRAP_MEASURE_WIDTH : innerWidth;
|
|
4070
4197
|
const lines = [];
|
|
4071
4198
|
const nestedTables = [];
|
|
4072
4199
|
const cellShapes = [];
|
|
@@ -4085,7 +4212,7 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
4085
4212
|
if (mergeRole !== "middle" && mergeRole !== "end") {
|
|
4086
4213
|
for (const el of cell.content) if (el.kind === "paragraph") {
|
|
4087
4214
|
const noWrap = cell.properties.noWrap === true;
|
|
4088
|
-
const block = layoutParagraphBlock(el.paragraph, options, fontResources, imageResources, noWrap ? NO_WRAP_MEASURE_WIDTH :
|
|
4215
|
+
const block = layoutParagraphBlock(el.paragraph, options, fontResources, imageResources, noWrap ? NO_WRAP_MEASURE_WIDTH : measureWidth);
|
|
4089
4216
|
const cutAt = widthPt - padLeftPt;
|
|
4090
4217
|
if (noWrap && (block.lines[0]?.contentWidthPt ?? 0) > cutAt) clipped = true;
|
|
4091
4218
|
const keep = noWrap ? clipLineToWidth(block.lines, cutAt, cell.properties.hashOnOverflow === true) : block.lines;
|
|
@@ -4136,7 +4263,9 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
4136
4263
|
}
|
|
4137
4264
|
const colEnd = colStart + colSpan - 1;
|
|
4138
4265
|
const borders = resolveCellBorders(cell.properties.borders, tableProps.borders, rowIdx, colStart, colEnd, rowCount, colCount, mergeRole, leftNeighborBorders, aboveNeighborBorders);
|
|
4139
|
-
const
|
|
4266
|
+
const alongPt = turned ? lines.reduce((a, l) => Math.max(a, l.contentWidthPt), 0) : 0;
|
|
4267
|
+
const heightPt = turned ? alongPt : contentHeightPt;
|
|
4268
|
+
const totalHeightPt = mergeRole === "middle" || mergeRole === "end" ? 0 : padTopPt + heightPt + padBottomPt;
|
|
4140
4269
|
return {
|
|
4141
4270
|
widthPt,
|
|
4142
4271
|
padTopPt,
|
|
@@ -4153,8 +4282,9 @@ function layoutTableCell(cell, tableProps, widthPt, options, fontResources, imag
|
|
|
4153
4282
|
...nestedTables.length > 0 ? { nestedTables } : {},
|
|
4154
4283
|
...cellShapes.length > 0 ? { shapes: cellShapes } : {},
|
|
4155
4284
|
...cellFloats.length > 0 ? { floats: cellFloats } : {},
|
|
4156
|
-
contentHeightPt,
|
|
4285
|
+
contentHeightPt: heightPt,
|
|
4157
4286
|
totalHeightPt,
|
|
4287
|
+
...turned ? { textDirection: turned } : {},
|
|
4158
4288
|
...cell.properties.verticalAlign ? { verticalAlign: cell.properties.verticalAlign } : {},
|
|
4159
4289
|
colStart,
|
|
4160
4290
|
colSpan,
|
|
@@ -4807,16 +4937,24 @@ var PageAssembler = class PageAssembler {
|
|
|
4807
4937
|
* one: stretched over the page it is a blur, and its 128 pixels are 96 points
|
|
4808
4938
|
* at the resolution Office measures a picture in.
|
|
4809
4939
|
*/
|
|
4810
|
-
static tileItems = (resourceName, natural, box) => {
|
|
4940
|
+
static tileItems = (resourceName, natural, box, fromCentre = false) => {
|
|
4811
4941
|
const tw = Math.max(1, natural.widthPt);
|
|
4812
4942
|
const th = Math.max(1, natural.heightPt);
|
|
4813
|
-
const
|
|
4814
|
-
|
|
4943
|
+
const first = (start, span, step) => {
|
|
4944
|
+
if (!fromCentre) return start;
|
|
4945
|
+
let at = start + span / 2 - step / 2;
|
|
4946
|
+
while (at > start) at -= step;
|
|
4947
|
+
return at;
|
|
4948
|
+
};
|
|
4949
|
+
const x0 = first(box.x, box.width, tw);
|
|
4950
|
+
const y0 = first(box.y, box.height, th);
|
|
4951
|
+
const cols = Math.min(200, Math.max(1, Math.ceil((box.x + box.width - x0) / tw)));
|
|
4952
|
+
const rows = Math.min(200, Math.max(1, Math.ceil((box.y + box.height - y0) / th)));
|
|
4815
4953
|
const out = [];
|
|
4816
4954
|
for (let r = 0; r < rows; r++) for (let c = 0; c < cols; c++) out.push({
|
|
4817
4955
|
type: "image",
|
|
4818
|
-
x: pt(
|
|
4819
|
-
y: pt(
|
|
4956
|
+
x: pt(x0 + c * tw),
|
|
4957
|
+
y: pt(y0 + r * th),
|
|
4820
4958
|
width: pt(tw),
|
|
4821
4959
|
height: pt(th),
|
|
4822
4960
|
imageResourceName: resourceName
|
|
@@ -5191,7 +5329,7 @@ function paginateSections(blocks, sectionCtxs, builder, defaultLang = "en-US", n
|
|
|
5191
5329
|
const chunks = !row.cantSplit && row.heightPt > room && asm.colHasContent() && room > 0 ? splitRowIntoChunks(row, room, page) : row.heightPt > page ? splitRowIntoChunks(row, page) : [row];
|
|
5192
5330
|
for (let ci = 0; ci < chunks.length; ci++) {
|
|
5193
5331
|
const chunk = chunks[ci];
|
|
5194
|
-
const forcedBreak = ci === 0 && row.breakBefore && !isLeadingHeader && asm.
|
|
5332
|
+
const forcedBreak = ci === 0 && row.breakBefore && !isLeadingHeader && asm.pageHasContent();
|
|
5195
5333
|
const overflow = asm.cursorY - chunk.heightPt < asm.bottomLimit() && asm.colHasContent();
|
|
5196
5334
|
if (forcedBreak || overflow) {
|
|
5197
5335
|
if (forcedBreak) asm.flushPage();
|
|
@@ -5484,6 +5622,29 @@ function emitRowChunk(out, row, marginLeft, cursorY, pageHeight, colCount, cellS
|
|
|
5484
5622
|
});
|
|
5485
5623
|
}
|
|
5486
5624
|
};
|
|
5625
|
+
if (cell.textDirection !== void 0) {
|
|
5626
|
+
const up = cell.textDirection === "vert270";
|
|
5627
|
+
const along = Math.max(1, boxHeightPt - cell.padTopPt - cell.padBottomPt);
|
|
5628
|
+
const cellBottomYUp = rowTop - boxHeightPt;
|
|
5629
|
+
let across = cell.padLeftPt;
|
|
5630
|
+
for (const line of cell.lines) {
|
|
5631
|
+
const h = computeLineHeight(line, line.resolved);
|
|
5632
|
+
const lineOffset = alignmentOffset(line.resolved.alignment, line.contentWidthPt, along);
|
|
5633
|
+
const off = lineBaselineOffset(line, line.resolved);
|
|
5634
|
+
const baselineAcross = up ? across + h - off : across + off;
|
|
5635
|
+
out.push({
|
|
5636
|
+
type: "line",
|
|
5637
|
+
line,
|
|
5638
|
+
originX: pt(up ? cellX + baselineAcross : cellX + cell.widthPt - baselineAcross),
|
|
5639
|
+
baselineY: pt(pageHeight - (up ? cellBottomYUp + cell.padBottomPt + lineOffset : rowTop - cell.padTopPt - lineOffset)),
|
|
5640
|
+
rotationDeg: up ? 90 : -90,
|
|
5641
|
+
...structId !== void 0 ? { structId } : {}
|
|
5642
|
+
});
|
|
5643
|
+
across += h;
|
|
5644
|
+
}
|
|
5645
|
+
drawNestedBefore(cell.lines.length);
|
|
5646
|
+
continue;
|
|
5647
|
+
}
|
|
5487
5648
|
for (const [lineIdx, line] of cell.lines.entries()) {
|
|
5488
5649
|
drawNestedBefore(lineIdx);
|
|
5489
5650
|
textY -= cell.lineGaps?.get(lineIdx) ?? 0;
|
package/dist/esm/pdf/shading.js
CHANGED
|
@@ -284,14 +284,16 @@ function normalizeStops(stops) {
|
|
|
284
284
|
colorHex: "000000",
|
|
285
285
|
alpha: 1
|
|
286
286
|
}];
|
|
287
|
-
out[0]
|
|
288
|
-
|
|
287
|
+
const first = out[0];
|
|
288
|
+
if (first.offset > 0) out.unshift({
|
|
289
|
+
...first,
|
|
289
290
|
offset: 0
|
|
290
|
-
};
|
|
291
|
-
out[out.length - 1]
|
|
292
|
-
|
|
291
|
+
});
|
|
292
|
+
const last = out[out.length - 1];
|
|
293
|
+
if (last.offset < 1) out.push({
|
|
294
|
+
...last,
|
|
293
295
|
offset: 1
|
|
294
|
-
};
|
|
296
|
+
});
|
|
295
297
|
return out;
|
|
296
298
|
}
|
|
297
299
|
function rgb01(hex) {
|
|
@@ -7,6 +7,7 @@ import { GLUE_SHRINK_RATIO } from "../layout/styled-layout.js";
|
|
|
7
7
|
import { paintPlan } from "../layout/page-doc.js";
|
|
8
8
|
import { emitClipPath, emitVectorShape, shadowBlurLayers } from "./vector-graphics.js";
|
|
9
9
|
import { buildGradientAlphaMask, buildGradientPattern, shapeBbox } from "./shading.js";
|
|
10
|
+
import { warpGlyphMatrix } from "../core/drawingml/text-warp.js";
|
|
10
11
|
import { sanitizeHref } from "../core/links.js";
|
|
11
12
|
import { embedAssociatedFile } from "./embedded-file.js";
|
|
12
13
|
import { buildSrgbIccProfile } from "./icc-profile.js";
|
|
@@ -111,7 +112,11 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
111
112
|
if (!pdfaProfile) for (const page of renderedPages) {
|
|
112
113
|
const ph = page.height;
|
|
113
114
|
const plan = paintPlan(page.commands);
|
|
114
|
-
const shapesNeedingPatterns = [...plan.shapes, ...[
|
|
115
|
+
const shapesNeedingPatterns = [...plan.shapes, ...[
|
|
116
|
+
...plan.behind,
|
|
117
|
+
...plan.pictures.flat(),
|
|
118
|
+
...plan.ordered.flat()
|
|
119
|
+
].filter((i) => i.type === "shape")];
|
|
115
120
|
for (const item of shapesNeedingPatterns) {
|
|
116
121
|
const gradient = item.shape.fillGradient;
|
|
117
122
|
if (!gradient) continue;
|
|
@@ -211,7 +216,11 @@ function assembleStyledPdf(laid, options, doc) {
|
|
|
211
216
|
wantAlpha(img.alpha);
|
|
212
217
|
wantDuotone(img, page.height);
|
|
213
218
|
}
|
|
214
|
-
for (const item of [
|
|
219
|
+
for (const item of [
|
|
220
|
+
...plan.behind,
|
|
221
|
+
...plan.pictures.flat(),
|
|
222
|
+
...plan.ordered.flat()
|
|
223
|
+
]) {
|
|
215
224
|
if (item.type === "image") {
|
|
216
225
|
wantAlpha(washVeil(item.wash)?.alpha);
|
|
217
226
|
wantAlpha(item.alpha);
|
|
@@ -1009,6 +1018,34 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1009
1018
|
}
|
|
1010
1019
|
const hasRise = line.tokens.some((t) => t.kind === "text" && t.risePt !== void 0);
|
|
1011
1020
|
const hasFauxItalic = line.tokens.some((t) => t.kind === "text" && t.synthetic?.italic === true);
|
|
1021
|
+
const warp = cmd.warp;
|
|
1022
|
+
if (warp) {
|
|
1023
|
+
if (!inBT) {
|
|
1024
|
+
out.push("BT");
|
|
1025
|
+
inBT = true;
|
|
1026
|
+
}
|
|
1027
|
+
let cursor = originX;
|
|
1028
|
+
for (const tok of line.tokens) {
|
|
1029
|
+
if (tok.kind !== "text" || tok.isSpace) {
|
|
1030
|
+
cursor += tok.widthPt;
|
|
1031
|
+
continue;
|
|
1032
|
+
}
|
|
1033
|
+
switchFontIfNeeded(tok);
|
|
1034
|
+
const chars = [...tok.text];
|
|
1035
|
+
const raw = chars.map((c) => tok.font.measure.textWidthPt(c, tok.fontSizePt));
|
|
1036
|
+
const total = raw.reduce((a, b) => a + b, 0);
|
|
1037
|
+
const k = total > 0 ? tok.widthPt / total : 1;
|
|
1038
|
+
for (let i = 0; i < chars.length; i++) {
|
|
1039
|
+
const adv = raw[i] * k;
|
|
1040
|
+
const m = warpGlyphMatrix(warp, cursor, adv, cmd.baselineY);
|
|
1041
|
+
cursor += adv;
|
|
1042
|
+
if (!m) continue;
|
|
1043
|
+
out.push(`${formatNumber(m[0])} ${formatNumber(-m[1])} ${formatNumber(m[2])} ${formatNumber(-m[3])} ${formatNumber(m[4])} ${formatNumber(H - m[5])} Tm`);
|
|
1044
|
+
out.push(tok.font.measure.showText(chars[i]));
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return;
|
|
1048
|
+
}
|
|
1012
1049
|
if (rotationDeg !== 0 && !hasImageToken && !hasMathToken) {
|
|
1013
1050
|
if (!inBT) {
|
|
1014
1051
|
out.push("BT");
|
|
@@ -1104,6 +1141,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1104
1141
|
if (item.type === "shape") {
|
|
1105
1142
|
const t = item.shape.transform;
|
|
1106
1143
|
const fillAlpha = item.shape.fillAlpha;
|
|
1144
|
+
const layer = item.shape.shadow ? shadowBlurLayers(item.shape.shadow) : void 0;
|
|
1107
1145
|
for (const op of emitVectorShape({
|
|
1108
1146
|
...item.shape,
|
|
1109
1147
|
transform: [
|
|
@@ -1114,7 +1152,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1114
1152
|
t[4],
|
|
1115
1153
|
H - t[5]
|
|
1116
1154
|
]
|
|
1117
|
-
}, gradientNames?.get(item.shape), void 0, gradientMaskNames?.get(item.shape) ?? (fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0))) out.push(op);
|
|
1155
|
+
}, gradientNames?.get(item.shape), layer && layer.alpha < 1 ? alphaStateNames?.get(Math.round(layer.alpha * 1e3) / 1e3) : void 0, gradientMaskNames?.get(item.shape) ?? (fillAlpha !== void 0 && fillAlpha < 1 ? alphaStateNames?.get(Math.round(fillAlpha * 1e3) / 1e3) : void 0))) out.push(op);
|
|
1118
1156
|
return;
|
|
1119
1157
|
}
|
|
1120
1158
|
if (item.type === "image") {
|
|
@@ -1287,6 +1325,7 @@ function emitPageContent(page, tagging, gradientNames, alphaStateNames, duotoneS
|
|
|
1287
1325
|
for (const item of run) emitInOrder(item);
|
|
1288
1326
|
if (tagging) out.push("EMC");
|
|
1289
1327
|
}
|
|
1328
|
+
for (const run of plan.ordered) for (const item of run) emitInOrder(item);
|
|
1290
1329
|
emitLinesPass();
|
|
1291
1330
|
return {
|
|
1292
1331
|
content: encoder.encode(out.join("\n")),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PDF_NULL, PdfHexString, PdfName, PdfStream } from "../pdf/objects.js";
|
|
2
|
-
import { lzwDecodeMsb } from "../core/lzw.js";
|
|
3
2
|
import { encodePng } from "../core/png-encode.js";
|
|
3
|
+
import { lzwDecodeMsb } from "../core/lzw.js";
|
|
4
4
|
import { reversePredictor } from "./predictor.js";
|
|
5
5
|
import { decodeCcitt } from "./ccitt.js";
|
|
6
6
|
import { unzlibSync } from "fflate";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { pt } from "../../core/ir/units.js";
|
|
2
2
|
import { ResourceStore } from "../../core/ir/resources.js";
|
|
3
3
|
import { FEATURES } from "../../core/ir/features.js";
|
|
4
|
+
import { knockOutColor } from "../../core/images.js";
|
|
4
5
|
import { isEmf } from "../../core/metafile/emf.js";
|
|
5
6
|
import { isWmf } from "../../core/metafile/wmf.js";
|
|
6
7
|
import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../../core/style-cascade/resolver.js";
|
|
@@ -136,8 +137,9 @@ function bulletedRuns(para) {
|
|
|
136
137
|
const runs = para.runs.map(toRun);
|
|
137
138
|
if (para.bullet === void 0) return runs;
|
|
138
139
|
const { bold: _b, italic: _i, ...rest } = runs[0]?.properties ?? {};
|
|
140
|
+
const gap = hangs(para) ? " " : " ";
|
|
139
141
|
return [{
|
|
140
|
-
text: `${para.bullet}
|
|
142
|
+
text: `${para.bullet}${gap}`,
|
|
141
143
|
properties: rest
|
|
142
144
|
}, ...runs];
|
|
143
145
|
}
|
|
@@ -175,16 +177,13 @@ function backdropFill(bg, resources) {
|
|
|
175
177
|
if (bg.image) return {
|
|
176
178
|
kind: "picture",
|
|
177
179
|
imageResource: resources.put(bg.image.bytes),
|
|
178
|
-
...bg.imageTiled ? {
|
|
180
|
+
...bg.imageTiled ? {
|
|
181
|
+
tiled: true,
|
|
182
|
+
tileFromCentre: true
|
|
183
|
+
} : {}
|
|
179
184
|
};
|
|
180
185
|
if (bg.gradient) {
|
|
181
|
-
const stops =
|
|
182
|
-
offset: 0,
|
|
183
|
-
colorHex: bg.gradient.fromHex
|
|
184
|
-
}, {
|
|
185
|
-
offset: 1,
|
|
186
|
-
colorHex: bg.gradient.toHex
|
|
187
|
-
}];
|
|
186
|
+
const stops = gradientStops(bg.gradient);
|
|
188
187
|
return {
|
|
189
188
|
kind: "gradient",
|
|
190
189
|
gradient: bg.gradient.radial ? {
|
|
@@ -242,9 +241,10 @@ function positionedImage(rect, image, resources) {
|
|
|
242
241
|
kind: "image",
|
|
243
242
|
image: {
|
|
244
243
|
float: floatAt(rect),
|
|
245
|
-
resource: resources.put(image
|
|
244
|
+
resource: resources.put(drawnBytes(image)),
|
|
246
245
|
width: pt(rect.w),
|
|
247
246
|
height: pt(rect.h),
|
|
247
|
+
...image.crop ? { crop: image.crop } : {},
|
|
248
248
|
paragraphProperties: {}
|
|
249
249
|
}
|
|
250
250
|
};
|
|
@@ -290,34 +290,72 @@ function toCustomGeometry(g) {
|
|
|
290
290
|
commands
|
|
291
291
|
};
|
|
292
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* §2.3.7.6 `fillFocus` — the stops a shaded fill's two colours make.
|
|
295
|
+
*
|
|
296
|
+
* A focus of zero is the plain ramp everyone expects: the first colour at one
|
|
297
|
+
* end, the second at the other. Any other value means the sweep runs OUT from
|
|
298
|
+
* one of them — a focus of 50 puts the first colour halfway along with the
|
|
299
|
+
* second at BOTH ends, which is what 23884's every slide asks for and why its
|
|
300
|
+
* background read as a flat wash into violet where the reference is blue
|
|
301
|
+
* across the middle and dark only at the corners.
|
|
302
|
+
*
|
|
303
|
+
* @param g The gradient as the `.ppt` states it.
|
|
304
|
+
* @returns The stops, in order.
|
|
305
|
+
*/
|
|
306
|
+
function gradientStops(g) {
|
|
307
|
+
const focus = g.focusPct ?? 0;
|
|
308
|
+
if (focus === 0) return [{
|
|
309
|
+
offset: 0,
|
|
310
|
+
colorHex: g.fromHex
|
|
311
|
+
}, {
|
|
312
|
+
offset: 1,
|
|
313
|
+
colorHex: g.toHex
|
|
314
|
+
}];
|
|
315
|
+
if (Math.abs(focus) >= 100) return [{
|
|
316
|
+
offset: 0,
|
|
317
|
+
colorHex: g.toHex
|
|
318
|
+
}, {
|
|
319
|
+
offset: 1,
|
|
320
|
+
colorHex: g.fromHex
|
|
321
|
+
}];
|
|
322
|
+
const peak = focus > 0 ? g.fromHex : g.toHex;
|
|
323
|
+
const ends = focus > 0 ? g.toHex : g.fromHex;
|
|
324
|
+
const at = focus > 0 ? focus / 100 : 1 + focus / 100;
|
|
325
|
+
return [
|
|
326
|
+
{
|
|
327
|
+
offset: 0,
|
|
328
|
+
colorHex: ends
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
offset: at,
|
|
332
|
+
colorHex: peak
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
offset: 1,
|
|
336
|
+
colorHex: ends
|
|
337
|
+
}
|
|
338
|
+
];
|
|
339
|
+
}
|
|
293
340
|
function positionedAutoShape(rect, auto, resources) {
|
|
294
341
|
const line = isLineShape(auto.shapeType);
|
|
295
342
|
const fill = line ? { kind: "none" } : auto.image ? {
|
|
296
343
|
kind: "picture",
|
|
297
344
|
imageResource: resources.put(auto.image.bytes),
|
|
298
|
-
...auto.imageTiled ? {
|
|
345
|
+
...auto.imageTiled ? {
|
|
346
|
+
tiled: true,
|
|
347
|
+
tileFromCentre: true
|
|
348
|
+
} : {},
|
|
299
349
|
...auto.tileSizePt ? { tileSizePt: auto.tileSizePt } : {}
|
|
300
350
|
} : auto.gradient ? {
|
|
301
351
|
kind: "gradient",
|
|
302
352
|
gradient: auto.gradient.radial ? {
|
|
303
353
|
kind: "radial",
|
|
304
|
-
stops:
|
|
305
|
-
offset: 0,
|
|
306
|
-
colorHex: auto.gradient.fromHex
|
|
307
|
-
}, {
|
|
308
|
-
offset: 1,
|
|
309
|
-
colorHex: auto.gradient.toHex
|
|
310
|
-
}]
|
|
354
|
+
stops: gradientStops(auto.gradient)
|
|
311
355
|
} : {
|
|
312
356
|
kind: "linear",
|
|
313
357
|
angle: auto.gradient.angleDeg,
|
|
314
|
-
stops:
|
|
315
|
-
offset: 0,
|
|
316
|
-
colorHex: auto.gradient.fromHex
|
|
317
|
-
}, {
|
|
318
|
-
offset: 1,
|
|
319
|
-
colorHex: auto.gradient.toHex
|
|
320
|
-
}]
|
|
358
|
+
stops: gradientStops(auto.gradient)
|
|
321
359
|
}
|
|
322
360
|
} : auto.fillColorHex ? {
|
|
323
361
|
kind: "solid",
|
|
@@ -353,13 +391,30 @@ function inFlowImage(image, resources) {
|
|
|
353
391
|
return {
|
|
354
392
|
kind: "image",
|
|
355
393
|
image: {
|
|
356
|
-
resource: resources.put(image
|
|
394
|
+
resource: resources.put(drawnBytes(image)),
|
|
357
395
|
width: pt(size.w * .75),
|
|
358
396
|
height: pt(size.h * .75),
|
|
397
|
+
...image.crop ? { crop: image.crop } : {},
|
|
359
398
|
paragraphProperties: {}
|
|
360
399
|
}
|
|
361
400
|
};
|
|
362
401
|
}
|
|
402
|
+
/**
|
|
403
|
+
* The bytes a picture is actually DRAWN from.
|
|
404
|
+
*
|
|
405
|
+
* §2.3.23 `pictureTransparent` names a colour the picture is drawn without, and
|
|
406
|
+
* a raster carries no alpha channel to say so — so the knock-out is baked into
|
|
407
|
+
* bytes of its own. The resource store hashes content, so two shapes knocking
|
|
408
|
+
* different colours out of the same blip stay two resources by themselves, and
|
|
409
|
+
* one that knocks out nothing keeps the bytes it arrived with.
|
|
410
|
+
*
|
|
411
|
+
* @param image The picture as the shape states it.
|
|
412
|
+
* @returns The bytes to store, knocked out where the shape asks for it.
|
|
413
|
+
*/
|
|
414
|
+
function drawnBytes(image) {
|
|
415
|
+
if (image.transparentHex === void 0 || isMetafile(image.bytes)) return image.bytes;
|
|
416
|
+
return knockOutColor(image.bytes, image.transparentHex) ?? image.bytes;
|
|
417
|
+
}
|
|
363
418
|
function isMetafile(d) {
|
|
364
419
|
return isEmf(d) || isWmf(d);
|
|
365
420
|
}
|
|
@@ -418,12 +473,25 @@ function toRun(r) {
|
|
|
418
473
|
function toParaProperties(p, breakBefore) {
|
|
419
474
|
const alignment = p.align !== void 0 ? alignmentFrom(p.align) : void 0;
|
|
420
475
|
const level = p.level ?? 0;
|
|
476
|
+
const leftPt = p.leftMarginPt ?? (level > 0 ? level * LEVEL_INDENT_PT : void 0);
|
|
477
|
+
const firstPt = p.indentPt !== void 0 ? p.indentPt - (leftPt ?? 0) : void 0;
|
|
421
478
|
return {
|
|
422
479
|
...breakBefore ? { pageBreakBefore: true } : {},
|
|
423
480
|
...alignment ? { alignment } : {},
|
|
424
|
-
...
|
|
481
|
+
...leftPt !== void 0 ? { indentLeft: pt(leftPt) } : {},
|
|
482
|
+
...firstPt !== void 0 && firstPt !== 0 ? { indentFirstLine: pt(firstPt) } : {},
|
|
483
|
+
...p.spaceBeforePt !== void 0 ? { spacingBefore: pt(p.spaceBeforePt) } : {},
|
|
484
|
+
...p.spaceAfterPt !== void 0 ? { spacingAfter: pt(p.spaceAfterPt) } : {},
|
|
485
|
+
...p.lineSpacing !== void 0 && p.lineSpacing > 0 ? {
|
|
486
|
+
spacingLineRule: "auto",
|
|
487
|
+
spacingLine: pt(p.lineSpacing / 100 * 12)
|
|
488
|
+
} : {}
|
|
425
489
|
};
|
|
426
490
|
}
|
|
491
|
+
/** Whether the paragraph's first line starts LEFT of its body — a hanging bullet. */
|
|
492
|
+
function hangs(p) {
|
|
493
|
+
return p.indentPt !== void 0 && p.leftMarginPt !== void 0 && p.indentPt < p.leftMarginPt;
|
|
494
|
+
}
|
|
427
495
|
function alignmentFrom(a) {
|
|
428
496
|
switch (a) {
|
|
429
497
|
case 1: return "center";
|