reamkit 1.22.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/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +55 -0
- package/dist/esm/core/drawingml/chart-geometry.js +14 -7
- package/dist/esm/core/drawingml/colors.d.ts +4 -2
- package/dist/esm/core/drawingml/colors.js +15 -0
- 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.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +73 -4
- package/dist/esm/core/font/measure.d.ts +12 -0
- package/dist/esm/core/font/measure.js +36 -0
- package/dist/esm/core/fonts/families.d.ts +10 -0
- package/dist/esm/core/fonts/families.js +44 -0
- package/dist/esm/core/fonts/index.d.ts +3 -2
- package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
- package/dist/esm/core/fonts/remote-fonts.js +114 -8
- package/dist/esm/core/fonts/scripts.d.ts +26 -0
- package/dist/esm/core/fonts/scripts.js +177 -0
- package/dist/esm/core/images.d.ts +30 -2
- package/dist/esm/core/images.js +121 -5
- package/dist/esm/core/metafile/blit.d.ts +33 -0
- package/dist/esm/core/metafile/blit.js +67 -0
- package/dist/esm/core/metafile/dib.d.ts +61 -0
- package/dist/esm/core/metafile/dib.js +205 -0
- package/dist/esm/core/metafile/emf.js +280 -38
- package/dist/esm/core/metafile/picture.d.ts +61 -1
- package/dist/esm/core/metafile/picture.js +70 -1
- package/dist/esm/core/metafile/wmf.js +202 -13
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +98 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/excel/print-model.js +5 -3
- package/dist/esm/excel/sheet-drawing.js +1 -1
- package/dist/esm/excel/sheet-to-flow.js +16 -2
- package/dist/esm/excel/styles-parser.js +1 -1
- package/dist/esm/excel/xls/biff-reader.js +53 -18
- package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
- package/dist/esm/excel/xls/biff-styles.js +9 -7
- package/dist/esm/excel/xls/escher.js +90 -24
- package/dist/esm/html/html-writer.js +2 -1
- package/dist/esm/layout/page-doc.d.ts +74 -0
- package/dist/esm/layout/page-doc.js +14 -1
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +475 -48
- package/dist/esm/pdf/shading.js +8 -6
- package/dist/esm/pdf/styled-page-emitter.js +77 -5
- package/dist/esm/pdf/vector-graphics.js +1 -1
- package/dist/esm/pdf-reader/image-decode.js +1 -1
- package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
- package/dist/esm/pptx/embedded-fonts.js +104 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
- package/dist/esm/pptx/placeholder-cascade.js +114 -18
- package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
- package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
- package/dist/esm/pptx/ppt/ppt-text.js +873 -144
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +117 -15
- package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
- package/dist/esm/pptx/preset-table-styles.js +27 -0
- package/dist/esm/pptx/slide-parser.d.ts +11 -2
- package/dist/esm/pptx/slide-parser.js +203 -44
- package/dist/esm/pptx/sp-helpers.d.ts +9 -4
- package/dist/esm/pptx/sp-helpers.js +48 -9
- package/dist/esm/pptx/table-style.d.ts +16 -1
- package/dist/esm/pptx/table-style.js +104 -10
- package/dist/esm/svg/svg-writer.js +1 -0
- package/dist/esm/word/document-parser.d.ts +11 -2
- package/dist/esm/word/document-parser.js +10 -7
- package/dist/esm/word/docx-reader.js +32 -16
- package/dist/esm/word/docx-to-pdf.d.ts +8 -7
- package/dist/esm/word/docx-to-pdf.js +25 -7
- package/dist/esm/word/docx-writer.js +4 -0
- package/dist/esm/word/drawing-parser.d.ts +20 -0
- package/dist/esm/word/drawing-parser.js +67 -22
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +6 -6
- package/dist/esm/word/paragraph-properties.d.ts +2 -1
- package/dist/esm/word/paragraph-properties.js +2 -2
- package/dist/esm/word/run-properties.d.ts +5 -2
- package/dist/esm/word/run-properties.js +13 -8
- package/dist/esm/word/styles-parser.d.ts +2 -1
- package/dist/esm/word/styles-parser.js +12 -12
- package/dist/esm/word/table-parser.js +6 -3
- package/dist/esm/word/theme-fonts.d.ts +10 -0
- package/dist/esm/word/theme-fonts.js +28 -0
- package/package.json +1 -1
- /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { PathBuilder } from "../vector.js";
|
|
2
|
-
import { cloneDc, colorRef, newDeviceContext } from "./picture.js";
|
|
2
|
+
import { clippedAway, cloneDc, colorRef, intersectClip, newDeviceContext, primBounds } from "./picture.js";
|
|
3
|
+
import { cropDib, readDib } from "./dib.js";
|
|
4
|
+
import { makeBlitter } from "./blit.js";
|
|
3
5
|
import { fromSymbolFont, symbolGeometryOf, symbolOutline } from "./symbol-fonts.js";
|
|
4
6
|
import { ellipseSegments } from "./emf.js";
|
|
5
7
|
//#region src/core/metafile/wmf.ts
|
|
@@ -14,9 +16,6 @@ function isWmf(bytes) {
|
|
|
14
16
|
return (type === 1 || type === 2) && headerWords === 9;
|
|
15
17
|
}
|
|
16
18
|
var RECORD_NAMES = new Map([
|
|
17
|
-
[2368, "bitmap"],
|
|
18
|
-
[2881, "bitmap"],
|
|
19
|
-
[3907, "bitmap"],
|
|
20
19
|
[2338, "pie"],
|
|
21
20
|
[2096, "chord"],
|
|
22
21
|
[2071, "arc"],
|
|
@@ -61,6 +60,17 @@ function readWmf(bytes) {
|
|
|
61
60
|
cx: 0,
|
|
62
61
|
cy: 0
|
|
63
62
|
};
|
|
63
|
+
let origin;
|
|
64
|
+
const emit = (prim) => {
|
|
65
|
+
if (clippedAway(dc, primBounds(prim))) return;
|
|
66
|
+
origin ??= {
|
|
67
|
+
x: win.x,
|
|
68
|
+
y: win.y
|
|
69
|
+
};
|
|
70
|
+
const dx = origin.x - win.x;
|
|
71
|
+
const dy = origin.y - win.y;
|
|
72
|
+
prims.push(dx === 0 && dy === 0 ? prim : shiftPrim(prim, dx, dy));
|
|
73
|
+
};
|
|
64
74
|
const strokeOf = () => {
|
|
65
75
|
if (dc.pen.style === "none") return void 0;
|
|
66
76
|
const w = Math.max(1, dc.pen.widthLu);
|
|
@@ -79,7 +89,7 @@ function readWmf(bytes) {
|
|
|
79
89
|
const st = stroke ? strokeOf() : void 0;
|
|
80
90
|
const fillHex = fill && !dc.brush.hollow ? dc.brush.colorHex : void 0;
|
|
81
91
|
if (fillHex === void 0 && !st) return;
|
|
82
|
-
|
|
92
|
+
emit({
|
|
83
93
|
kind: "path",
|
|
84
94
|
paths: [path],
|
|
85
95
|
...fillHex !== void 0 ? { fillColorHex: fillHex } : {},
|
|
@@ -87,6 +97,27 @@ function readWmf(bytes) {
|
|
|
87
97
|
});
|
|
88
98
|
};
|
|
89
99
|
const rectSegments = (l, t, r, b) => new PathBuilder().moveTo(l, t).lineTo(r, t).lineTo(r, b).lineTo(l, b).close().build().segments;
|
|
100
|
+
const blitter = makeBlitter(emit);
|
|
101
|
+
/**
|
|
102
|
+
* §2.3.1 — one blit record: the packed bitmap the record ends with, into the
|
|
103
|
+
* destination rectangle its fields name. A WMF's coordinates are its own
|
|
104
|
+
* logical units, which is the frame the primitives are already in.
|
|
105
|
+
*/
|
|
106
|
+
const blit = (o) => {
|
|
107
|
+
const dib = readDib(bytes, off + o.dibAt);
|
|
108
|
+
if (!dib) {
|
|
109
|
+
skipped.add("bitmap");
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const s = o.src;
|
|
113
|
+
const part = s.x !== 0 || s.y !== 0 || s.w !== dib.width || s.h !== dib.height ? cropDib(dib, s.x, dib.bottomUp === true ? dib.height - s.y - s.h : s.y, s.w, s.h) : dib;
|
|
114
|
+
blitter.blit(part, {
|
|
115
|
+
x: Math.min(o.dest.x, o.dest.x + o.dest.w),
|
|
116
|
+
y: Math.min(o.dest.y, o.dest.y + o.dest.h),
|
|
117
|
+
width: Math.abs(o.dest.w),
|
|
118
|
+
height: Math.abs(o.dest.h)
|
|
119
|
+
}, o.rop);
|
|
120
|
+
};
|
|
90
121
|
let off = placeable ? 22 : 0;
|
|
91
122
|
off += 18;
|
|
92
123
|
let guard = 0;
|
|
@@ -115,6 +146,17 @@ function readWmf(bytes) {
|
|
|
115
146
|
cy: p(0)
|
|
116
147
|
};
|
|
117
148
|
break;
|
|
149
|
+
case 1046:
|
|
150
|
+
dc = {
|
|
151
|
+
...dc,
|
|
152
|
+
clip: intersectClip(dc, {
|
|
153
|
+
bottom: p(0),
|
|
154
|
+
right: p(1),
|
|
155
|
+
top: p(2),
|
|
156
|
+
left: p(3)
|
|
157
|
+
})
|
|
158
|
+
};
|
|
159
|
+
break;
|
|
118
160
|
case 30:
|
|
119
161
|
stack.push(cloneDc(dc));
|
|
120
162
|
break;
|
|
@@ -135,6 +177,12 @@ function readWmf(bytes) {
|
|
|
135
177
|
case 496:
|
|
136
178
|
objects[pu(0)] = void 0;
|
|
137
179
|
break;
|
|
180
|
+
case 247:
|
|
181
|
+
case 322:
|
|
182
|
+
case 505:
|
|
183
|
+
case 1791:
|
|
184
|
+
put({ kind: "other" });
|
|
185
|
+
break;
|
|
138
186
|
case 762:
|
|
139
187
|
put({
|
|
140
188
|
kind: "pen",
|
|
@@ -223,6 +271,79 @@ function readWmf(bytes) {
|
|
|
223
271
|
dc.brush = brush;
|
|
224
272
|
}
|
|
225
273
|
break;
|
|
274
|
+
case 2368:
|
|
275
|
+
case 2881:
|
|
276
|
+
case 3907:
|
|
277
|
+
{
|
|
278
|
+
const rop = p32(0);
|
|
279
|
+
const f = fn === 2368 ? {
|
|
280
|
+
dib: 22,
|
|
281
|
+
srcH: 4,
|
|
282
|
+
srcW: 5,
|
|
283
|
+
ySrc: 2,
|
|
284
|
+
xSrc: 3,
|
|
285
|
+
h: 4,
|
|
286
|
+
w: 5,
|
|
287
|
+
y: 6,
|
|
288
|
+
x: 7
|
|
289
|
+
} : fn === 2881 ? {
|
|
290
|
+
dib: 26,
|
|
291
|
+
srcH: 2,
|
|
292
|
+
srcW: 3,
|
|
293
|
+
ySrc: 4,
|
|
294
|
+
xSrc: 5,
|
|
295
|
+
h: 6,
|
|
296
|
+
w: 7,
|
|
297
|
+
y: 8,
|
|
298
|
+
x: 9
|
|
299
|
+
} : {
|
|
300
|
+
dib: 28,
|
|
301
|
+
srcH: 3,
|
|
302
|
+
srcW: 4,
|
|
303
|
+
ySrc: 5,
|
|
304
|
+
xSrc: 6,
|
|
305
|
+
h: 7,
|
|
306
|
+
w: 8,
|
|
307
|
+
y: 9,
|
|
308
|
+
x: 10
|
|
309
|
+
};
|
|
310
|
+
if (f.dib + 12 > size * 2) {
|
|
311
|
+
const hex = rop === 66 ? "000000" : rop === 16711778 ? "FFFFFF" : void 0;
|
|
312
|
+
const brush = dc.brush;
|
|
313
|
+
if (hex !== void 0) dc.brush = {
|
|
314
|
+
kind: "brush",
|
|
315
|
+
colorHex: hex,
|
|
316
|
+
hollow: false
|
|
317
|
+
};
|
|
318
|
+
const shift = fn === 2368 ? 1 : 0;
|
|
319
|
+
const [h, w, y, x] = [
|
|
320
|
+
p(f.h + shift),
|
|
321
|
+
p(f.w + shift),
|
|
322
|
+
p(f.y + shift),
|
|
323
|
+
p(f.x + shift)
|
|
324
|
+
];
|
|
325
|
+
paint(rectSegments(x, y, x + w, y + h), true, false);
|
|
326
|
+
dc.brush = brush;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
blit({
|
|
330
|
+
dibAt: f.dib,
|
|
331
|
+
dest: {
|
|
332
|
+
x: p(f.x),
|
|
333
|
+
y: p(f.y),
|
|
334
|
+
w: p(f.w),
|
|
335
|
+
h: p(f.h)
|
|
336
|
+
},
|
|
337
|
+
src: {
|
|
338
|
+
x: p(f.xSrc),
|
|
339
|
+
y: p(f.ySrc),
|
|
340
|
+
w: p(f.srcW),
|
|
341
|
+
h: p(f.srcH)
|
|
342
|
+
},
|
|
343
|
+
rop
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
break;
|
|
226
347
|
case 804:
|
|
227
348
|
case 805:
|
|
228
349
|
{
|
|
@@ -251,7 +372,7 @@ function readWmf(bytes) {
|
|
|
251
372
|
const count = pu(0);
|
|
252
373
|
const text = readString(bytes, off + 8, count, false);
|
|
253
374
|
const words = count + 1 >> 1;
|
|
254
|
-
pushText(
|
|
375
|
+
pushText(emit, dc, text, p(1 + words + 1), p(1 + words));
|
|
255
376
|
}
|
|
256
377
|
break;
|
|
257
378
|
case 2610:
|
|
@@ -261,7 +382,7 @@ function readWmf(bytes) {
|
|
|
261
382
|
const count = pu(2);
|
|
262
383
|
const hasRect = (pu(3) & 6) !== 0;
|
|
263
384
|
const text = readString(bytes, off + 6 + (4 + (hasRect ? 4 : 0)) * 2, count, false);
|
|
264
|
-
pushText(
|
|
385
|
+
pushText(emit, dc, text, x, y);
|
|
265
386
|
}
|
|
266
387
|
break;
|
|
267
388
|
default:
|
|
@@ -279,24 +400,25 @@ function readWmf(bytes) {
|
|
|
279
400
|
right: win.x + (win.cx || 1e3),
|
|
280
401
|
bottom: win.y + (win.cy || 1e3)
|
|
281
402
|
};
|
|
403
|
+
const flipped = win.cy < 0 ? prims.map((p) => mirrorPrimY(p, box.top + box.bottom)) : prims;
|
|
282
404
|
return {
|
|
283
|
-
left: box.left,
|
|
284
|
-
top: box.top,
|
|
405
|
+
left: Math.min(box.left, box.right),
|
|
406
|
+
top: Math.min(box.top, box.bottom),
|
|
285
407
|
width: Math.max(1, Math.abs(box.right - box.left)),
|
|
286
408
|
height: Math.max(1, Math.abs(box.bottom - box.top)),
|
|
287
|
-
prims,
|
|
409
|
+
prims: flipped,
|
|
288
410
|
skipped: [...skipped]
|
|
289
411
|
};
|
|
290
412
|
}
|
|
291
|
-
function pushText(
|
|
413
|
+
function pushText(emit, dc, text, x, y) {
|
|
292
414
|
if (text.trim() === "") return;
|
|
293
415
|
const em = Math.abs(dc.font?.heightLu ?? 12);
|
|
294
416
|
const drawn = symbolPrims(text, dc, x, y, em);
|
|
295
417
|
if (drawn) {
|
|
296
|
-
|
|
418
|
+
for (const prim of drawn) emit(prim);
|
|
297
419
|
return;
|
|
298
420
|
}
|
|
299
|
-
|
|
421
|
+
emit({
|
|
300
422
|
kind: "text",
|
|
301
423
|
text: fromSymbolFont(text, dc.font?.family),
|
|
302
424
|
x,
|
|
@@ -311,6 +433,73 @@ function pushText(prims, dc, text, x, y) {
|
|
|
311
433
|
...dc.font?.escapement ? { escapement: dc.font.escapement } : {}
|
|
312
434
|
});
|
|
313
435
|
}
|
|
436
|
+
function shiftPrim(prim, dx, dy) {
|
|
437
|
+
if (prim.kind === "text") return {
|
|
438
|
+
...prim,
|
|
439
|
+
x: prim.x + dx,
|
|
440
|
+
y: prim.y + dy
|
|
441
|
+
};
|
|
442
|
+
if (prim.kind === "image") return {
|
|
443
|
+
...prim,
|
|
444
|
+
x: prim.x + dx,
|
|
445
|
+
y: prim.y + dy
|
|
446
|
+
};
|
|
447
|
+
return {
|
|
448
|
+
...prim,
|
|
449
|
+
paths: prim.paths.map((path) => ({
|
|
450
|
+
...path,
|
|
451
|
+
segments: path.segments.map((sg) => "x" in sg ? {
|
|
452
|
+
...sg,
|
|
453
|
+
x: sg.x + dx,
|
|
454
|
+
y: sg.y + dy,
|
|
455
|
+
..."x1" in sg ? {
|
|
456
|
+
x1: sg.x1 + dx,
|
|
457
|
+
y1: sg.y1 + dy
|
|
458
|
+
} : {},
|
|
459
|
+
..."x2" in sg ? {
|
|
460
|
+
x2: sg.x2 + dx,
|
|
461
|
+
y2: sg.y2 + dy
|
|
462
|
+
} : {}
|
|
463
|
+
} : sg)
|
|
464
|
+
}))
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* A primitive mirrored about a horizontal axis, for a window whose y grows UP.
|
|
469
|
+
*
|
|
470
|
+
* Only the geometry turns over. A text run's reference point names a corner of
|
|
471
|
+
* the cell IN DEVICE SPACE — GDI never draws the glyphs themselves upside down —
|
|
472
|
+
* so the point moves and the alignment flags stay as they are. An image states
|
|
473
|
+
* the TOP of its destination rectangle, which after the mirror is where its
|
|
474
|
+
* bottom used to be.
|
|
475
|
+
*
|
|
476
|
+
* @param prim The primitive, in the metafile's own logical units.
|
|
477
|
+
* @param twiceAxis Twice the y the mirror runs along, so `y' = twiceAxis - y`.
|
|
478
|
+
* @returns The primitive with its y coordinates turned over.
|
|
479
|
+
*/
|
|
480
|
+
function mirrorPrimY(prim, twiceAxis) {
|
|
481
|
+
const at = (y) => twiceAxis - y;
|
|
482
|
+
if (prim.kind === "text") return {
|
|
483
|
+
...prim,
|
|
484
|
+
y: at(prim.y)
|
|
485
|
+
};
|
|
486
|
+
if (prim.kind === "image") return {
|
|
487
|
+
...prim,
|
|
488
|
+
y: at(prim.y + prim.height)
|
|
489
|
+
};
|
|
490
|
+
return {
|
|
491
|
+
...prim,
|
|
492
|
+
paths: prim.paths.map((path) => ({
|
|
493
|
+
...path,
|
|
494
|
+
segments: path.segments.map((sg) => "x" in sg ? {
|
|
495
|
+
...sg,
|
|
496
|
+
y: at(sg.y),
|
|
497
|
+
..."y1" in sg ? { y1: at(sg.y1) } : {},
|
|
498
|
+
..."y2" in sg ? { y2: at(sg.y2) } : {}
|
|
499
|
+
} : sg)
|
|
500
|
+
}))
|
|
501
|
+
};
|
|
502
|
+
}
|
|
314
503
|
function penStyle(style) {
|
|
315
504
|
switch (style & 15) {
|
|
316
505
|
case 1: return "dash";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The picture bytes inside one Escher BLIP record — a raster as it stands, or a
|
|
3
|
+
* metafile unpacked out of its header.
|
|
4
|
+
*
|
|
5
|
+
* @param type The blip record type (`0xF01A`…`0xF02A`).
|
|
6
|
+
* @param instance The record's `recInstance`, which says how many UIDs precede
|
|
7
|
+
* the payload.
|
|
8
|
+
* @param data The record's body, without the 8-byte header.
|
|
9
|
+
* @returns The bytes to hand the renderer, or `undefined` when the blip holds
|
|
10
|
+
* nothing this can read.
|
|
11
|
+
*/
|
|
12
|
+
export declare function readEscherBlip(type: number, instance: number, data: Uint8Array): Uint8Array | undefined;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { dibToBmp } from "../bmp.js";
|
|
2
|
+
import { unzlibSync } from "fflate";
|
|
3
|
+
//#region src/core/ole/escher-blip.ts
|
|
4
|
+
var BLIP_EMF = 61466;
|
|
5
|
+
var BLIP_WMF = 61467;
|
|
6
|
+
var BLIP_PICT = 61468;
|
|
7
|
+
var BLIP_JPEG = 61469;
|
|
8
|
+
var BLIP_PNG = 61470;
|
|
9
|
+
var BLIP_DIB = 61471;
|
|
10
|
+
var BLIP_TIFF = 61481;
|
|
11
|
+
var BLIP_JPEG_CMYK = 61482;
|
|
12
|
+
var METAFILE_HEADER_BYTES = 34;
|
|
13
|
+
var COMPRESSION_DEFLATE = 0;
|
|
14
|
+
var TWO_UID_INSTANCES = new Set([
|
|
15
|
+
981,
|
|
16
|
+
535,
|
|
17
|
+
1347,
|
|
18
|
+
1761,
|
|
19
|
+
1763,
|
|
20
|
+
1961,
|
|
21
|
+
1765,
|
|
22
|
+
481
|
|
23
|
+
]);
|
|
24
|
+
/** The signatures of the rasters a blip may hold, for the scan fallback. */
|
|
25
|
+
var RASTER_MAGICS = [
|
|
26
|
+
[
|
|
27
|
+
137,
|
|
28
|
+
80,
|
|
29
|
+
78,
|
|
30
|
+
71
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
255,
|
|
34
|
+
216,
|
|
35
|
+
255
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
71,
|
|
39
|
+
73,
|
|
40
|
+
70,
|
|
41
|
+
56
|
|
42
|
+
],
|
|
43
|
+
[66, 77]
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* The picture bytes inside one Escher BLIP record — a raster as it stands, or a
|
|
47
|
+
* metafile unpacked out of its header.
|
|
48
|
+
*
|
|
49
|
+
* @param type The blip record type (`0xF01A`…`0xF02A`).
|
|
50
|
+
* @param instance The record's `recInstance`, which says how many UIDs precede
|
|
51
|
+
* the payload.
|
|
52
|
+
* @param data The record's body, without the 8-byte header.
|
|
53
|
+
* @returns The bytes to hand the renderer, or `undefined` when the blip holds
|
|
54
|
+
* nothing this can read.
|
|
55
|
+
*/
|
|
56
|
+
function readEscherBlip(type, instance, data) {
|
|
57
|
+
if (type === BLIP_EMF || type === BLIP_WMF || type === BLIP_PICT) return readMetafileBlip(instance, data);
|
|
58
|
+
if (type === BLIP_DIB) return readDibBlip(instance, data) ?? scanRaster(data);
|
|
59
|
+
if (type === BLIP_JPEG || type === BLIP_PNG || type === BLIP_TIFF || type === BLIP_JPEG_CMYK) return scanRaster(data);
|
|
60
|
+
return scanRaster(data);
|
|
61
|
+
}
|
|
62
|
+
function readDibBlip(instance, data) {
|
|
63
|
+
const uidBytes = TWO_UID_INSTANCES.has(instance) ? 32 : 16;
|
|
64
|
+
for (const at of [uidBytes + 1, uidBytes]) {
|
|
65
|
+
if (data.length <= at) continue;
|
|
66
|
+
const bmp = dibToBmp(data.subarray(at));
|
|
67
|
+
if (bmp) return bmp;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function readMetafileBlip(instance, data) {
|
|
71
|
+
const uidBytes = TWO_UID_INSTANCES.has(instance) ? 32 : 16;
|
|
72
|
+
const head = uidBytes + METAFILE_HEADER_BYTES;
|
|
73
|
+
if (data.length < head) return void 0;
|
|
74
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
75
|
+
const uncompressed = view.getUint32(uidBytes, true);
|
|
76
|
+
const compressed = view.getUint32(uidBytes + 24, true);
|
|
77
|
+
const compression = data[uidBytes + 32];
|
|
78
|
+
const payload = data.subarray(head, Math.min(data.length, head + (compressed || Infinity)));
|
|
79
|
+
if (payload.length === 0) return void 0;
|
|
80
|
+
if (compression !== COMPRESSION_DEFLATE) return payload;
|
|
81
|
+
try {
|
|
82
|
+
const out = unzlibSync(payload, uncompressed > 0 ? { out: new Uint8Array(uncompressed) } : {});
|
|
83
|
+
return out.length > 0 ? out : void 0;
|
|
84
|
+
} catch {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function scanRaster(data) {
|
|
89
|
+
const limit = Math.min(data.length, 80);
|
|
90
|
+
for (let off = 0; off < limit; off++) for (const magic of RASTER_MAGICS) if (matches(data, off, magic)) return data.subarray(off);
|
|
91
|
+
}
|
|
92
|
+
function matches(d, off, magic) {
|
|
93
|
+
if (off + magic.length > d.length) return false;
|
|
94
|
+
for (let i = 0; i < magic.length; i++) if (d[off + i] !== magic[i]) return false;
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
//#endregion
|
|
98
|
+
export { readEscherBlip };
|
|
@@ -101,7 +101,8 @@ var DIGIT_EM = [
|
|
|
101
101
|
[/^(arial|helvetica|liberation sans|arimo|arial unicode ms)$/i, 1139 / 2048],
|
|
102
102
|
[/^(times new roman|liberation serif|tinos)$/i, 1024 / 2048],
|
|
103
103
|
[/^(tahoma)$/i, 1118 / 2048],
|
|
104
|
-
[/^(verdana|dejavu sans)$/i, 1303 / 2048]
|
|
104
|
+
[/^(verdana|dejavu sans)$/i, 1303 / 2048],
|
|
105
|
+
[/* @__PURE__ */ new RegExp("^(新細明體|細明體|pmingliu|mingliu|標楷體|dfkai-sb|宋体|新宋体|simsun|nsimsun|黑体|simhei|微软雅黑|microsoft yahei|微軟正黑體|microsoft jhenghei|MS [P]?明朝|MS [P]?ゴシック|ms [p]?mincho|ms [p]?gothic|meiryo|メイリオ|游ゴシック|yu gothic|굴림체?|gulim(che)?|돋움체?|dotum(che)?|바탕체?|batang(che)?|맑은 고딕|malgun gothic)$", "iu"), 1024 / 2048]
|
|
105
106
|
];
|
|
106
107
|
/**
|
|
107
108
|
* §18.3.1.13 — the Maximum Digit Width, in twips, of the normal style's font.
|
|
@@ -1021,6 +1022,7 @@ function runPropsFromXf(xf, styles) {
|
|
|
1021
1022
|
if (font.strike) props.strike = true;
|
|
1022
1023
|
if (font.sizePt !== void 0) props.fontSizePt = halfPtToPt(Math.round(font.sizePt * 2));
|
|
1023
1024
|
if (font.colorHex) props.colorHex = font.colorHex;
|
|
1025
|
+
if (font.name) props.fontFamily = { ascii: font.name };
|
|
1024
1026
|
return props;
|
|
1025
1027
|
}
|
|
1026
1028
|
function stackedVerticalContent(text, runProps, href) {
|
|
@@ -1120,8 +1122,8 @@ function shadingFromXf(xf, styles) {
|
|
|
1120
1122
|
if (!pattern || pattern === "none") return void 0;
|
|
1121
1123
|
if (pattern === "solid") return fill.fgColorHex ? { colorHex: fill.fgColorHex } : void 0;
|
|
1122
1124
|
const density = PATTERN_DENSITY[pattern];
|
|
1123
|
-
if (density === void 0
|
|
1124
|
-
const blended = blendHex(fill.fgColorHex, fill.bgColorHex ?? "FFFFFF", density);
|
|
1125
|
+
if (density === void 0) return void 0;
|
|
1126
|
+
const blended = blendHex(fill.fgColorHex ?? "000000", fill.bgColorHex ?? "FFFFFF", density);
|
|
1125
1127
|
return blended ? { colorHex: blended } : void 0;
|
|
1126
1128
|
}
|
|
1127
1129
|
function blendHex(fg, bg, fraction) {
|
|
@@ -162,7 +162,7 @@ function makeColWidthPt(ws) {
|
|
|
162
162
|
return (col) => {
|
|
163
163
|
for (const c of ws.columns) if (col >= c.min - 1 && col <= c.max - 1) return widthPt(c.widthChars);
|
|
164
164
|
if (ws.defaultColWidthChars !== void 0) return widthPt(ws.defaultColWidthChars);
|
|
165
|
-
if (ws.baseColWidthChars !== void 0) return (columnTwips(ws.baseColWidthChars, 105) +
|
|
165
|
+
if (ws.baseColWidthChars !== void 0) return (columnTwips(ws.baseColWidthChars, 105) + 150) / TWIPS_PER_PT;
|
|
166
166
|
return 960 / TWIPS_PER_PT;
|
|
167
167
|
};
|
|
168
168
|
}
|
|
@@ -401,8 +401,16 @@ function withDrawingsByBand(drawings, gridBody, lefts) {
|
|
|
401
401
|
const byBand = lefts.map(() => []);
|
|
402
402
|
for (const el of drawings) {
|
|
403
403
|
const x = floatLeftPt(el);
|
|
404
|
-
|
|
405
|
-
|
|
404
|
+
if (x === void 0) {
|
|
405
|
+
byBand[0].push(el);
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const start = bandOf(x);
|
|
409
|
+
const right = x + (floatWidthPt(el) ?? 0);
|
|
410
|
+
for (let band = start; band < lefts.length; band++) {
|
|
411
|
+
if (band > start && right <= lefts[band]) break;
|
|
412
|
+
byBand[band].push(shiftFloatLeft(el, lefts[band]));
|
|
413
|
+
}
|
|
406
414
|
}
|
|
407
415
|
const out = [];
|
|
408
416
|
let seen = 0;
|
|
@@ -416,6 +424,12 @@ function withDrawingsByBand(drawings, gridBody, lefts) {
|
|
|
416
424
|
function floatLeftPt(el) {
|
|
417
425
|
return (el.kind === "chart" ? el.chart.float : el.kind === "image" ? el.image.float : el.kind === "shape" ? el.shape.float : void 0)?.posH?.offsetPt;
|
|
418
426
|
}
|
|
427
|
+
/** A float's own width, for the block kinds a sheet anchors. */
|
|
428
|
+
function floatWidthPt(el) {
|
|
429
|
+
if (el.kind === "chart") return el.chart.width;
|
|
430
|
+
if (el.kind === "image") return el.image.width;
|
|
431
|
+
if (el.kind === "shape") return el.shape.width;
|
|
432
|
+
}
|
|
419
433
|
/** The same block with its horizontal anchor measured from `by` points later. */
|
|
420
434
|
function shiftFloatLeft(el, by) {
|
|
421
435
|
if (by === 0) return el;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { INDEXED_COLORS } from "../core/indexed-colors.js";
|
|
2
2
|
import { applyColorMods } from "../core/drawingml/colors.js";
|
|
3
|
-
import { resolveInternalEntities } from "../core/opc/xml-entities.js";
|
|
4
3
|
import { resolveAlternateContent } from "../core/opc/alternate-content.js";
|
|
4
|
+
import { resolveInternalEntities } from "../core/opc/xml-entities.js";
|
|
5
5
|
import { XMLParser } from "fast-xml-parser";
|
|
6
6
|
//#region src/excel/styles-parser.ts
|
|
7
7
|
var decoder = new TextDecoder("utf-8");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { pt } from "../../core/ir/units.js";
|
|
2
2
|
import { ResourceStore } from "../../core/ir/resources.js";
|
|
3
|
+
import { makeColWidthPt, makeRowHeightPt } from "../sheet-drawing.js";
|
|
3
4
|
import { openCfb } from "../../core/ole/cfb.js";
|
|
4
5
|
import { parseBiffChart } from "./biff-chart.js";
|
|
5
6
|
import { buildBiffPalette, parseBiffStyles } from "./biff-styles.js";
|
|
@@ -333,7 +334,8 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
333
334
|
...pane ? { pane } : {}
|
|
334
335
|
};
|
|
335
336
|
const drawing = gatherDrawing(records, REC.MSODRAWING);
|
|
336
|
-
const
|
|
337
|
+
const place = anchorPlacer(grid);
|
|
338
|
+
const images = drawing.length > 0 && blips.length > 0 ? buildImages(drawing, blips, resources, place) : [];
|
|
337
339
|
const charts = [];
|
|
338
340
|
for (let i = 0; i < records.length; i++) {
|
|
339
341
|
if (records[i].type !== REC.BOF || readU16(records[i].data, 2) !== 32) continue;
|
|
@@ -361,7 +363,7 @@ function readSheet(wb, view, start, blips, resources, sharedStrings, chartData,
|
|
|
361
363
|
grid,
|
|
362
364
|
images,
|
|
363
365
|
charts,
|
|
364
|
-
shapes: drawing.length > 0 ? buildShapes(parseSheetShapes(drawing), gatherTxoTexts(records)) : [],
|
|
366
|
+
shapes: drawing.length > 0 ? buildShapes(parseSheetShapes(drawing), gatherTxoTexts(records), place) : [],
|
|
365
367
|
hyperlinks,
|
|
366
368
|
comments: parseComments(records)
|
|
367
369
|
};
|
|
@@ -1174,13 +1176,24 @@ function parseComments(records) {
|
|
|
1174
1176
|
}
|
|
1175
1177
|
return out;
|
|
1176
1178
|
}
|
|
1177
|
-
function buildShapes(escherShapes, txoTexts) {
|
|
1179
|
+
function buildShapes(escherShapes, txoTexts, place) {
|
|
1178
1180
|
const out = [];
|
|
1179
1181
|
let textIdx = 0;
|
|
1180
1182
|
for (const s of escherShapes) {
|
|
1181
1183
|
const text = s.hasText ? txoTexts[textIdx++] ?? "" : "";
|
|
1182
|
-
const { widthPt, heightPt } =
|
|
1184
|
+
const { xPt, yPt, widthPt, heightPt } = place(s.anchor);
|
|
1183
1185
|
out.push({
|
|
1186
|
+
float: {
|
|
1187
|
+
wrap: "none",
|
|
1188
|
+
posH: {
|
|
1189
|
+
relativeFrom: "margin",
|
|
1190
|
+
offsetPt: pt(xPt)
|
|
1191
|
+
},
|
|
1192
|
+
posV: {
|
|
1193
|
+
relativeFrom: "margin",
|
|
1194
|
+
offsetPt: pt(yPt)
|
|
1195
|
+
}
|
|
1196
|
+
},
|
|
1184
1197
|
width: pt(widthPt),
|
|
1185
1198
|
height: pt(heightPt),
|
|
1186
1199
|
geometry: {
|
|
@@ -1222,34 +1235,56 @@ function shapePreset(type) {
|
|
|
1222
1235
|
default: return "rect";
|
|
1223
1236
|
}
|
|
1224
1237
|
}
|
|
1225
|
-
function buildImages(drawing, blips, resources) {
|
|
1238
|
+
function buildImages(drawing, blips, resources, place) {
|
|
1226
1239
|
const out = [];
|
|
1227
1240
|
for (const pic of parseSheetPictures(drawing)) {
|
|
1228
1241
|
const bytes = blips[pic.blipIndex - 1];
|
|
1229
1242
|
if (!bytes) continue;
|
|
1230
|
-
const { widthPt, heightPt } =
|
|
1243
|
+
const { xPt, yPt, widthPt, heightPt } = place(pic.anchor);
|
|
1231
1244
|
out.push({
|
|
1232
1245
|
resourceId: resources.put(bytes),
|
|
1233
1246
|
widthPt,
|
|
1234
|
-
heightPt
|
|
1247
|
+
heightPt,
|
|
1248
|
+
xPt,
|
|
1249
|
+
yPt
|
|
1235
1250
|
});
|
|
1236
1251
|
}
|
|
1237
1252
|
return out;
|
|
1238
1253
|
}
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1254
|
+
function anchorPlacer(grid) {
|
|
1255
|
+
const colPt = makeColWidthPt(grid);
|
|
1256
|
+
const rowPt = makeRowHeightPt(grid);
|
|
1257
|
+
const before = (track) => {
|
|
1258
|
+
const sums = [0];
|
|
1259
|
+
return (index) => {
|
|
1260
|
+
const n = Math.min(Math.max(Math.trunc(index), 0), MAX_ANCHOR_TRACKS);
|
|
1261
|
+
while (sums.length <= n) sums.push(sums[sums.length - 1] + track(sums.length - 1));
|
|
1262
|
+
return sums[n];
|
|
1263
|
+
};
|
|
1243
1264
|
};
|
|
1244
|
-
const
|
|
1245
|
-
const
|
|
1246
|
-
const
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1265
|
+
const beforeCol = before(colPt);
|
|
1266
|
+
const beforeRow = before(rowPt);
|
|
1267
|
+
const at = (index, off, start, track) => start(index) + off / 1024 * track(index);
|
|
1268
|
+
return (anchor) => {
|
|
1269
|
+
if (!anchor) return {
|
|
1270
|
+
xPt: 0,
|
|
1271
|
+
yPt: 0,
|
|
1272
|
+
widthPt: 96,
|
|
1273
|
+
heightPt: 72
|
|
1274
|
+
};
|
|
1275
|
+
const x1 = at(anchor.col1, anchor.dx1, beforeCol, colPt);
|
|
1276
|
+
const x2 = at(anchor.col2, anchor.dx2, beforeCol, colPt);
|
|
1277
|
+
const y1 = at(anchor.row1, anchor.dy1, beforeRow, rowPt);
|
|
1278
|
+
const y2 = at(anchor.row2, anchor.dy2, beforeRow, rowPt);
|
|
1279
|
+
return {
|
|
1280
|
+
xPt: x1,
|
|
1281
|
+
yPt: y1,
|
|
1282
|
+
widthPt: Math.max(1, x2 - x1),
|
|
1283
|
+
heightPt: Math.max(1, y2 - y1)
|
|
1284
|
+
};
|
|
1251
1285
|
};
|
|
1252
1286
|
}
|
|
1287
|
+
var MAX_ANCHOR_TRACKS = 65536;
|
|
1253
1288
|
function numCell(row, column, style, rawValue) {
|
|
1254
1289
|
return {
|
|
1255
1290
|
column,
|
|
@@ -4,8 +4,11 @@ interface BiffRec {
|
|
|
4
4
|
readonly data: Uint8Array;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
* Build a palette-index → `"
|
|
8
|
-
*
|
|
7
|
+
* Build a palette-index → `"RRGGBB"` resolver from the default 56-colour palette
|
|
8
|
+
* plus any `PALETTE` override. Six hex digits, not the eight an xlsx `rgb`
|
|
9
|
+
* attribute carries: by the time styles are parsed the alpha is gone, and a
|
|
10
|
+
* colour that kept it was read from its first six characters — silver `C0C0C0`
|
|
11
|
+
* reaching the page as the pink `FFC0C0`.
|
|
9
12
|
* `0x7FFF` / 64 / 65 are automatic or system colours → `undefined` (the renderer
|
|
10
13
|
* default). Exported so the conditional-format reader (XLS-13) resolves its dxf
|
|
11
14
|
* colours the same way.
|
|
@@ -116,8 +116,11 @@ var PALETTE56 = [
|
|
|
116
116
|
"333333"
|
|
117
117
|
];
|
|
118
118
|
/**
|
|
119
|
-
* Build a palette-index → `"
|
|
120
|
-
*
|
|
119
|
+
* Build a palette-index → `"RRGGBB"` resolver from the default 56-colour palette
|
|
120
|
+
* plus any `PALETTE` override. Six hex digits, not the eight an xlsx `rgb`
|
|
121
|
+
* attribute carries: by the time styles are parsed the alpha is gone, and a
|
|
122
|
+
* colour that kept it was read from its first six characters — silver `C0C0C0`
|
|
123
|
+
* reaching the page as the pink `FFC0C0`.
|
|
121
124
|
* `0x7FFF` / 64 / 65 are automatic or system colours → `undefined` (the renderer
|
|
122
125
|
* default). Exported so the conditional-format reader (XLS-13) resolves its dxf
|
|
123
126
|
* colours the same way.
|
|
@@ -130,8 +133,7 @@ function buildBiffPalette(records) {
|
|
|
130
133
|
for (const rec of records) if (rec.type === REC_PALETTE) applyPalette(rec.data, palette);
|
|
131
134
|
return (icv) => {
|
|
132
135
|
if (icv === 32767 || icv === 64 || icv === 65) return void 0;
|
|
133
|
-
|
|
134
|
-
return rgb ? `FF${rgb}` : void 0;
|
|
136
|
+
return palette[icv];
|
|
135
137
|
};
|
|
136
138
|
}
|
|
137
139
|
/**
|
|
@@ -252,11 +254,11 @@ function parseXf(d, color, internFill, internBorder) {
|
|
|
252
254
|
if (right) border.right = right;
|
|
253
255
|
if (top) border.top = top;
|
|
254
256
|
if (bottom) border.bottom = bottom;
|
|
255
|
-
const patternType = FILL_PATTERNS[brd3 >>
|
|
257
|
+
const patternType = FILL_PATTERNS[brd3 >> 10 & 63];
|
|
256
258
|
let fill;
|
|
257
259
|
if (patternType && patternType !== "none") {
|
|
258
|
-
const fg = color(brd3 & 127);
|
|
259
|
-
const bg = color(brd3 >>
|
|
260
|
+
const fg = color(brd3 >> 16 & 127);
|
|
261
|
+
const bg = color(brd3 >> 23 & 127);
|
|
260
262
|
fill = {
|
|
261
263
|
patternType,
|
|
262
264
|
...fg ? { fgColorHex: fg } : {},
|