reamkit 1.15.4 → 1.17.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/bidi/segments.js +1 -2
- package/dist/esm/core/converter/facade.d.ts +5 -0
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/converter/ream.d.ts +6 -0
- package/dist/esm/core/converter/ream.js +34 -8
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +659 -7
- package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
- package/dist/esm/core/drawingml/chart-geometry.js +424 -92
- package/dist/esm/core/drawingml/chart-parser.js +301 -11
- package/dist/esm/core/drawingml/colors.d.ts +7 -7
- package/dist/esm/core/drawingml/colors.js +84 -18
- package/dist/esm/core/drawingml/preset-geometry.js +240 -6
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
- package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
- package/dist/esm/core/drawingml/theme-parser.js +92 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/font/ttf-subset.js +26 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +353 -43
- package/dist/esm/core/indexed-colors.d.ts +11 -0
- package/dist/esm/core/indexed-colors.js +81 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/ir/sheet.d.ts +61 -0
- package/dist/esm/{excel → core}/number-format.d.ts +37 -0
- package/dist/esm/core/number-format.js +800 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/opc/alternate-content.d.ts +13 -0
- package/dist/esm/core/opc/alternate-content.js +72 -0
- package/dist/esm/core/opc/core-properties.js +1 -0
- package/dist/esm/core/opc/package.d.ts +14 -1
- package/dist/esm/core/opc/package.js +43 -4
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/opc/xml-entities.d.ts +12 -0
- package/dist/esm/core/opc/xml-entities.js +91 -0
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/vector.d.ts +30 -0
- package/dist/esm/excel/activex-parser.js +1 -0
- package/dist/esm/excel/column-bands.d.ts +26 -1
- package/dist/esm/excel/column-bands.js +156 -20
- package/dist/esm/excel/comments-parser.js +5 -3
- package/dist/esm/excel/conditional-format.d.ts +25 -2
- package/dist/esm/excel/conditional-format.js +63 -19
- package/dist/esm/excel/escaped-text.d.ts +9 -0
- package/dist/esm/excel/escaped-text.js +20 -0
- package/dist/esm/excel/form-control-parser.js +1 -0
- package/dist/esm/excel/formula/dates.js +1 -1
- package/dist/esm/excel/header-footer.d.ts +9 -1
- package/dist/esm/excel/header-footer.js +162 -14
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/index.js +2 -2
- package/dist/esm/excel/pivot-table-parser.js +1 -0
- package/dist/esm/excel/print-model.d.ts +75 -0
- package/dist/esm/excel/print-model.js +899 -77
- package/dist/esm/excel/printer-settings.d.ts +16 -0
- package/dist/esm/excel/printer-settings.js +36 -0
- package/dist/esm/excel/rich-value.d.ts +13 -0
- package/dist/esm/excel/rich-value.js +120 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -7
- package/dist/esm/excel/sheet-drawing.d.ts +11 -0
- package/dist/esm/excel/sheet-drawing.js +26 -3
- package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
- package/dist/esm/excel/sheet-shape-parser.js +461 -32
- package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
- package/dist/esm/excel/sheet-to-flow.js +553 -36
- package/dist/esm/excel/slicer-parser.js +1 -0
- package/dist/esm/excel/styles-parser.d.ts +30 -2
- package/dist/esm/excel/styles-parser.js +177 -40
- package/dist/esm/excel/table-parser.js +1 -0
- package/dist/esm/excel/vml-drawing.d.ts +68 -0
- package/dist/esm/excel/vml-drawing.js +158 -0
- package/dist/esm/excel/workbook-parser.d.ts +5 -0
- package/dist/esm/excel/workbook-parser.js +5 -1
- package/dist/esm/excel/worksheet-parser.d.ts +2 -1
- package/dist/esm/excel/worksheet-parser.js +150 -61
- package/dist/esm/excel/xlsx-reader.js +242 -11
- package/dist/esm/excel/xlsx-to-pdf.js +12 -1
- package/dist/esm/html/html-writer.js +29 -6
- package/dist/esm/layout/page-doc.d.ts +87 -1
- package/dist/esm/layout/styled-layout.d.ts +46 -2
- package/dist/esm/layout/styled-layout.js +2345 -274
- package/dist/esm/pdf/cid-font.js +20 -9
- package/dist/esm/pdf/objects.d.ts +13 -0
- package/dist/esm/pdf/objects.js +18 -1
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +355 -49
- package/dist/esm/pdf/text-page-renderer.js +1 -0
- package/dist/esm/pdf/vector-graphics.d.ts +31 -2
- package/dist/esm/pdf/vector-graphics.js +103 -3
- package/dist/esm/pptx/pptx-reader.js +2 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +98 -24
- package/dist/esm/svg/svg-writer.js +23 -4
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +538 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +86 -5
- package/dist/esm/word/drawing-parser.js +1590 -54
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +108 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +32 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +9 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +7 -3
- package/dist/esm/excel/number-format.js +0 -476
|
@@ -86,8 +86,33 @@ function presetPaths(preset, w, h, adjust) {
|
|
|
86
86
|
[0, h / 2]
|
|
87
87
|
])];
|
|
88
88
|
}
|
|
89
|
+
case "round1Rect":
|
|
90
|
+
case "round2SameRect":
|
|
91
|
+
case "round2DiagRect":
|
|
92
|
+
case "snip1Rect":
|
|
93
|
+
case "snip2SameRect":
|
|
94
|
+
case "snip2DiagRect":
|
|
95
|
+
case "snipRoundRect": return [cornerRect(preset, w, h, adjust)];
|
|
96
|
+
case "star4":
|
|
97
|
+
case "star5":
|
|
98
|
+
case "star6":
|
|
99
|
+
case "star7":
|
|
100
|
+
case "star8":
|
|
101
|
+
case "star10":
|
|
102
|
+
case "star12":
|
|
103
|
+
case "star16":
|
|
104
|
+
case "star24":
|
|
105
|
+
case "star32": {
|
|
106
|
+
const s = STARS.get(preset);
|
|
107
|
+
return s ? [star(w, h, s, adjust)] : null;
|
|
108
|
+
}
|
|
89
109
|
case "line":
|
|
90
110
|
case "straightConnector1": return [new PathBuilder().moveTo(0, h).lineTo(w, 0).build()];
|
|
111
|
+
case "bentConnector2": return [new PathBuilder().moveTo(0, h).lineTo(w, h).lineTo(w, 0).build()];
|
|
112
|
+
case "bentConnector3": {
|
|
113
|
+
const bx = clamp(frac(adjust, "adj1", 5e4), 0, 1) * w;
|
|
114
|
+
return [new PathBuilder().moveTo(0, h).lineTo(bx, h).lineTo(bx, 0).lineTo(w, 0).build()];
|
|
115
|
+
}
|
|
91
116
|
case "rightArrow": return [blockArrow(w, h, adjust, "right")];
|
|
92
117
|
case "leftArrow": return [blockArrow(w, h, adjust, "left")];
|
|
93
118
|
case "upArrow": return [blockArrow(w, h, adjust, "up")];
|
|
@@ -157,6 +182,214 @@ function customPaths(geom, wPt, hPt) {
|
|
|
157
182
|
}
|
|
158
183
|
return [b.build()];
|
|
159
184
|
}
|
|
185
|
+
var SQUARE = {
|
|
186
|
+
cut: 0,
|
|
187
|
+
round: false
|
|
188
|
+
};
|
|
189
|
+
var CORNER_RECTS = new Map([
|
|
190
|
+
["round1Rect", {
|
|
191
|
+
defaults: [16667, 0],
|
|
192
|
+
corners: [
|
|
193
|
+
void 0,
|
|
194
|
+
0,
|
|
195
|
+
void 0,
|
|
196
|
+
void 0
|
|
197
|
+
],
|
|
198
|
+
round: true
|
|
199
|
+
}],
|
|
200
|
+
["snip1Rect", {
|
|
201
|
+
defaults: [16667, 0],
|
|
202
|
+
corners: [
|
|
203
|
+
void 0,
|
|
204
|
+
0,
|
|
205
|
+
void 0,
|
|
206
|
+
void 0
|
|
207
|
+
],
|
|
208
|
+
round: false
|
|
209
|
+
}],
|
|
210
|
+
["round2SameRect", {
|
|
211
|
+
defaults: [16667, 0],
|
|
212
|
+
corners: [
|
|
213
|
+
0,
|
|
214
|
+
0,
|
|
215
|
+
1,
|
|
216
|
+
1
|
|
217
|
+
],
|
|
218
|
+
round: true
|
|
219
|
+
}],
|
|
220
|
+
["snip2SameRect", {
|
|
221
|
+
defaults: [16667, 0],
|
|
222
|
+
corners: [
|
|
223
|
+
0,
|
|
224
|
+
0,
|
|
225
|
+
1,
|
|
226
|
+
1
|
|
227
|
+
],
|
|
228
|
+
round: false
|
|
229
|
+
}],
|
|
230
|
+
["round2DiagRect", {
|
|
231
|
+
defaults: [16667, 0],
|
|
232
|
+
corners: [
|
|
233
|
+
0,
|
|
234
|
+
1,
|
|
235
|
+
0,
|
|
236
|
+
1
|
|
237
|
+
],
|
|
238
|
+
round: true
|
|
239
|
+
}],
|
|
240
|
+
["snip2DiagRect", {
|
|
241
|
+
defaults: [16667, 0],
|
|
242
|
+
corners: [
|
|
243
|
+
0,
|
|
244
|
+
1,
|
|
245
|
+
0,
|
|
246
|
+
1
|
|
247
|
+
],
|
|
248
|
+
round: false
|
|
249
|
+
}],
|
|
250
|
+
["snipRoundRect", {
|
|
251
|
+
defaults: [16667, 16667],
|
|
252
|
+
corners: [
|
|
253
|
+
0,
|
|
254
|
+
1,
|
|
255
|
+
void 0,
|
|
256
|
+
void 0
|
|
257
|
+
],
|
|
258
|
+
round: [false, true]
|
|
259
|
+
}]
|
|
260
|
+
]);
|
|
261
|
+
function cornerRect(preset, w, h, adjust) {
|
|
262
|
+
const spec = CORNER_RECTS.get(preset);
|
|
263
|
+
const ss = Math.min(w, h);
|
|
264
|
+
const guide = (i) => {
|
|
265
|
+
return clamp((adjust.get(i === 0 ? "adj1" : "adj2") ?? (i === 0 ? adjust.get("adj") : void 0) ?? spec.defaults[i]) / 1e5, 0, .5) * ss;
|
|
266
|
+
};
|
|
267
|
+
return roundedCorners(w, h, spec.corners.map((g) => {
|
|
268
|
+
if (g === void 0) return SQUARE;
|
|
269
|
+
const round = typeof spec.round === "boolean" ? spec.round : spec.round[g];
|
|
270
|
+
return {
|
|
271
|
+
cut: guide(g),
|
|
272
|
+
round
|
|
273
|
+
};
|
|
274
|
+
}));
|
|
275
|
+
}
|
|
276
|
+
function roundedCorners(w, h, [tl, tr, br, bl]) {
|
|
277
|
+
const at = [
|
|
278
|
+
{
|
|
279
|
+
c: tl,
|
|
280
|
+
from: [0, h - tl.cut],
|
|
281
|
+
to: [tl.cut, h],
|
|
282
|
+
centre: [tl.cut, h - tl.cut],
|
|
283
|
+
start: Math.PI
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
c: tr,
|
|
287
|
+
from: [w - tr.cut, h],
|
|
288
|
+
to: [w, h - tr.cut],
|
|
289
|
+
centre: [w - tr.cut, h - tr.cut],
|
|
290
|
+
start: Math.PI / 2
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
c: br,
|
|
294
|
+
from: [w, br.cut],
|
|
295
|
+
to: [w - br.cut, 0],
|
|
296
|
+
centre: [w - br.cut, br.cut],
|
|
297
|
+
start: 0
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
c: bl,
|
|
301
|
+
from: [bl.cut, 0],
|
|
302
|
+
to: [0, bl.cut],
|
|
303
|
+
centre: [bl.cut, bl.cut],
|
|
304
|
+
start: -Math.PI / 2
|
|
305
|
+
}
|
|
306
|
+
];
|
|
307
|
+
const b = new PathBuilder();
|
|
308
|
+
at.forEach((corner, i) => {
|
|
309
|
+
if (i === 0) b.moveTo(corner.from[0], corner.from[1]);
|
|
310
|
+
else b.lineTo(corner.from[0], corner.from[1]);
|
|
311
|
+
if (corner.c.cut <= 0) return;
|
|
312
|
+
if (corner.c.round) b.append(arcToBeziers(corner.centre[0], corner.centre[1], corner.c.cut, corner.c.cut, corner.start, -Math.PI / 2));
|
|
313
|
+
else b.lineTo(corner.to[0], corner.to[1]);
|
|
314
|
+
});
|
|
315
|
+
return b.close().build();
|
|
316
|
+
}
|
|
317
|
+
var STARS = new Map([
|
|
318
|
+
["star4", {
|
|
319
|
+
points: 4,
|
|
320
|
+
adj: 12500,
|
|
321
|
+
hf: 1e5,
|
|
322
|
+
vf: 1e5
|
|
323
|
+
}],
|
|
324
|
+
["star5", {
|
|
325
|
+
points: 5,
|
|
326
|
+
adj: 19098,
|
|
327
|
+
hf: 105146,
|
|
328
|
+
vf: 110557
|
|
329
|
+
}],
|
|
330
|
+
["star6", {
|
|
331
|
+
points: 6,
|
|
332
|
+
adj: 28868,
|
|
333
|
+
hf: 115470,
|
|
334
|
+
vf: 1e5
|
|
335
|
+
}],
|
|
336
|
+
["star7", {
|
|
337
|
+
points: 7,
|
|
338
|
+
adj: 34601,
|
|
339
|
+
hf: 102572,
|
|
340
|
+
vf: 105210
|
|
341
|
+
}],
|
|
342
|
+
["star8", {
|
|
343
|
+
points: 8,
|
|
344
|
+
adj: 37500,
|
|
345
|
+
hf: 1e5,
|
|
346
|
+
vf: 1e5
|
|
347
|
+
}],
|
|
348
|
+
["star10", {
|
|
349
|
+
points: 10,
|
|
350
|
+
adj: 42533,
|
|
351
|
+
hf: 105146,
|
|
352
|
+
vf: 1e5
|
|
353
|
+
}],
|
|
354
|
+
["star12", {
|
|
355
|
+
points: 12,
|
|
356
|
+
adj: 37500,
|
|
357
|
+
hf: 1e5,
|
|
358
|
+
vf: 1e5
|
|
359
|
+
}],
|
|
360
|
+
["star16", {
|
|
361
|
+
points: 16,
|
|
362
|
+
adj: 37500,
|
|
363
|
+
hf: 1e5,
|
|
364
|
+
vf: 1e5
|
|
365
|
+
}],
|
|
366
|
+
["star24", {
|
|
367
|
+
points: 24,
|
|
368
|
+
adj: 37500,
|
|
369
|
+
hf: 1e5,
|
|
370
|
+
vf: 1e5
|
|
371
|
+
}],
|
|
372
|
+
["star32", {
|
|
373
|
+
points: 32,
|
|
374
|
+
adj: 37500,
|
|
375
|
+
hf: 1e5,
|
|
376
|
+
vf: 1e5
|
|
377
|
+
}]
|
|
378
|
+
]);
|
|
379
|
+
function star(w, h, preset, adjust) {
|
|
380
|
+
const inner = clamp(frac(adjust, "adj", preset.adj) * 2, 0, 1);
|
|
381
|
+
const hf = preset.hf / 1e5;
|
|
382
|
+
const vf = preset.vf / 1e5;
|
|
383
|
+
const pts = [];
|
|
384
|
+
for (let i = 0; i < preset.points; i++) {
|
|
385
|
+
const out = -Math.PI / 2 + i * 2 * Math.PI / preset.points;
|
|
386
|
+
for (const [angle, r] of [[out, 1], [out + Math.PI / preset.points, inner]]) {
|
|
387
|
+
const x = w / 2 * (1 + hf * r * Math.cos(angle));
|
|
388
|
+
pts.push([x, h - h / 2 * vf * (1 + r * Math.sin(angle))]);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return polygon(pts);
|
|
392
|
+
}
|
|
160
393
|
function regularPolygon(w, h, n) {
|
|
161
394
|
const cx = w / 2;
|
|
162
395
|
const cy = h / 2;
|
|
@@ -172,10 +405,11 @@ function regularPolygon(w, h, n) {
|
|
|
172
405
|
function blockArrow(w, h, adjust, dir) {
|
|
173
406
|
const thick = clamp(frac(adjust, "adj1", 5e4), 0, 1);
|
|
174
407
|
const head = clamp(frac(adjust, "adj2", 5e4), 0, 1);
|
|
408
|
+
const ss = Math.min(w, h);
|
|
175
409
|
if (dir === "right" || dir === "left") {
|
|
176
|
-
const sb = h
|
|
177
|
-
const st = h
|
|
178
|
-
const hl = head *
|
|
410
|
+
const sb = (h - ss * thick) / 2;
|
|
411
|
+
const st = (h + ss * thick) / 2;
|
|
412
|
+
const hl = head * ss;
|
|
179
413
|
if (dir === "right") {
|
|
180
414
|
const bx = w - hl;
|
|
181
415
|
return polygon([
|
|
@@ -199,9 +433,9 @@ function blockArrow(w, h, adjust, dir) {
|
|
|
199
433
|
[w, st]
|
|
200
434
|
]);
|
|
201
435
|
}
|
|
202
|
-
const sl = w
|
|
203
|
-
const sr = w
|
|
204
|
-
const hh = head *
|
|
436
|
+
const sl = (w - ss * thick) / 2;
|
|
437
|
+
const sr = (w + ss * thick) / 2;
|
|
438
|
+
const hh = head * ss;
|
|
205
439
|
if (dir === "up") {
|
|
206
440
|
const by = h - hh;
|
|
207
441
|
return polygon([
|
|
@@ -37,6 +37,18 @@ export declare function gradientToSolid(gradient: ShapeGradient): string;
|
|
|
37
37
|
* @returns The `<linearGradient>` or `<radialGradient>` markup.
|
|
38
38
|
*/
|
|
39
39
|
export declare function gradientSvgDef(id: string, g: ShapeGradient): string;
|
|
40
|
+
/**
|
|
41
|
+
* §20.1.8.24 / §20.1.8.42 — the arrowheads a line asks for at its ends, as
|
|
42
|
+
* filled paths in the same local frame as the shape's own geometry. The head
|
|
43
|
+
* rides the first point of the first subpath and the tail the last point of
|
|
44
|
+
* the last one, each turned along the segment that reaches it.
|
|
45
|
+
*
|
|
46
|
+
* @param paths The shape's geometry paths.
|
|
47
|
+
* @param line The parsed line (its `headEnd`/`tailEnd` are read).
|
|
48
|
+
* @param strokeWidthPt The pen width the decorations are sized against.
|
|
49
|
+
* @returns The decoration paths (empty when the line asks for none).
|
|
50
|
+
*/
|
|
51
|
+
export declare function lineEndPaths(paths: ReadonlyArray<VectorPath>, line: ShapeLine | undefined, strokeWidthPt: number): Array<VectorPath>;
|
|
40
52
|
/**
|
|
41
53
|
* Build a {@link StrokeStyle} from a shape's `a:ln` line, resolving the default
|
|
42
54
|
* width (0.75pt), dash pattern and line cap. Returns `undefined` for no line or
|
|
@@ -60,12 +60,125 @@ function gradientToSolid(gradient) {
|
|
|
60
60
|
function gradientSvgDef(id, g) {
|
|
61
61
|
const n = (x) => String(Math.round(x * 1e4) / 1e4);
|
|
62
62
|
const stops = g.stops.map((s) => `<stop offset="${n(s.offset)}" stop-color="#${s.colorHex}"/>`).join("");
|
|
63
|
-
if (g.kind === "radial")
|
|
63
|
+
if (g.kind === "radial") {
|
|
64
|
+
const c = g.center;
|
|
65
|
+
if (!c) return `<radialGradient id="${id}">${stops}</radialGradient>`;
|
|
66
|
+
const r = Math.SQRT2 / 2;
|
|
67
|
+
return `<radialGradient id="${id}" cx="${n(c.x)}" cy="${n(c.y)}" r="${n(r)}">${stops}</radialGradient>`;
|
|
68
|
+
}
|
|
64
69
|
const rad = -(g.angle ?? 0) * Math.PI / 180;
|
|
65
70
|
const dx = Math.cos(rad) / 2;
|
|
66
71
|
const dy = Math.sin(rad) / 2;
|
|
67
72
|
return `<linearGradient id="${id}" x1="${n(.5 - dx)}" y1="${n(.5 - dy)}" x2="${n(.5 + dx)}" y2="${n(.5 + dy)}">${stops}</linearGradient>`;
|
|
68
73
|
}
|
|
74
|
+
var LINE_END_STEPS = {
|
|
75
|
+
sm: 3,
|
|
76
|
+
med: 4.5,
|
|
77
|
+
lg: 6
|
|
78
|
+
};
|
|
79
|
+
var MIN_LINE_END_PEN_PT = 1;
|
|
80
|
+
/**
|
|
81
|
+
* §20.1.8.24 / §20.1.8.42 — the arrowheads a line asks for at its ends, as
|
|
82
|
+
* filled paths in the same local frame as the shape's own geometry. The head
|
|
83
|
+
* rides the first point of the first subpath and the tail the last point of
|
|
84
|
+
* the last one, each turned along the segment that reaches it.
|
|
85
|
+
*
|
|
86
|
+
* @param paths The shape's geometry paths.
|
|
87
|
+
* @param line The parsed line (its `headEnd`/`tailEnd` are read).
|
|
88
|
+
* @param strokeWidthPt The pen width the decorations are sized against.
|
|
89
|
+
* @returns The decoration paths (empty when the line asks for none).
|
|
90
|
+
*/
|
|
91
|
+
function lineEndPaths(paths, line, strokeWidthPt) {
|
|
92
|
+
if (!line || !line.headEnd && !line.tailEnd || line.fill === "none") return [];
|
|
93
|
+
const pts = pathPoints(paths);
|
|
94
|
+
if (pts.length < 2) return [];
|
|
95
|
+
const out = [];
|
|
96
|
+
const pen = Math.max(strokeWidthPt, MIN_LINE_END_PEN_PT);
|
|
97
|
+
if (line.headEnd) {
|
|
98
|
+
const p = pts[0];
|
|
99
|
+
const q = pts[1];
|
|
100
|
+
const path = endPath(line.headEnd, p, q, pen);
|
|
101
|
+
if (path) out.push(path);
|
|
102
|
+
}
|
|
103
|
+
if (line.tailEnd) {
|
|
104
|
+
const p = pts[pts.length - 1];
|
|
105
|
+
const q = pts[pts.length - 2];
|
|
106
|
+
const path = endPath(line.tailEnd, p, q, pen);
|
|
107
|
+
if (path) out.push(path);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function pathPoints(paths) {
|
|
112
|
+
const out = [];
|
|
113
|
+
for (const path of paths) for (const seg of path.segments) {
|
|
114
|
+
if (seg.op === "close") continue;
|
|
115
|
+
out.push({
|
|
116
|
+
x: seg.x,
|
|
117
|
+
y: seg.y
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
function endPath(end, tip, from, pen) {
|
|
123
|
+
const dx = tip.x - from.x;
|
|
124
|
+
const dy = tip.y - from.y;
|
|
125
|
+
const len = Math.hypot(dx, dy);
|
|
126
|
+
if (len < 1e-6) return void 0;
|
|
127
|
+
const ux = dx / len;
|
|
128
|
+
const uy = dy / len;
|
|
129
|
+
const nx = -uy;
|
|
130
|
+
const ny = ux;
|
|
131
|
+
const L = LINE_END_STEPS[end.length ?? "med"] * pen;
|
|
132
|
+
const W = LINE_END_STEPS[end.width ?? "med"] * pen;
|
|
133
|
+
const at = (along, across) => ({
|
|
134
|
+
x: tip.x - ux * along + nx * across,
|
|
135
|
+
y: tip.y - uy * along + ny * across
|
|
136
|
+
});
|
|
137
|
+
const segments = [];
|
|
138
|
+
const move = (p) => {
|
|
139
|
+
segments.push({
|
|
140
|
+
op: "move",
|
|
141
|
+
x: p.x,
|
|
142
|
+
y: p.y
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
const line2 = (p) => {
|
|
146
|
+
segments.push({
|
|
147
|
+
op: "line",
|
|
148
|
+
x: p.x,
|
|
149
|
+
y: p.y
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
if (end.type === "diamond") {
|
|
153
|
+
move(at(0, 0));
|
|
154
|
+
line2(at(L / 2, W / 2));
|
|
155
|
+
line2(at(L, 0));
|
|
156
|
+
line2(at(L / 2, -W / 2));
|
|
157
|
+
} else if (end.type === "oval") {
|
|
158
|
+
const r = W / 2;
|
|
159
|
+
const c = at(L / 2, 0);
|
|
160
|
+
for (let i = 0; i < 8; i++) {
|
|
161
|
+
const a = i / 8 * 2 * Math.PI;
|
|
162
|
+
const p = {
|
|
163
|
+
x: c.x + r * Math.cos(a),
|
|
164
|
+
y: c.y + r * Math.sin(a)
|
|
165
|
+
};
|
|
166
|
+
if (i === 0) move(p);
|
|
167
|
+
else line2(p);
|
|
168
|
+
}
|
|
169
|
+
} else if (end.type === "stealth") {
|
|
170
|
+
move(at(0, 0));
|
|
171
|
+
line2(at(L, W / 2));
|
|
172
|
+
line2(at(L * .6, 0));
|
|
173
|
+
line2(at(L, -W / 2));
|
|
174
|
+
} else {
|
|
175
|
+
move(at(0, 0));
|
|
176
|
+
line2(at(L, W / 2));
|
|
177
|
+
line2(at(L, -W / 2));
|
|
178
|
+
}
|
|
179
|
+
segments.push({ op: "close" });
|
|
180
|
+
return { segments };
|
|
181
|
+
}
|
|
69
182
|
/**
|
|
70
183
|
* Build a {@link StrokeStyle} from a shape's `a:ln` line, resolving the default
|
|
71
184
|
* width (0.75pt), dash pattern and line cap. Returns `undefined` for no line or
|
|
@@ -77,7 +190,7 @@ function gradientSvgDef(id, g) {
|
|
|
77
190
|
function buildStroke(line) {
|
|
78
191
|
if (!line || line.fill === "none") return void 0;
|
|
79
192
|
const widthPt = line.width ?? DEFAULT_LINE_WIDTH_EMU / 12700;
|
|
80
|
-
const dash = line.dash && line.dash !== "solid" ? dashPattern(line.dash, widthPt) : void 0;
|
|
193
|
+
const dash = line.customDash?.map((n) => Math.max(.01, n * widthPt)) ?? (line.dash && line.dash !== "solid" ? dashPattern(line.dash, widthPt) : void 0);
|
|
81
194
|
const cap = line.cap === "flat" ? "butt" : line.cap;
|
|
82
195
|
return {
|
|
83
196
|
colorHex: line.colorHex ?? "000000",
|
|
@@ -148,4 +261,4 @@ function buildShapeTransform(pageX, pageY, widthPt, heightPt, rotation60k, flipH
|
|
|
148
261
|
];
|
|
149
262
|
}
|
|
150
263
|
//#endregion
|
|
151
|
-
export { DEFAULT_INSET_LR_PT, DEFAULT_INSET_TB_PT, buildShapePaths, buildShapeTransform, buildStroke, gradientSvgDef, gradientToSolid };
|
|
264
|
+
export { DEFAULT_INSET_LR_PT, DEFAULT_INSET_TB_PT, buildShapePaths, buildShapeTransform, buildStroke, gradientSvgDef, gradientToSolid, lineEndPaths };
|
|
@@ -59,14 +59,16 @@ function columnSpark(values, w, h, color) {
|
|
|
59
59
|
const slot = w / n;
|
|
60
60
|
const bw = slot * .72;
|
|
61
61
|
const off = (slot - bw) / 2;
|
|
62
|
-
const pad = h * .06;
|
|
63
62
|
const paths = [];
|
|
63
|
+
const at = (v) => (v - min) / span * h;
|
|
64
|
+
const zero = Math.min(h, Math.max(0, at(0)));
|
|
64
65
|
for (let i = 0; i < n; i++) {
|
|
65
66
|
const v = values[i];
|
|
66
67
|
if (v === null || v === void 0) continue;
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
68
|
+
const y = at(v);
|
|
69
|
+
const bottom = Math.min(zero, y);
|
|
70
|
+
const bh = Math.max(.4, Math.abs(y - zero));
|
|
71
|
+
paths.push(rectPath(i * slot + off, bottom, bw, bh));
|
|
70
72
|
}
|
|
71
73
|
return paths.length > 0 ? [{
|
|
72
74
|
paths,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PoNode } from '../po-helpers.js';
|
|
1
2
|
/**
|
|
2
3
|
* Parse a DrawingML theme part (ECMA-376 §20.1.6.2, `a:clrScheme`) into a
|
|
3
4
|
* `name → hex` colour map. Reads the twelve scheme slots — `dk1`/`lt1`/`dk2`/
|
|
@@ -10,3 +11,53 @@
|
|
|
10
11
|
* empty when no `a:clrScheme` is present.
|
|
11
12
|
*/
|
|
12
13
|
export declare function parseTheme(themeXml: Uint8Array): Map<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Parse a theme's line-style widths (ECMA-376 §20.1.4.1.21 `a:lnStyleLst`).
|
|
16
|
+
*
|
|
17
|
+
* A shape drawn from the gallery keeps its outline as `<a:lnRef idx="N">`,
|
|
18
|
+
* which is a 1-based index into this list — the reference names the colour and
|
|
19
|
+
* the list holds the width. The standard Office theme is 0.75pt / 2pt / 3pt.
|
|
20
|
+
*
|
|
21
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
22
|
+
* @returns The widths in points, in list order; empty when the theme declares
|
|
23
|
+
* no `a:fmtScheme`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseThemeLineWidths(themeXml: Uint8Array): Array<number>;
|
|
26
|
+
/**
|
|
27
|
+
* Parse a theme's fill styles (§20.1.4.1.13 `a:fillStyleLst`), as the raw nodes.
|
|
28
|
+
*
|
|
29
|
+
* A shape drawn from the gallery carries no fill of its own — only
|
|
30
|
+
* `<a:fillRef idx="N">`, a 1-based index into this list, and a colour to put
|
|
31
|
+
* where the styles say `phClr`. The standard Office theme's slots are a solid,
|
|
32
|
+
* a subtle gradient and a stronger one, so reading the reference's colour alone
|
|
33
|
+
* paints slot 3 flat: 47504.xlsx's rectangle is a gradient in both references
|
|
34
|
+
* and a single blue in ours.
|
|
35
|
+
*
|
|
36
|
+
* The nodes are handed back unparsed because what they hold is a whole fill —
|
|
37
|
+
* solid, gradient, pattern — which the shape readers already know how to read.
|
|
38
|
+
*
|
|
39
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
40
|
+
* @returns The `a:fillStyleLst` children in list order; empty when the theme
|
|
41
|
+
* declares no `a:fmtScheme`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function parseThemeFillStyles(themeXml: Uint8Array): Array<PoNode>;
|
|
44
|
+
/**
|
|
45
|
+
* Parse a theme's BACKGROUND fill styles (§20.1.4.1.7 `a:bgFillStyleLst`), as
|
|
46
|
+
* the raw nodes. An `<a:fillRef>` reaches them with an index past 1000 — slot
|
|
47
|
+
* 1001 is the first — and that is where the page-sized backdrops Word's cover
|
|
48
|
+
* pages are built from live (fdo78957.docx).
|
|
49
|
+
*
|
|
50
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
51
|
+
* @returns The fill children in list order; empty when the theme declares none.
|
|
52
|
+
*/
|
|
53
|
+
export declare function parseThemeBgFillStyles(themeXml: Uint8Array): Array<PoNode>;
|
|
54
|
+
/**
|
|
55
|
+
* Parse a theme's effect styles (§20.1.4.1.15 `a:effectStyleLst`), as the raw
|
|
56
|
+
* nodes. `<a:effectRef idx="N">` is a 1-based index into this list, exactly as
|
|
57
|
+
* the fill and line references index theirs.
|
|
58
|
+
*
|
|
59
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
60
|
+
* @returns The `a:effectStyle` children in list order; empty when the theme
|
|
61
|
+
* declares no `a:fmtScheme`.
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseThemeEffectStyles(themeXml: Uint8Array): Array<PoNode>;
|
|
@@ -3,6 +3,7 @@ import { XMLParser } from "fast-xml-parser";
|
|
|
3
3
|
//#region src/core/drawingml/theme-parser.ts
|
|
4
4
|
var decoder = new TextDecoder("utf-8");
|
|
5
5
|
var parser = new XMLParser({
|
|
6
|
+
htmlEntities: true,
|
|
6
7
|
ignoreAttributes: false,
|
|
7
8
|
attributeNamePrefix: "@_",
|
|
8
9
|
preserveOrder: true,
|
|
@@ -53,6 +54,96 @@ function parseTheme(themeXml) {
|
|
|
53
54
|
}
|
|
54
55
|
return out;
|
|
55
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse a theme's line-style widths (ECMA-376 §20.1.4.1.21 `a:lnStyleLst`).
|
|
59
|
+
*
|
|
60
|
+
* A shape drawn from the gallery keeps its outline as `<a:lnRef idx="N">`,
|
|
61
|
+
* which is a 1-based index into this list — the reference names the colour and
|
|
62
|
+
* the list holds the width. The standard Office theme is 0.75pt / 2pt / 3pt.
|
|
63
|
+
*
|
|
64
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
65
|
+
* @returns The widths in points, in list order; empty when the theme declares
|
|
66
|
+
* no `a:fmtScheme`.
|
|
67
|
+
*/
|
|
68
|
+
function parseThemeLineWidths(themeXml) {
|
|
69
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
70
|
+
"a:theme",
|
|
71
|
+
"a:themeElements",
|
|
72
|
+
"a:fmtScheme",
|
|
73
|
+
"a:lnStyleLst"
|
|
74
|
+
]);
|
|
75
|
+
if (!list) return [];
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const ln of poChildren(list)) {
|
|
78
|
+
if (!poIs(ln, "a:ln")) continue;
|
|
79
|
+
const w = Number(poAttr(ln, "w") ?? "");
|
|
80
|
+
out.push(Number.isFinite(w) && w > 0 ? w / EMU_PER_POINT : .75);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse a theme's fill styles (§20.1.4.1.13 `a:fillStyleLst`), as the raw nodes.
|
|
86
|
+
*
|
|
87
|
+
* A shape drawn from the gallery carries no fill of its own — only
|
|
88
|
+
* `<a:fillRef idx="N">`, a 1-based index into this list, and a colour to put
|
|
89
|
+
* where the styles say `phClr`. The standard Office theme's slots are a solid,
|
|
90
|
+
* a subtle gradient and a stronger one, so reading the reference's colour alone
|
|
91
|
+
* paints slot 3 flat: 47504.xlsx's rectangle is a gradient in both references
|
|
92
|
+
* and a single blue in ours.
|
|
93
|
+
*
|
|
94
|
+
* The nodes are handed back unparsed because what they hold is a whole fill —
|
|
95
|
+
* solid, gradient, pattern — which the shape readers already know how to read.
|
|
96
|
+
*
|
|
97
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
98
|
+
* @returns The `a:fillStyleLst` children in list order; empty when the theme
|
|
99
|
+
* declares no `a:fmtScheme`.
|
|
100
|
+
*/
|
|
101
|
+
function parseThemeFillStyles(themeXml) {
|
|
102
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
103
|
+
"a:theme",
|
|
104
|
+
"a:themeElements",
|
|
105
|
+
"a:fmtScheme",
|
|
106
|
+
"a:fillStyleLst"
|
|
107
|
+
]);
|
|
108
|
+
return list ? [...poChildren(list)] : [];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse a theme's BACKGROUND fill styles (§20.1.4.1.7 `a:bgFillStyleLst`), as
|
|
112
|
+
* the raw nodes. An `<a:fillRef>` reaches them with an index past 1000 — slot
|
|
113
|
+
* 1001 is the first — and that is where the page-sized backdrops Word's cover
|
|
114
|
+
* pages are built from live (fdo78957.docx).
|
|
115
|
+
*
|
|
116
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
117
|
+
* @returns The fill children in list order; empty when the theme declares none.
|
|
118
|
+
*/
|
|
119
|
+
function parseThemeBgFillStyles(themeXml) {
|
|
120
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
121
|
+
"a:theme",
|
|
122
|
+
"a:themeElements",
|
|
123
|
+
"a:fmtScheme",
|
|
124
|
+
"a:bgFillStyleLst"
|
|
125
|
+
]);
|
|
126
|
+
return list ? [...poChildren(list)] : [];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Parse a theme's effect styles (§20.1.4.1.15 `a:effectStyleLst`), as the raw
|
|
130
|
+
* nodes. `<a:effectRef idx="N">` is a 1-based index into this list, exactly as
|
|
131
|
+
* the fill and line references index theirs.
|
|
132
|
+
*
|
|
133
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
134
|
+
* @returns The `a:effectStyle` children in list order; empty when the theme
|
|
135
|
+
* declares no `a:fmtScheme`.
|
|
136
|
+
*/
|
|
137
|
+
function parseThemeEffectStyles(themeXml) {
|
|
138
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
139
|
+
"a:theme",
|
|
140
|
+
"a:themeElements",
|
|
141
|
+
"a:fmtScheme",
|
|
142
|
+
"a:effectStyleLst"
|
|
143
|
+
]);
|
|
144
|
+
return list ? [...poChildren(list)] : [];
|
|
145
|
+
}
|
|
146
|
+
var EMU_PER_POINT = 12700;
|
|
56
147
|
function colorOf(slot) {
|
|
57
148
|
for (const c of poChildren(slot)) if (poIs(c, "a:srgbClr")) {
|
|
58
149
|
const v = poAttr(c, "val");
|
|
@@ -63,4 +154,4 @@ function colorOf(slot) {
|
|
|
63
154
|
}
|
|
64
155
|
}
|
|
65
156
|
//#endregion
|
|
66
|
-
export { parseTheme };
|
|
157
|
+
export { parseTheme, parseThemeBgFillStyles, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths };
|
|
@@ -12,6 +12,11 @@ export interface FontMeasure {
|
|
|
12
12
|
readonly textWidthPt: (text: string, fontSize: number) => number;
|
|
13
13
|
/** Encode `text` as a hex string of 4-digit glyph ids (Identity-H addressing). */
|
|
14
14
|
readonly encodeTextAsCidHex: (text: string) => string;
|
|
15
|
+
/**
|
|
16
|
+
* The complete PDF text-showing operator for `text` — `<hex> Tj`, or a
|
|
17
|
+
* `[…] TJ` array when shaping moved a glyph off its own advance.
|
|
18
|
+
*/
|
|
19
|
+
readonly showText: (text: string) => string;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* Build a {@link FontMeasure} over a parsed font.
|
|
@@ -33,10 +33,30 @@ function createFontMeasure(parsed, kern = true) {
|
|
|
33
33
|
for (const gid of shaped.gids) out += gid.toString(16).padStart(4, "0").toUpperCase();
|
|
34
34
|
return out;
|
|
35
35
|
};
|
|
36
|
+
const showText = (text) => {
|
|
37
|
+
const shaped = shapeText(text, parsed.glyphForCodepoint, parsed.advanceWidths, parsed.ligatures, kerning, parsed.joiningForms);
|
|
38
|
+
const parts = [];
|
|
39
|
+
let hex = "";
|
|
40
|
+
let kerned = false;
|
|
41
|
+
for (let i = 0; i < shaped.gids.length; i++) {
|
|
42
|
+
const gid = shaped.gids[i];
|
|
43
|
+
hex += gid.toString(16).padStart(4, "0").toUpperCase();
|
|
44
|
+
const delta = (shaped.advances[i] ?? 0) - (parsed.advanceWidths[gid] ?? 0);
|
|
45
|
+
if (delta === 0) continue;
|
|
46
|
+
const adj = -delta * 1e3 / parsed.unitsPerEm;
|
|
47
|
+
parts.push(`<${hex}>`, String(Number(adj.toFixed(2))));
|
|
48
|
+
hex = "";
|
|
49
|
+
kerned = true;
|
|
50
|
+
}
|
|
51
|
+
if (!kerned) return `<${hex}> Tj`;
|
|
52
|
+
if (hex !== "") parts.push(`<${hex}>`);
|
|
53
|
+
return `[${parts.join(" ")}] TJ`;
|
|
54
|
+
};
|
|
36
55
|
return {
|
|
37
56
|
pdfWidthForGid,
|
|
38
57
|
textWidthPt,
|
|
39
|
-
encodeTextAsCidHex
|
|
58
|
+
encodeTextAsCidHex,
|
|
59
|
+
showText
|
|
40
60
|
};
|
|
41
61
|
}
|
|
42
62
|
//#endregion
|