@office-kit/pptx-preview 0.9.1 → 0.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.js +1 -1
- package/dist/node.js +1 -1
- package/dist/{src-C_bsFwWV.js → src-B2rbAoIa.js} +272 -13
- package/dist/src-B2rbAoIa.js.map +1 -0
- package/package.json +3 -3
- package/dist/src-C_bsFwWV.js.map +0 -1
package/README.md
CHANGED
|
@@ -125,8 +125,10 @@ placeholder layout/master cascade), strokes, rotation, effects (shadow, glow,
|
|
|
125
125
|
soft edge, reflection), images with adjustments, charts (column, bar, line,
|
|
126
126
|
area, pie, doughnut, scatter, radar, bubble), tables with per-run cell text,
|
|
127
127
|
vertical and multi-column text in both text-layout modes, picture bullets, and
|
|
128
|
-
template (layout/master) decoration all render.
|
|
129
|
-
|
|
128
|
+
template (layout/master) decoration all render. EMF pictures containing solid-filled
|
|
129
|
+
line/Bézier paths, including rectangular and path clipping with copy semantics,
|
|
130
|
+
render as transparent SVG images. Other EMF drawing commands, WMF, SmartArt,
|
|
131
|
+
animations, and 3D fall back to labelled placeholders carrying a machine-readable marker
|
|
130
132
|
(below). Per-slide closeness to a LibreOffice baseline is measured and gated
|
|
131
133
|
in CI by the fidelity harness in the monorepo (`site/fidelity`) — mean
|
|
132
134
|
fg-SSIM ≈ 0.78 across the corpus, with the residual gaps documented there.
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as MONO, c as TIMES, d as substituteFamily, l as defaultMeasurer, n as renderSlideSvg, o as SANS, r as ARIAL, s as SERIF, t as auditTextLayout } from "./src-
|
|
1
|
+
import { a as MONO, c as TIMES, d as substituteFamily, l as defaultMeasurer, n as renderSlideSvg, o as SANS, r as ARIAL, s as SERIF, t as auditTextLayout } from "./src-B2rbAoIa.js";
|
|
2
2
|
export { ARIAL, MONO, SANS, SERIF, TIMES, auditTextLayout, defaultMeasurer, renderSlideSvg as renderSlideToSvg, substituteFamily };
|
package/dist/node.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as MONO, c as TIMES, d as substituteFamily, i as AVG_GLYPH_W_RATIO, l as defaultMeasurer, n as renderSlideSvg, o as SANS, r as ARIAL, s as SERIF, t as auditTextLayout, u as isCjk } from "./src-
|
|
1
|
+
import { a as MONO, c as TIMES, d as substituteFamily, i as AVG_GLYPH_W_RATIO, l as defaultMeasurer, n as renderSlideSvg, o as SANS, r as ARIAL, s as SERIF, t as auditTextLayout, u as isCjk } from "./src-B2rbAoIa.js";
|
|
2
2
|
import { getSlideSize } from "@office-kit/pptx";
|
|
3
3
|
import { Resvg } from "@resvg/resvg-js";
|
|
4
4
|
import * as fontkit from "fontkit";
|
|
@@ -1,4 +1,247 @@
|
|
|
1
|
-
import { getEffectiveColorMap, getGroupChildren, getGroupTransform, getParagraphAlignment, getParagraphBullet, getParagraphBulletImageBytes, getParagraphBulletStyle, getParagraphIndent, getParagraphLevel, getParagraphPropertiesEffective, getParagraphSpacing, getPresentationFonts, getPresentationTheme, getShapeAdjustValues, getShapeAltTitle, getShapeBodyPrEffective, getShapeBoundsResolved, getShapeChartSpec, getShapeClickAction, getShapeCustomGeometry, getShapeDescription, getShapeEffectsEffective, getShapeFillColorResolved, getShapeFillEffective, getShapeFlip, getShapeGradientFill, getShapeGradientFillEffective, getShapeHyperlink, getShapeHyperlinkTooltip, getShapeImageBiLevelThreshold, getShapeImageBrightness, getShapeImageBytes, getShapeImageContrast, getShapeImageCrop, getShapeImageDuotone, getShapeImageFillBytes, getShapeImageFormat, getShapeImageLinkUrl, getShapeImageOpacity, getShapeImagePartName, getShapeKind, getShapeName, getShapeParagraphCount, getShapeParagraphElements, getShapePatternFill, getShapePlaceholderType, getShapePreset, getShapeRotation, getShapeRunClickAction, getShapeRunFormat, getShapeRunFormatEffective, getShapeRunHyperlink, getShapeRunHyperlinkTooltip, getShapeStrokeArrow, getShapeStrokeCap, getShapeStrokeColorResolved, getShapeStrokeCompound, getShapeStrokeDash, getShapeStrokeEffective, getShapeStrokeJoin, getShapeTextAnchor, getShapeTextAutoFitParams, getShapeTextBodyRotationDeg, getShapeTextColumns, getShapeTextDirection, getShapeTextMargins, getShapeXmlString, getSlideBackground, getSlideBackgroundGradientFill, getSlideBackgroundImageBytes, getSlideBackgroundPatternFill, getSlideIndex, getSlideLayout, getSlideLayoutBackground, getSlideLayoutBackgroundGradientFill, getSlideLayoutBackgroundImageBytes, getSlideLayoutBackgroundPatternFill, getSlideLayoutShapes, getSlideMasterBackground, getSlideMasterBackgroundGradientFill, getSlideMasterBackgroundImageBytes, getSlideMasterBackgroundPatternFill, getSlideMasterShapes, getSlideShapes, getSlideSize, getSlides, getTableCellAnchor, getTableCellBorders, getTableCellFill, getTableCellMargins, getTableCellParagraphs, getTableCellSpan, getTableCells, getTableColumnWidths, getTableDimensions, getTableRowHeights, getTableStyleFlags, isChartShape, isParagraphBulletPicture, isShapeImageGrayscale, isShapePlaceholder, isShapeTextBox, isTableShape, resolveDeckBodyTextColor } from "@office-kit/pptx";
|
|
1
|
+
import { getEffectiveColorMap, getGroupChildren, getGroupTransform, getParagraphAlignment, getParagraphBullet, getParagraphBulletImageBytes, getParagraphBulletStyle, getParagraphIndent, getParagraphLevel, getParagraphPropertiesEffective, getParagraphSpacing, getPresentationFonts, getPresentationTheme, getShapeAdjustValues, getShapeAltTitle, getShapeBodyPrEffective, getShapeBoundsResolved, getShapeChartSpec, getShapeClickAction, getShapeCustomGeometry, getShapeDescription, getShapeEffectsEffective, getShapeFillColorResolved, getShapeFillEffective, getShapeFillOpacity, getShapeFlip, getShapeGradientFill, getShapeGradientFillEffective, getShapeHyperlink, getShapeHyperlinkTooltip, getShapeImageBiLevelThreshold, getShapeImageBrightness, getShapeImageBytes, getShapeImageContrast, getShapeImageCrop, getShapeImageDuotone, getShapeImageFillBytes, getShapeImageFormat, getShapeImageLinkUrl, getShapeImageOpacity, getShapeImagePartName, getShapeKind, getShapeName, getShapeParagraphCount, getShapeParagraphElements, getShapePatternFill, getShapePlaceholderType, getShapePreset, getShapeRotation, getShapeRunClickAction, getShapeRunFormat, getShapeRunFormatEffective, getShapeRunHyperlink, getShapeRunHyperlinkTooltip, getShapeStrokeArrow, getShapeStrokeCap, getShapeStrokeColorResolved, getShapeStrokeCompound, getShapeStrokeDash, getShapeStrokeEffective, getShapeStrokeJoin, getShapeStrokeOpacity, getShapeTextAnchor, getShapeTextAutoFitParams, getShapeTextBodyRotationDeg, getShapeTextColumns, getShapeTextDirection, getShapeTextMargins, getShapeXmlString, getSlideBackground, getSlideBackgroundGradientFill, getSlideBackgroundImageBytes, getSlideBackgroundPatternFill, getSlideIndex, getSlideLayout, getSlideLayoutBackground, getSlideLayoutBackgroundGradientFill, getSlideLayoutBackgroundImageBytes, getSlideLayoutBackgroundPatternFill, getSlideLayoutShapes, getSlideMasterBackground, getSlideMasterBackgroundGradientFill, getSlideMasterBackgroundImageBytes, getSlideMasterBackgroundPatternFill, getSlideMasterShapes, getSlideShapes, getSlideSize, getSlides, getTableCellAnchor, getTableCellBorders, getTableCellFill, getTableCellMargins, getTableCellParagraphs, getTableCellSpan, getTableCells, getTableColumnWidths, getTableDimensions, getTableRowHeights, getTableStyleFlags, isChartShape, isParagraphBulletPicture, isShapeImageGrayscale, isShapePlaceholder, isShapeTextBox, isTableShape, resolveDeckBodyTextColor } from "@office-kit/pptx";
|
|
2
|
+
//#region src/emf.ts
|
|
3
|
+
const WORD_BYTES = 4;
|
|
4
|
+
const SHORT_BYTES = 2;
|
|
5
|
+
const RECORD_HEADER_BYTES = 8;
|
|
6
|
+
const HEADER_MIN_BYTES = 88;
|
|
7
|
+
const VALUE_RECORD_BYTES = 12;
|
|
8
|
+
const PAIR_RECORD_BYTES = 16;
|
|
9
|
+
const BOUNDS_RECORD_BYTES = 24;
|
|
10
|
+
const BRUSH_RECORD_BYTES = 24;
|
|
11
|
+
const EOF_MIN_BYTES = 20;
|
|
12
|
+
const HEADER_BOUNDS_OFFSET = 8;
|
|
13
|
+
const HEADER_FILE_SIZE_OFFSET = 48;
|
|
14
|
+
const HEADER_RECORD_COUNT_OFFSET = 52;
|
|
15
|
+
const VALUE_OFFSET = RECORD_HEADER_BYTES;
|
|
16
|
+
const SECOND_VALUE_OFFSET = 12;
|
|
17
|
+
const BRUSH_COLOR_OFFSET = 16;
|
|
18
|
+
const RGB_CHANNEL_COUNT = 3;
|
|
19
|
+
const HEX_RADIX = 16;
|
|
20
|
+
const EMFPLUS_COMMENT = 726027589;
|
|
21
|
+
const SIGNATURE_OFFSET = 40;
|
|
22
|
+
const SIGNATURE = 1179469088;
|
|
23
|
+
const POINT_COUNT_OFFSET = 24;
|
|
24
|
+
const POINTS_OFFSET = 28;
|
|
25
|
+
const BEZIER_POINT_COUNT = 3;
|
|
26
|
+
const STOCK_OBJECT_FLAG = 2147483648;
|
|
27
|
+
const REGION_COPY = 5;
|
|
28
|
+
const MAP_TEXT = 1;
|
|
29
|
+
const MAP_ANISOTROPIC = 8;
|
|
30
|
+
const BRUSH_SOLID = 0;
|
|
31
|
+
const BRUSH_NULL = 1;
|
|
32
|
+
const FILL_ALTERNATE = 1;
|
|
33
|
+
const FILL_WINDING = 2;
|
|
34
|
+
const STOCK_BRUSHES = [
|
|
35
|
+
"#ffffff",
|
|
36
|
+
"#c0c0c0",
|
|
37
|
+
"#808080",
|
|
38
|
+
"#404040",
|
|
39
|
+
"#000000",
|
|
40
|
+
"none"
|
|
41
|
+
];
|
|
42
|
+
const RECORD = {
|
|
43
|
+
HEADER: 1,
|
|
44
|
+
POLYBEZIERTO: 5,
|
|
45
|
+
POLYLINETO: 6,
|
|
46
|
+
SETWINDOWEXTEX: 9,
|
|
47
|
+
SETWINDOWORGEX: 10,
|
|
48
|
+
SETVIEWPORTEXTEX: 11,
|
|
49
|
+
SETVIEWPORTORGEX: 12,
|
|
50
|
+
SETBRUSHORGEX: 13,
|
|
51
|
+
EOF: 14,
|
|
52
|
+
SETMAPMODE: 17,
|
|
53
|
+
SETBKMODE: 18,
|
|
54
|
+
SETPOLYFILLMODE: 19,
|
|
55
|
+
SETSTRETCHBLTMODE: 21,
|
|
56
|
+
SETTEXTALIGN: 22,
|
|
57
|
+
MOVETOEX: 27,
|
|
58
|
+
SELECTOBJECT: 37,
|
|
59
|
+
CREATEBRUSHINDIRECT: 39,
|
|
60
|
+
DELETEOBJECT: 40,
|
|
61
|
+
BEGINPATH: 59,
|
|
62
|
+
ENDPATH: 60,
|
|
63
|
+
CLOSEFIGURE: 61,
|
|
64
|
+
FILLPATH: 62,
|
|
65
|
+
SELECTCLIPPATH: 67,
|
|
66
|
+
COMMENT: 70,
|
|
67
|
+
EXTSELECTCLIPRGN: 75,
|
|
68
|
+
POLYBEZIERTO16: 88,
|
|
69
|
+
POLYLINETO16: 89
|
|
70
|
+
};
|
|
71
|
+
const renderEmfToSvg = (bytes) => {
|
|
72
|
+
if (bytes.byteLength < HEADER_MIN_BYTES) return null;
|
|
73
|
+
const file = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
74
|
+
if (file.getUint32(0, true) !== RECORD.HEADER || file.getUint32(SIGNATURE_OFFSET, true) !== SIGNATURE) return null;
|
|
75
|
+
const left = file.getInt32(HEADER_BOUNDS_OFFSET, true);
|
|
76
|
+
const top = file.getInt32(12, true);
|
|
77
|
+
const width = file.getInt32(16, true) - left;
|
|
78
|
+
const height = file.getInt32(20, true) - top;
|
|
79
|
+
if (width <= 0 || height <= 0 || file.getUint32(HEADER_FILE_SIZE_OFFSET, true) !== bytes.byteLength) return null;
|
|
80
|
+
let windowX = 0;
|
|
81
|
+
let windowY = 0;
|
|
82
|
+
let windowWidth = 1;
|
|
83
|
+
let windowHeight = 1;
|
|
84
|
+
let viewportX = 0;
|
|
85
|
+
let viewportY = 0;
|
|
86
|
+
let viewportWidth = 1;
|
|
87
|
+
let viewportHeight = 1;
|
|
88
|
+
let mapMode = MAP_TEXT;
|
|
89
|
+
let fillRule = "evenodd";
|
|
90
|
+
let brush = "#ffffff";
|
|
91
|
+
const brushes = /* @__PURE__ */ new Map();
|
|
92
|
+
let path = [];
|
|
93
|
+
let recordingPath = false;
|
|
94
|
+
let clip = "";
|
|
95
|
+
let clipCount = 0;
|
|
96
|
+
const definitions = [];
|
|
97
|
+
const drawings = [];
|
|
98
|
+
let recordCount = 0;
|
|
99
|
+
const point = (x, y) => {
|
|
100
|
+
if (mapMode === MAP_TEXT) return `${x} ${y}`;
|
|
101
|
+
return `${(x - windowX) * viewportWidth / windowWidth + viewportX} ${(y - windowY) * viewportHeight / windowHeight + viewportY}`;
|
|
102
|
+
};
|
|
103
|
+
for (let offset = 0; offset < bytes.byteLength;) {
|
|
104
|
+
if (bytes.byteLength - offset < RECORD_HEADER_BYTES) return null;
|
|
105
|
+
const type = file.getUint32(offset, true);
|
|
106
|
+
const size = file.getUint32(offset + WORD_BYTES, true);
|
|
107
|
+
if (size < RECORD_HEADER_BYTES || size % WORD_BYTES !== 0 || size > bytes.byteLength - offset) return null;
|
|
108
|
+
const record = new DataView(bytes.buffer, bytes.byteOffset + offset, size);
|
|
109
|
+
const unsigned = (at) => record.getUint32(at, true);
|
|
110
|
+
const signed = (at) => record.getInt32(at, true);
|
|
111
|
+
recordCount++;
|
|
112
|
+
switch (type) {
|
|
113
|
+
case RECORD.HEADER:
|
|
114
|
+
if (offset !== 0 || size < HEADER_MIN_BYTES) return null;
|
|
115
|
+
break;
|
|
116
|
+
case RECORD.EOF:
|
|
117
|
+
if (size < EOF_MIN_BYTES || offset + size !== bytes.byteLength || recordingPath || recordCount !== file.getUint32(HEADER_RECORD_COUNT_OFFSET, true)) return null;
|
|
118
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${left} ${top} ${width} ${height}" width="${width}" height="${height}"><defs>${definitions.join("")}</defs>${drawings.join("")}</svg>`;
|
|
119
|
+
case RECORD.SETMAPMODE:
|
|
120
|
+
if (size < VALUE_RECORD_BYTES) return null;
|
|
121
|
+
mapMode = unsigned(VALUE_OFFSET);
|
|
122
|
+
if (mapMode !== MAP_TEXT && mapMode !== MAP_ANISOTROPIC) return null;
|
|
123
|
+
break;
|
|
124
|
+
case RECORD.SETWINDOWORGEX:
|
|
125
|
+
case RECORD.SETVIEWPORTORGEX:
|
|
126
|
+
case RECORD.SETWINDOWEXTEX:
|
|
127
|
+
case RECORD.SETVIEWPORTEXTEX: {
|
|
128
|
+
if (size < PAIR_RECORD_BYTES) return null;
|
|
129
|
+
const x = signed(VALUE_OFFSET);
|
|
130
|
+
const y = signed(SECOND_VALUE_OFFSET);
|
|
131
|
+
if (type === RECORD.SETWINDOWORGEX) {
|
|
132
|
+
windowX = x;
|
|
133
|
+
windowY = y;
|
|
134
|
+
} else if (type === RECORD.SETVIEWPORTORGEX) {
|
|
135
|
+
viewportX = x;
|
|
136
|
+
viewportY = y;
|
|
137
|
+
} else {
|
|
138
|
+
if (x === 0 || y === 0) return null;
|
|
139
|
+
if (type === RECORD.SETWINDOWEXTEX) {
|
|
140
|
+
windowWidth = x;
|
|
141
|
+
windowHeight = y;
|
|
142
|
+
} else {
|
|
143
|
+
viewportWidth = x;
|
|
144
|
+
viewportHeight = y;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case RECORD.CREATEBRUSHINDIRECT: {
|
|
150
|
+
if (size < BRUSH_RECORD_BYTES) return null;
|
|
151
|
+
const style = unsigned(SECOND_VALUE_OFFSET);
|
|
152
|
+
if (style !== BRUSH_SOLID && style !== BRUSH_NULL) return null;
|
|
153
|
+
const color = [...bytes.subarray(offset + BRUSH_COLOR_OFFSET, offset + BRUSH_COLOR_OFFSET + RGB_CHANNEL_COUNT)].map((channel) => channel.toString(HEX_RADIX).padStart(2, "0")).join("");
|
|
154
|
+
brushes.set(unsigned(VALUE_OFFSET), style === BRUSH_NULL ? "none" : `#${color}`);
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
case RECORD.SELECTOBJECT: {
|
|
158
|
+
if (size < VALUE_RECORD_BYTES) return null;
|
|
159
|
+
const handle = unsigned(VALUE_OFFSET);
|
|
160
|
+
const selected = handle >= STOCK_OBJECT_FLAG ? STOCK_BRUSHES[handle - STOCK_OBJECT_FLAG] : brushes.get(handle);
|
|
161
|
+
if (selected === void 0) return null;
|
|
162
|
+
brush = selected;
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case RECORD.DELETEOBJECT:
|
|
166
|
+
if (size < VALUE_RECORD_BYTES) return null;
|
|
167
|
+
brushes.delete(unsigned(VALUE_OFFSET));
|
|
168
|
+
break;
|
|
169
|
+
case RECORD.SETPOLYFILLMODE:
|
|
170
|
+
if (size < VALUE_RECORD_BYTES || unsigned(VALUE_OFFSET) !== FILL_ALTERNATE && unsigned(VALUE_OFFSET) !== FILL_WINDING) return null;
|
|
171
|
+
fillRule = unsigned(VALUE_OFFSET) === FILL_WINDING ? "nonzero" : "evenodd";
|
|
172
|
+
break;
|
|
173
|
+
case RECORD.BEGINPATH:
|
|
174
|
+
path = [];
|
|
175
|
+
recordingPath = true;
|
|
176
|
+
break;
|
|
177
|
+
case RECORD.MOVETOEX:
|
|
178
|
+
if (size < PAIR_RECORD_BYTES || !recordingPath) return null;
|
|
179
|
+
path.push(`M${point(signed(VALUE_OFFSET), signed(SECOND_VALUE_OFFSET))}`);
|
|
180
|
+
break;
|
|
181
|
+
case RECORD.POLYLINETO:
|
|
182
|
+
case RECORD.POLYLINETO16:
|
|
183
|
+
case RECORD.POLYBEZIERTO:
|
|
184
|
+
case RECORD.POLYBEZIERTO16: {
|
|
185
|
+
if (size < POINTS_OFFSET || !recordingPath || path.length === 0) return null;
|
|
186
|
+
const short = type === RECORD.POLYLINETO16 || type === RECORD.POLYBEZIERTO16;
|
|
187
|
+
const bezier = type === RECORD.POLYBEZIERTO || type === RECORD.POLYBEZIERTO16;
|
|
188
|
+
const coordinateBytes = short ? SHORT_BYTES : WORD_BYTES;
|
|
189
|
+
const pointBytes = coordinateBytes * 2;
|
|
190
|
+
const count = unsigned(POINT_COUNT_OFFSET);
|
|
191
|
+
if (count > Math.floor((size - POINTS_OFFSET) / pointBytes) || bezier && count % BEZIER_POINT_COUNT !== 0) return null;
|
|
192
|
+
for (let index = 0; index < count; index++) {
|
|
193
|
+
const at = POINTS_OFFSET + index * pointBytes;
|
|
194
|
+
const x = short ? record.getInt16(at, true) : signed(at);
|
|
195
|
+
const y = short ? record.getInt16(at + coordinateBytes, true) : signed(at + coordinateBytes);
|
|
196
|
+
const command = bezier ? index % BEZIER_POINT_COUNT === 0 ? "C" : " " : "L";
|
|
197
|
+
path.push(`${command}${point(x, y)}`);
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case RECORD.CLOSEFIGURE:
|
|
202
|
+
if (!recordingPath || path.length === 0) return null;
|
|
203
|
+
path.push("Z");
|
|
204
|
+
break;
|
|
205
|
+
case RECORD.ENDPATH:
|
|
206
|
+
if (!recordingPath) return null;
|
|
207
|
+
recordingPath = false;
|
|
208
|
+
break;
|
|
209
|
+
case RECORD.FILLPATH:
|
|
210
|
+
if (size < BOUNDS_RECORD_BYTES || recordingPath || path.length === 0) return null;
|
|
211
|
+
drawings.push(`<path d="${path.join("")}" fill="${brush}" fill-rule="${fillRule}"${clip}/>`);
|
|
212
|
+
path = [];
|
|
213
|
+
break;
|
|
214
|
+
case RECORD.SELECTCLIPPATH: {
|
|
215
|
+
if (size < VALUE_RECORD_BYTES || unsigned(VALUE_OFFSET) !== REGION_COPY || recordingPath || path.length === 0) return null;
|
|
216
|
+
const id = `emf-clip-${clipCount++}`;
|
|
217
|
+
definitions.push(`<clipPath id="${id}"><path d="${path.join("")}" clip-rule="${fillRule}"/></clipPath>`);
|
|
218
|
+
clip = ` clip-path="url(#${id})"`;
|
|
219
|
+
path = [];
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case RECORD.EXTSELECTCLIPRGN:
|
|
223
|
+
if (size < PAIR_RECORD_BYTES || unsigned(VALUE_OFFSET) !== 0 || unsigned(SECOND_VALUE_OFFSET) !== REGION_COPY) return null;
|
|
224
|
+
clip = "";
|
|
225
|
+
break;
|
|
226
|
+
case RECORD.COMMENT:
|
|
227
|
+
if (size < VALUE_RECORD_BYTES || unsigned(VALUE_OFFSET) > size - VALUE_RECORD_BYTES) return null;
|
|
228
|
+
if (unsigned(VALUE_OFFSET) >= WORD_BYTES && unsigned(SECOND_VALUE_OFFSET) === EMFPLUS_COMMENT) return null;
|
|
229
|
+
break;
|
|
230
|
+
case RECORD.SETBKMODE:
|
|
231
|
+
case RECORD.SETSTRETCHBLTMODE:
|
|
232
|
+
case RECORD.SETTEXTALIGN:
|
|
233
|
+
if (size < VALUE_RECORD_BYTES) return null;
|
|
234
|
+
break;
|
|
235
|
+
case RECORD.SETBRUSHORGEX:
|
|
236
|
+
if (size < PAIR_RECORD_BYTES) return null;
|
|
237
|
+
break;
|
|
238
|
+
default: return null;
|
|
239
|
+
}
|
|
240
|
+
offset += size;
|
|
241
|
+
}
|
|
242
|
+
return null;
|
|
243
|
+
};
|
|
244
|
+
//#endregion
|
|
2
245
|
//#region src/text-layout.ts
|
|
3
246
|
const SANS = "Carlito";
|
|
4
247
|
const SERIF = "Caladea";
|
|
@@ -530,6 +773,13 @@ const mimeFromPartName = (name) => {
|
|
|
530
773
|
const renderPicture = (shape, pres, x, y, w, h, transform, textOverlay, bytes, format) => {
|
|
531
774
|
let mime = null;
|
|
532
775
|
if (bytes && format) mime = imageMime[format] ?? null;
|
|
776
|
+
if (bytes && !mime) {
|
|
777
|
+
const svg = renderEmfToSvg(bytes);
|
|
778
|
+
if (svg !== null) {
|
|
779
|
+
bytes = new TextEncoder().encode(svg);
|
|
780
|
+
mime = "image/svg+xml";
|
|
781
|
+
}
|
|
782
|
+
}
|
|
533
783
|
if (bytes && !mime) mime = mimeFromPartName(getShapeImagePartName(shape));
|
|
534
784
|
if (bytes && mime) {
|
|
535
785
|
const dataUrl = `data:${mime};base64,${u8ToBase64(bytes)}`;
|
|
@@ -669,7 +919,8 @@ let activeColorMap = null;
|
|
|
669
919
|
let activeDeckTextColor = "#000000";
|
|
670
920
|
const gradientDef = (grad, theme) => {
|
|
671
921
|
const id = mintId();
|
|
672
|
-
const
|
|
922
|
+
const orderedStops = [...grad.stops].sort((a, b) => a.offset - b.offset);
|
|
923
|
+
const stops = orderedStops.map((s) => `<stop offset="${s.offset.toFixed(4)}" stop-color="${resolveColor(s.color, theme, "#E5E7EB")}"/>`).join("");
|
|
673
924
|
if (grad.path === "circle" || grad.path === "rect" || grad.path === "shape") {
|
|
674
925
|
const focus = grad.focus ?? {
|
|
675
926
|
left: .5,
|
|
@@ -679,7 +930,7 @@ const gradientDef = (grad, theme) => {
|
|
|
679
930
|
};
|
|
680
931
|
const cx = (focus.left + focus.right) / 2;
|
|
681
932
|
const cy = (focus.top + focus.bottom) / 2;
|
|
682
|
-
const reversed =
|
|
933
|
+
const reversed = orderedStops.slice().reverse().map((s) => `<stop offset="${(1 - s.offset).toFixed(4)}" stop-color="${resolveColor(s.color, theme, "#E5E7EB")}"/>`).join("");
|
|
683
934
|
return {
|
|
684
935
|
defs: `<defs><radialGradient id="${id}" gradientUnits="objectBoundingBox" cx="${cx.toFixed(4)}" cy="${cy.toFixed(4)}" r="${Math.max(.5, Math.max(cx, cy, 1 - cx, 1 - cy)).toFixed(4)}">${reversed}</radialGradient></defs>`,
|
|
685
936
|
fillAttr: `url(#${id})`
|
|
@@ -811,11 +1062,14 @@ const buildArrowMarker = (type, width, length, color, orient) => {
|
|
|
811
1062
|
};
|
|
812
1063
|
const paint = (shape, fill, stroke, theme, isPlaceholder, pres) => {
|
|
813
1064
|
let fillColor;
|
|
1065
|
+
let fillAttrs = "";
|
|
814
1066
|
let defs = "";
|
|
815
1067
|
if (fill.kind === "solid") {
|
|
816
1068
|
let resolved = null;
|
|
817
1069
|
if (shape && pres) resolved = getShapeFillColorResolved(pres, shape);
|
|
818
1070
|
fillColor = resolved ?? resolveColor(fill.color, theme, "#E5E7EB");
|
|
1071
|
+
const opacity = shape ? getShapeFillOpacity(shape) : null;
|
|
1072
|
+
if (opacity !== null && opacity < 1) fillAttrs = ` fill-opacity="${opacity.toFixed(3)}"`;
|
|
819
1073
|
} else if (fill.kind === "none") fillColor = "none";
|
|
820
1074
|
else if (fill.kind === "gradient") {
|
|
821
1075
|
const grad = shape ? pres ? getShapeGradientFillEffective(pres, shape) : getShapeGradientFill(shape) : null;
|
|
@@ -843,6 +1097,8 @@ const paint = (shape, fill, stroke, theme, isPlaceholder, pres) => {
|
|
|
843
1097
|
strokeColor = resolved ?? resolveColor(stroke.color, theme, "#9CA3AF");
|
|
844
1098
|
strokeWidth = stroke.widthEmu ?? 9525;
|
|
845
1099
|
if (shape) {
|
|
1100
|
+
const opacity = getShapeStrokeOpacity(shape);
|
|
1101
|
+
if (opacity !== null && opacity < 1) strokeAttrParts.push(`stroke-opacity="${opacity.toFixed(3)}"`);
|
|
846
1102
|
const dash = getShapeStrokeDash(shape);
|
|
847
1103
|
if (dash && dash !== "solid") {
|
|
848
1104
|
const pattern = DASH_PATTERNS[dash];
|
|
@@ -877,6 +1133,7 @@ const paint = (shape, fill, stroke, theme, isPlaceholder, pres) => {
|
|
|
877
1133
|
}
|
|
878
1134
|
return {
|
|
879
1135
|
fill: fillColor,
|
|
1136
|
+
fillAttrs,
|
|
880
1137
|
stroke: strokeColor,
|
|
881
1138
|
strokeWidth,
|
|
882
1139
|
defs,
|
|
@@ -4042,7 +4299,7 @@ const arcToCubicSegments = (startX, startY, wR, hR, stAng, swAng) => {
|
|
|
4042
4299
|
* Per-path `fill="none"` paints stroke-only; `stroke="0"` paints
|
|
4043
4300
|
* fill-only — mirroring `ST_PathFillMode` / the path `stroke` flag.
|
|
4044
4301
|
*/
|
|
4045
|
-
const customGeometryToSvg = (geom, x, y, w, h, fill, stroke, strokeWidthEmu, strokeExtra, markerExtra) => {
|
|
4302
|
+
const customGeometryToSvg = (geom, x, y, w, h, fill, fillExtra, stroke, strokeWidthEmu, strokeExtra, markerExtra) => {
|
|
4046
4303
|
const out = [];
|
|
4047
4304
|
for (const path of geom.paths) {
|
|
4048
4305
|
const cw = path.w ?? w;
|
|
@@ -4099,8 +4356,9 @@ const customGeometryToSvg = (geom, x, y, w, h, fill, stroke, strokeWidthEmu, str
|
|
|
4099
4356
|
}
|
|
4100
4357
|
if (d.length === 0) continue;
|
|
4101
4358
|
const pathFill = path.fill === "none" ? "none" : fill;
|
|
4359
|
+
const fillAttrs = path.fill === "none" ? "" : fillExtra;
|
|
4102
4360
|
const strokeAttrs = path.stroke ? ` stroke="${stroke}" stroke-width="${E(strokeWidthEmu)}"${strokeExtra}${markerExtra}` : " stroke=\"none\"";
|
|
4103
|
-
out.push(`<path d="${d.join(" ")}" fill="${pathFill}"${strokeAttrs} fill-rule="evenodd"/>`);
|
|
4361
|
+
out.push(`<path d="${d.join(" ")}" fill="${pathFill}"${fillAttrs}${strokeAttrs} fill-rule="evenodd"/>`);
|
|
4104
4362
|
}
|
|
4105
4363
|
return out.join("");
|
|
4106
4364
|
};
|
|
@@ -4244,25 +4502,26 @@ const renderShape = (shape, pres, theme, ctx) => {
|
|
|
4244
4502
|
}
|
|
4245
4503
|
const rawPreset = getShapePreset(shape);
|
|
4246
4504
|
const preset = rawPreset ?? "rect";
|
|
4505
|
+
const fa = p.fillAttrs;
|
|
4247
4506
|
const sa = p.strokeAttrs ? ` ${p.strokeAttrs}` : "";
|
|
4248
4507
|
const ma = p.markerAttrs ?? "";
|
|
4249
4508
|
const customGeom = rawPreset === null ? getShapeCustomGeometry(shape) : null;
|
|
4250
|
-
let geomSvg = customGeom !== null ? customGeometryToSvg(customGeom, x, y, w, h, p.fill, p.stroke, p.strokeWidth, sa, ma) : "";
|
|
4509
|
+
let geomSvg = customGeom !== null ? customGeometryToSvg(customGeom, x, y, w, h, p.fill, fa, p.stroke, p.strokeWidth, sa, ma) : "";
|
|
4251
4510
|
const isCustGeom = geomSvg === "" && rawPreset === null && getShapeXmlString(shape).includes("custGeom");
|
|
4252
|
-
if (geomSvg !== "") {} else if (preset === "rect") geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4511
|
+
if (geomSvg !== "") {} else if (preset === "rect") geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4253
4512
|
else if (preset === "roundRect") {
|
|
4254
4513
|
const adjVal = getShapeAdjustValues(shape).adj ?? 16667;
|
|
4255
4514
|
const ratio = Math.max(0, Math.min(.5, adjVal / 1e5));
|
|
4256
4515
|
const r = E(Math.min(w, h) * ratio);
|
|
4257
|
-
geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" rx="${r}" ry="${r}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4258
|
-
} else if (preset === "ellipse" || preset === "oval") geomSvg = `<ellipse cx="${E(cx)}" cy="${E(cy)}" rx="${E(w / 2)}" ry="${E(h / 2)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4516
|
+
geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" rx="${r}" ry="${r}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4517
|
+
} else if (preset === "ellipse" || preset === "oval") geomSvg = `<ellipse cx="${E(cx)}" cy="${E(cy)}" rx="${E(w / 2)}" ry="${E(h / 2)}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4259
4518
|
else {
|
|
4260
4519
|
const pathFn = PRESET_PATHS[preset];
|
|
4261
|
-
if (pathFn) geomSvg = `<path d="${pathFn(x / EMU_PER_PX, y / EMU_PER_PX, w / EMU_PER_PX, h / EMU_PER_PX)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}" fill-rule="evenodd"${sa}${ma}/>`;
|
|
4520
|
+
if (pathFn) geomSvg = `<path d="${pathFn(x / EMU_PER_PX, y / EMU_PER_PX, w / EMU_PER_PX, h / EMU_PER_PX)}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}" fill-rule="evenodd"${sa}${ma}/>`;
|
|
4262
4521
|
else {
|
|
4263
4522
|
const pointsFn = PRESET_POINTS[preset];
|
|
4264
|
-
if (pointsFn) geomSvg = `<polygon points="${pointsFn(w / EMU_PER_PX, h / EMU_PER_PX).map(([nx, ny]) => `${E(x + nx * w)},${E(y + ny * h)}`).join(" ")}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4265
|
-
else geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" fill="${p.fill}" stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma} data-pptx-preset="${escapeXml(preset)}"><title>${escapeXml(`preset: ${preset}`)}</title></rect>`;
|
|
4523
|
+
if (pointsFn) geomSvg = `<polygon points="${pointsFn(w / EMU_PER_PX, h / EMU_PER_PX).map(([nx, ny]) => `${E(x + nx * w)},${E(y + ny * h)}`).join(" ")}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma}/>`;
|
|
4524
|
+
else geomSvg = `<rect x="${E(x)}" y="${E(y)}" width="${E(w)}" height="${E(h)}" fill="${p.fill}"${fa} stroke="${p.stroke}" stroke-width="${E(p.strokeWidth)}"${sa}${ma} data-pptx-preset="${escapeXml(preset)}"><title>${escapeXml(`preset: ${preset}`)}</title></rect>`;
|
|
4266
4525
|
}
|
|
4267
4526
|
}
|
|
4268
4527
|
const fx = buildEffectsFilter(pres, shape);
|
|
@@ -4685,4 +4944,4 @@ const auditTextLayout = (pres, options = {}) => {
|
|
|
4685
4944
|
//#endregion
|
|
4686
4945
|
export { MONO as a, TIMES as c, substituteFamily as d, AVG_GLYPH_W_RATIO as i, defaultMeasurer as l, renderSlideSvg as n, SANS as o, ARIAL as r, SERIF as s, auditTextLayout as t, isCjk as u };
|
|
4687
4946
|
|
|
4688
|
-
//# sourceMappingURL=src-
|
|
4947
|
+
//# sourceMappingURL=src-B2rbAoIa.js.map
|