reamkit 1.21.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/bytes.d.ts +22 -4
- package/dist/esm/core/bytes.js +73 -5
- package/dist/esm/core/converter/ream.d.ts +16 -0
- package/dist/esm/core/converter/ream.js +59 -9
- package/dist/esm/core/document-model/types.d.ts +78 -0
- package/dist/esm/core/drawingml/chart-geometry.js +11 -5
- package/dist/esm/core/drawingml/chart-parser.d.ts +2 -1
- package/dist/esm/core/drawingml/chart-parser.js +23 -1
- package/dist/esm/core/drawingml/colors.d.ts +30 -4
- package/dist/esm/core/drawingml/colors.js +45 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
- package/dist/esm/core/drawingml/theme-parser.js +64 -1
- 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/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 +139 -24
- package/dist/esm/core/metafile/picture.d.ts +12 -1
- package/dist/esm/core/metafile/symbol-fonts.d.ts +42 -0
- package/dist/esm/core/metafile/symbol-fonts.js +154 -0
- package/dist/esm/core/metafile/wmf.js +183 -10
- package/dist/esm/core/ole/escher-blip.d.ts +12 -0
- package/dist/esm/core/ole/escher-blip.js +88 -0
- package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/print-model.js +3 -1
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- 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/excel/xlsx-reader.d.ts +1 -1
- package/dist/esm/excel/xlsx-reader.js +3 -3
- package/dist/esm/layout/page-doc.d.ts +77 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.d.ts +2 -2
- package/dist/esm/layout/styled-layout.js +467 -76
- package/dist/esm/pdf/shading.d.ts +19 -0
- package/dist/esm/pdf/shading.js +84 -11
- package/dist/esm/pdf/styled-page-emitter.js +647 -444
- 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/ole-preview.d.ts +10 -0
- package/dist/esm/pptx/ole-preview.js +52 -0
- package/dist/esm/pptx/placeholder-cascade.d.ts +136 -5
- package/dist/esm/pptx/placeholder-cascade.js +260 -27
- package/dist/esm/pptx/ppt/ppt-reader.js +120 -10
- package/dist/esm/pptx/ppt/ppt-text.d.ts +66 -1
- package/dist/esm/pptx/ppt/ppt-text.js +576 -137
- package/dist/esm/pptx/pptx-reader.d.ts +8 -0
- package/dist/esm/pptx/pptx-reader.js +271 -41
- 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 +78 -10
- package/dist/esm/pptx/slide-parser.js +396 -95
- package/dist/esm/pptx/sp-helpers.d.ts +2 -1
- package/dist/esm/pptx/sp-helpers.js +22 -6
- package/dist/esm/pptx/table-style.d.ts +64 -0
- package/dist/esm/pptx/table-style.js +203 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/document-parser.d.ts +7 -1
- package/dist/esm/word/document-parser.js +6 -6
- package/dist/esm/word/docx-reader.js +8 -5
- 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/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +173 -15
- 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 +3 -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,8 @@
|
|
|
1
1
|
import { PathBuilder } from "../vector.js";
|
|
2
2
|
import { applyTransform, cloneDc, colorRef, newDeviceContext } from "./picture.js";
|
|
3
|
+
import { cropDib, fadedDib, readDib } from "./dib.js";
|
|
4
|
+
import { makeBlitter } from "./blit.js";
|
|
5
|
+
import { fromSymbolFont } from "./symbol-fonts.js";
|
|
3
6
|
//#region src/core/metafile/emf.ts
|
|
4
7
|
/** Whether the bytes open with an EMF header (MS-EMF §2.3.4.2: type 1 + " EMF"). */
|
|
5
8
|
function isEmf(bytes) {
|
|
@@ -20,11 +23,6 @@ var RECORD_NAMES = new Map([
|
|
|
20
23
|
[74, "region paint"],
|
|
21
24
|
[78, "masked blit"],
|
|
22
25
|
[79, "parallelogram blit"],
|
|
23
|
-
[80, "device bitmap"],
|
|
24
|
-
[81, "bitmap"],
|
|
25
|
-
[76, "bitmap"],
|
|
26
|
-
[77, "bitmap"],
|
|
27
|
-
[114, "alpha blit"],
|
|
28
26
|
[116, "transparent blit"],
|
|
29
27
|
[118, "gradient fill"]
|
|
30
28
|
]);
|
|
@@ -73,6 +71,34 @@ function readEmf(bytes) {
|
|
|
73
71
|
};
|
|
74
72
|
let building;
|
|
75
73
|
const open = () => building ?? [];
|
|
74
|
+
const blitter = makeBlitter((prim) => prims.push(prim));
|
|
75
|
+
/**
|
|
76
|
+
* §2.3.1 — one blit record: the source bitmap into the destination
|
|
77
|
+
* rectangle, both stated in the record's own fields. The rectangle is mapped
|
|
78
|
+
* the way every other coordinate here is, so the picture lands in the same
|
|
79
|
+
* device frame as the paths around it.
|
|
80
|
+
*/
|
|
81
|
+
const blit = (o) => {
|
|
82
|
+
const dib = o.cbBmi > 0 ? readDib(bytes, off + o.bmiAt, {
|
|
83
|
+
bitsAt: off + o.bitsAt,
|
|
84
|
+
cbBits: o.cbBits,
|
|
85
|
+
...o.blend?.perPixel === true ? { alpha: true } : {}
|
|
86
|
+
}) : void 0;
|
|
87
|
+
if (!dib) {
|
|
88
|
+
skipped.add("bitmap");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const s = o.src;
|
|
92
|
+
const part = s && (s.x !== 0 || s.y !== 0 || s.w !== dib.width || s.h !== dib.height) ? cropDib(dib, s.x, o.inBitmap === true && dib.bottomUp === true ? dib.height - s.y - s.h : s.y, s.w, s.h) : dib;
|
|
93
|
+
const a = px(o.dest.x, o.dest.y);
|
|
94
|
+
const b = px(o.dest.x + o.dest.w, o.dest.y + o.dest.h);
|
|
95
|
+
blitter.blit(o.blend && o.blend.alpha < 255 ? fadedDib(part, o.blend.alpha / 255) : part, {
|
|
96
|
+
x: Math.min(a.x, b.x),
|
|
97
|
+
y: Math.min(a.y, b.y),
|
|
98
|
+
width: Math.abs(b.x - a.x),
|
|
99
|
+
height: Math.abs(b.y - a.y)
|
|
100
|
+
}, o.rop);
|
|
101
|
+
};
|
|
76
102
|
const strokeOf = () => {
|
|
77
103
|
if (dc.pen.style === "none") return void 0;
|
|
78
104
|
const w = dc.pen.widthLu <= 1 ? 1 : dc.pen.widthLu * Math.abs(sx());
|
|
@@ -371,7 +397,7 @@ function readEmf(bytes) {
|
|
|
371
397
|
const font = dc.font;
|
|
372
398
|
prims.push({
|
|
373
399
|
kind: "text",
|
|
374
|
-
text,
|
|
400
|
+
text: fromSymbolFont(text, font?.family),
|
|
375
401
|
x: p.x,
|
|
376
402
|
y: p.y,
|
|
377
403
|
alignH: dc.alignH,
|
|
@@ -387,25 +413,114 @@ function readEmf(bytes) {
|
|
|
387
413
|
}
|
|
388
414
|
break;
|
|
389
415
|
case 76:
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
416
|
+
case 77: {
|
|
417
|
+
const cbBmiSrc = u(88);
|
|
418
|
+
const rop = u(40);
|
|
419
|
+
const x = at(24);
|
|
420
|
+
const y = at(28);
|
|
421
|
+
const w = at(32);
|
|
422
|
+
const h = at(36);
|
|
423
|
+
if (cbBmiSrc === 0) {
|
|
424
|
+
const hex = rop === 66 ? "000000" : rop === 16711778 ? "FFFFFF" : void 0;
|
|
425
|
+
const brush = dc.brush;
|
|
426
|
+
if (hex !== void 0) dc.brush = {
|
|
427
|
+
kind: "brush",
|
|
428
|
+
colorHex: hex,
|
|
429
|
+
hollow: false
|
|
430
|
+
};
|
|
431
|
+
paint(rectSegments(x, y, x + w, y + h), true, false);
|
|
432
|
+
dc.brush = brush;
|
|
433
|
+
break;
|
|
408
434
|
}
|
|
435
|
+
blit({
|
|
436
|
+
bmiAt: u(84),
|
|
437
|
+
cbBmi: cbBmiSrc,
|
|
438
|
+
bitsAt: u(92),
|
|
439
|
+
cbBits: u(96),
|
|
440
|
+
dest: {
|
|
441
|
+
x,
|
|
442
|
+
y,
|
|
443
|
+
w,
|
|
444
|
+
h
|
|
445
|
+
},
|
|
446
|
+
src: {
|
|
447
|
+
x: at(44),
|
|
448
|
+
y: at(48),
|
|
449
|
+
w: type === 77 ? at(100) : w,
|
|
450
|
+
h: type === 77 ? at(104) : h
|
|
451
|
+
},
|
|
452
|
+
rop
|
|
453
|
+
});
|
|
454
|
+
break;
|
|
455
|
+
}
|
|
456
|
+
case 80:
|
|
457
|
+
blit({
|
|
458
|
+
bmiAt: u(48),
|
|
459
|
+
cbBmi: u(52),
|
|
460
|
+
bitsAt: u(56),
|
|
461
|
+
cbBits: u(60),
|
|
462
|
+
dest: {
|
|
463
|
+
x: at(24),
|
|
464
|
+
y: at(28),
|
|
465
|
+
w: at(40),
|
|
466
|
+
h: at(44)
|
|
467
|
+
},
|
|
468
|
+
src: {
|
|
469
|
+
x: at(32),
|
|
470
|
+
y: at(36),
|
|
471
|
+
w: at(40),
|
|
472
|
+
h: at(44)
|
|
473
|
+
},
|
|
474
|
+
inBitmap: true,
|
|
475
|
+
rop: 13369376
|
|
476
|
+
});
|
|
477
|
+
break;
|
|
478
|
+
case 81:
|
|
479
|
+
blit({
|
|
480
|
+
bmiAt: u(48),
|
|
481
|
+
cbBmi: u(52),
|
|
482
|
+
bitsAt: u(56),
|
|
483
|
+
cbBits: u(60),
|
|
484
|
+
dest: {
|
|
485
|
+
x: at(24),
|
|
486
|
+
y: at(28),
|
|
487
|
+
w: at(72),
|
|
488
|
+
h: at(76)
|
|
489
|
+
},
|
|
490
|
+
src: {
|
|
491
|
+
x: at(32),
|
|
492
|
+
y: at(36),
|
|
493
|
+
w: at(40),
|
|
494
|
+
h: at(44)
|
|
495
|
+
},
|
|
496
|
+
inBitmap: true,
|
|
497
|
+
rop: u(68)
|
|
498
|
+
});
|
|
499
|
+
break;
|
|
500
|
+
case 114:
|
|
501
|
+
blit({
|
|
502
|
+
bmiAt: u(84),
|
|
503
|
+
cbBmi: u(88),
|
|
504
|
+
bitsAt: u(92),
|
|
505
|
+
cbBits: u(96),
|
|
506
|
+
dest: {
|
|
507
|
+
x: at(24),
|
|
508
|
+
y: at(28),
|
|
509
|
+
w: at(32),
|
|
510
|
+
h: at(36)
|
|
511
|
+
},
|
|
512
|
+
src: {
|
|
513
|
+
x: at(44),
|
|
514
|
+
y: at(48),
|
|
515
|
+
w: at(100),
|
|
516
|
+
h: at(104)
|
|
517
|
+
},
|
|
518
|
+
blend: {
|
|
519
|
+
alpha: u(40) >>> 16 & 255,
|
|
520
|
+
perPixel: u(40) >>> 24 === 1
|
|
521
|
+
},
|
|
522
|
+
rop: 13369376
|
|
523
|
+
});
|
|
409
524
|
break;
|
|
410
525
|
default:
|
|
411
526
|
{
|
|
@@ -74,7 +74,18 @@ export interface MetaFont {
|
|
|
74
74
|
readonly italic?: boolean;
|
|
75
75
|
readonly escapement?: number;
|
|
76
76
|
}
|
|
77
|
-
|
|
77
|
+
/**
|
|
78
|
+
* An object the reader does not model — a palette, a region, a pattern brush.
|
|
79
|
+
* It still OCCUPIES a slot in the metafile's object table: handles are indices
|
|
80
|
+
* into that table, so a creation the reader passed over silently shifted every
|
|
81
|
+
* one that followed. 23884's chart selects its coloured pens by handle, and one
|
|
82
|
+
* unrecorded palette put every selection one slot back — on the black pen the
|
|
83
|
+
* pens had displaced.
|
|
84
|
+
*/
|
|
85
|
+
export interface MetaOther {
|
|
86
|
+
readonly kind: 'other';
|
|
87
|
+
}
|
|
88
|
+
export type MetaObject = MetaPen | MetaBrush | MetaFont | MetaOther;
|
|
78
89
|
/** The device context: everything a record draws THROUGH. */
|
|
79
90
|
export interface DeviceContext {
|
|
80
91
|
pen: MetaPen;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { VectorPath } from '../vector.js';
|
|
2
|
+
/**
|
|
3
|
+
* The geometry a symbol character DRAWS, for the handful that are plain shapes.
|
|
4
|
+
*
|
|
5
|
+
* Translating them to Unicode is not enough on its own: the substitute font a
|
|
6
|
+
* document renders with has no `●` either, and a missing glyph is a box with
|
|
7
|
+
* its code number in it — which is what 45541_Footer's table filled sixty-eight
|
|
8
|
+
* cells with. A shape this simple is better drawn than spelled.
|
|
9
|
+
*
|
|
10
|
+
* Measured off the fonts themselves: both fill the em square, one unit wide,
|
|
11
|
+
* from 0.2 em below the baseline to 0.8 em above it.
|
|
12
|
+
*/
|
|
13
|
+
export type SymbolGeometry = 'circle' | 'square' | 'diamond';
|
|
14
|
+
/**
|
|
15
|
+
* The shapes a symbol string draws, one per character, or `undefined` when any
|
|
16
|
+
* character is not one of them — a string that mixes a pictogram with a circle
|
|
17
|
+
* stays text, which is the safer half of the trade.
|
|
18
|
+
*
|
|
19
|
+
* @param text The string as stored.
|
|
20
|
+
* @param family The typeface it is drawn with.
|
|
21
|
+
*/
|
|
22
|
+
export declare function symbolGeometryOf(text: string, family: string | undefined): Array<SymbolGeometry> | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The outline of one symbol in a box, as the path segments a picture draws.
|
|
25
|
+
*
|
|
26
|
+
* @param shape Which symbol.
|
|
27
|
+
* @param left The box's left edge, in the metafile's logical units.
|
|
28
|
+
* @param top Its top edge (y grows DOWN, as a metafile has it).
|
|
29
|
+
* @param size The em, which is both the width and the height of the box.
|
|
30
|
+
* @returns The closed outline.
|
|
31
|
+
*/
|
|
32
|
+
export declare function symbolOutline(shape: SymbolGeometry, left: number, top: number, size: number): VectorPath;
|
|
33
|
+
/** Whether a typeface's characters are symbols rather than letters. */
|
|
34
|
+
export declare function isSymbolFont(family: string | undefined): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Translate a string drawn in a symbol font to the Unicode that means the same.
|
|
37
|
+
*
|
|
38
|
+
* @param text The string as the metafile stored it.
|
|
39
|
+
* @param family The typeface it was drawn with.
|
|
40
|
+
* @returns The translated string; characters with no counterpart are kept.
|
|
41
|
+
*/
|
|
42
|
+
export declare function fromSymbolFont(text: string, family: string | undefined): string;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { PathBuilder } from "../vector.js";
|
|
2
|
+
//#region src/core/metafile/symbol-fonts.ts
|
|
3
|
+
/** Half a circle's control-point distance for a cubic quarter-arc. */
|
|
4
|
+
var KAPPA = .5522847498307936;
|
|
5
|
+
/**
|
|
6
|
+
* The shapes a symbol string draws, one per character, or `undefined` when any
|
|
7
|
+
* character is not one of them — a string that mixes a pictogram with a circle
|
|
8
|
+
* stays text, which is the safer half of the trade.
|
|
9
|
+
*
|
|
10
|
+
* @param text The string as stored.
|
|
11
|
+
* @param family The typeface it is drawn with.
|
|
12
|
+
*/
|
|
13
|
+
function symbolGeometryOf(text, family) {
|
|
14
|
+
const table = family === void 0 ? void 0 : GEOMETRY_TABLES.get(normalize(family));
|
|
15
|
+
if (!table || text.length === 0) return void 0;
|
|
16
|
+
const out = [];
|
|
17
|
+
for (const ch of text) {
|
|
18
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
19
|
+
const key = code >= 61440 && code <= 61695 ? code - 61440 : code;
|
|
20
|
+
const shape = table.get(key);
|
|
21
|
+
if (shape === void 0) return void 0;
|
|
22
|
+
out.push(shape);
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The outline of one symbol in a box, as the path segments a picture draws.
|
|
28
|
+
*
|
|
29
|
+
* @param shape Which symbol.
|
|
30
|
+
* @param left The box's left edge, in the metafile's logical units.
|
|
31
|
+
* @param top Its top edge (y grows DOWN, as a metafile has it).
|
|
32
|
+
* @param size The em, which is both the width and the height of the box.
|
|
33
|
+
* @returns The closed outline.
|
|
34
|
+
*/
|
|
35
|
+
function symbolOutline(shape, left, top, size) {
|
|
36
|
+
const b = new PathBuilder();
|
|
37
|
+
const r = size / 2;
|
|
38
|
+
const [cx, cy] = [left + r, top + r];
|
|
39
|
+
if (shape === "circle") {
|
|
40
|
+
const k = r * KAPPA;
|
|
41
|
+
return b.moveTo(cx, top).cubicTo(cx + k, top, left + size, cy - k, left + size, cy).cubicTo(left + size, cy + k, cx + k, top + size, cx, top + size).cubicTo(cx - k, top + size, left, cy + k, left, cy).cubicTo(left, cy - k, cx - k, top, cx, top).close().build();
|
|
42
|
+
}
|
|
43
|
+
if (shape === "diamond") return b.moveTo(cx, top).lineTo(left + size, cy).lineTo(cx, top + size).lineTo(left, cy).close().build();
|
|
44
|
+
return b.moveTo(left, top).lineTo(left + size, top).lineTo(left + size, top + size).lineTo(left, top + size).close().build();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Translate a string drawn in a symbol font to the Unicode that means the same.
|
|
48
|
+
*
|
|
49
|
+
* @param text The string as the metafile stored it.
|
|
50
|
+
* @param family The typeface it was drawn with.
|
|
51
|
+
* @returns The translated string; characters with no counterpart are kept.
|
|
52
|
+
*/
|
|
53
|
+
function fromSymbolFont(text, family) {
|
|
54
|
+
const table = family === void 0 ? void 0 : SYMBOL_TABLES.get(normalize(family));
|
|
55
|
+
if (!table) return text;
|
|
56
|
+
let out = "";
|
|
57
|
+
for (const ch of text) {
|
|
58
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
59
|
+
const key = code >= 61440 && code <= 61695 ? code - 61440 : code;
|
|
60
|
+
out += table.get(key) ?? ch;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function normalize(family) {
|
|
65
|
+
return family.trim().toLowerCase();
|
|
66
|
+
}
|
|
67
|
+
var WINGDINGS = new Map([
|
|
68
|
+
[108, "●"],
|
|
69
|
+
[109, "❍"],
|
|
70
|
+
[110, "■"],
|
|
71
|
+
[111, "□"],
|
|
72
|
+
[112, "❑"],
|
|
73
|
+
[113, "❒"],
|
|
74
|
+
[114, "▪"],
|
|
75
|
+
[115, "▪"],
|
|
76
|
+
[116, "▫"],
|
|
77
|
+
[117, "◆"],
|
|
78
|
+
[118, "❖"],
|
|
79
|
+
[119, "◇"],
|
|
80
|
+
[120, "✗"],
|
|
81
|
+
[159, "•"],
|
|
82
|
+
[167, "▪"],
|
|
83
|
+
[252, "✔"],
|
|
84
|
+
[253, "✘"],
|
|
85
|
+
[254, "☑"],
|
|
86
|
+
[255, "☒"]
|
|
87
|
+
]);
|
|
88
|
+
var WEBDINGS = new Map([
|
|
89
|
+
[103, "■"],
|
|
90
|
+
[108, "■"],
|
|
91
|
+
[110, "●"],
|
|
92
|
+
[111, "○"],
|
|
93
|
+
[112, "□"],
|
|
94
|
+
[114, "◆"],
|
|
95
|
+
[115, "▲"],
|
|
96
|
+
[116, "▼"],
|
|
97
|
+
[161, "●"]
|
|
98
|
+
]);
|
|
99
|
+
var SYMBOL = new Map([
|
|
100
|
+
[97, "α"],
|
|
101
|
+
[98, "β"],
|
|
102
|
+
[99, "χ"],
|
|
103
|
+
[100, "δ"],
|
|
104
|
+
[101, "ε"],
|
|
105
|
+
[102, "φ"],
|
|
106
|
+
[103, "γ"],
|
|
107
|
+
[104, "η"],
|
|
108
|
+
[108, "λ"],
|
|
109
|
+
[109, "μ"],
|
|
110
|
+
[112, "π"],
|
|
111
|
+
[114, "ρ"],
|
|
112
|
+
[115, "σ"],
|
|
113
|
+
[116, "τ"],
|
|
114
|
+
[119, "ω"],
|
|
115
|
+
[183, "•"],
|
|
116
|
+
[215, "×"],
|
|
117
|
+
[177, "±"],
|
|
118
|
+
[163, "≤"],
|
|
119
|
+
[179, "≥"],
|
|
120
|
+
[185, "≠"],
|
|
121
|
+
[187, "≈"]
|
|
122
|
+
]);
|
|
123
|
+
var WINGDINGS_GEOMETRY = new Map([
|
|
124
|
+
[108, "circle"],
|
|
125
|
+
[110, "square"],
|
|
126
|
+
[111, "square"],
|
|
127
|
+
[114, "square"],
|
|
128
|
+
[115, "square"],
|
|
129
|
+
[117, "diamond"],
|
|
130
|
+
[119, "diamond"]
|
|
131
|
+
]);
|
|
132
|
+
var GEOMETRY_TABLES = new Map([
|
|
133
|
+
["wingdings", WINGDINGS_GEOMETRY],
|
|
134
|
+
["wingdings 2", WINGDINGS_GEOMETRY],
|
|
135
|
+
["wingdings 3", WINGDINGS_GEOMETRY],
|
|
136
|
+
["webdings", new Map([
|
|
137
|
+
[103, "square"],
|
|
138
|
+
[108, "square"],
|
|
139
|
+
[110, "circle"]
|
|
140
|
+
])],
|
|
141
|
+
["monotype sorts", WINGDINGS_GEOMETRY],
|
|
142
|
+
["zapfdingbats", WINGDINGS_GEOMETRY]
|
|
143
|
+
]);
|
|
144
|
+
var SYMBOL_TABLES = new Map([
|
|
145
|
+
["wingdings", WINGDINGS],
|
|
146
|
+
["wingdings 2", WINGDINGS],
|
|
147
|
+
["wingdings 3", WINGDINGS],
|
|
148
|
+
["webdings", WEBDINGS],
|
|
149
|
+
["symbol", SYMBOL],
|
|
150
|
+
["monotype sorts", WINGDINGS],
|
|
151
|
+
["zapfdingbats", WINGDINGS]
|
|
152
|
+
]);
|
|
153
|
+
//#endregion
|
|
154
|
+
export { fromSymbolFont, symbolGeometryOf, symbolOutline };
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { PathBuilder } from "../vector.js";
|
|
2
2
|
import { cloneDc, colorRef, newDeviceContext } from "./picture.js";
|
|
3
|
+
import { cropDib, readDib } from "./dib.js";
|
|
4
|
+
import { makeBlitter } from "./blit.js";
|
|
5
|
+
import { fromSymbolFont, symbolGeometryOf, symbolOutline } from "./symbol-fonts.js";
|
|
3
6
|
import { ellipseSegments } from "./emf.js";
|
|
4
7
|
//#region src/core/metafile/wmf.ts
|
|
5
8
|
var PLACEABLE_KEY = 2596720087;
|
|
@@ -13,9 +16,6 @@ function isWmf(bytes) {
|
|
|
13
16
|
return (type === 1 || type === 2) && headerWords === 9;
|
|
14
17
|
}
|
|
15
18
|
var RECORD_NAMES = new Map([
|
|
16
|
-
[2368, "bitmap"],
|
|
17
|
-
[2881, "bitmap"],
|
|
18
|
-
[3907, "bitmap"],
|
|
19
19
|
[2338, "pie"],
|
|
20
20
|
[2096, "chord"],
|
|
21
21
|
[2071, "arc"],
|
|
@@ -60,6 +60,16 @@ function readWmf(bytes) {
|
|
|
60
60
|
cx: 0,
|
|
61
61
|
cy: 0
|
|
62
62
|
};
|
|
63
|
+
let origin;
|
|
64
|
+
const emit = (prim) => {
|
|
65
|
+
origin ??= {
|
|
66
|
+
x: win.x,
|
|
67
|
+
y: win.y
|
|
68
|
+
};
|
|
69
|
+
const dx = origin.x - win.x;
|
|
70
|
+
const dy = origin.y - win.y;
|
|
71
|
+
prims.push(dx === 0 && dy === 0 ? prim : shiftPrim(prim, dx, dy));
|
|
72
|
+
};
|
|
63
73
|
const strokeOf = () => {
|
|
64
74
|
if (dc.pen.style === "none") return void 0;
|
|
65
75
|
const w = Math.max(1, dc.pen.widthLu);
|
|
@@ -78,7 +88,7 @@ function readWmf(bytes) {
|
|
|
78
88
|
const st = stroke ? strokeOf() : void 0;
|
|
79
89
|
const fillHex = fill && !dc.brush.hollow ? dc.brush.colorHex : void 0;
|
|
80
90
|
if (fillHex === void 0 && !st) return;
|
|
81
|
-
|
|
91
|
+
emit({
|
|
82
92
|
kind: "path",
|
|
83
93
|
paths: [path],
|
|
84
94
|
...fillHex !== void 0 ? { fillColorHex: fillHex } : {},
|
|
@@ -86,6 +96,27 @@ function readWmf(bytes) {
|
|
|
86
96
|
});
|
|
87
97
|
};
|
|
88
98
|
const rectSegments = (l, t, r, b) => new PathBuilder().moveTo(l, t).lineTo(r, t).lineTo(r, b).lineTo(l, b).close().build().segments;
|
|
99
|
+
const blitter = makeBlitter(emit);
|
|
100
|
+
/**
|
|
101
|
+
* §2.3.1 — one blit record: the packed bitmap the record ends with, into the
|
|
102
|
+
* destination rectangle its fields name. A WMF's coordinates are its own
|
|
103
|
+
* logical units, which is the frame the primitives are already in.
|
|
104
|
+
*/
|
|
105
|
+
const blit = (o) => {
|
|
106
|
+
const dib = readDib(bytes, off + o.dibAt);
|
|
107
|
+
if (!dib) {
|
|
108
|
+
skipped.add("bitmap");
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const s = o.src;
|
|
112
|
+
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;
|
|
113
|
+
blitter.blit(part, {
|
|
114
|
+
x: Math.min(o.dest.x, o.dest.x + o.dest.w),
|
|
115
|
+
y: Math.min(o.dest.y, o.dest.y + o.dest.h),
|
|
116
|
+
width: Math.abs(o.dest.w),
|
|
117
|
+
height: Math.abs(o.dest.h)
|
|
118
|
+
}, o.rop);
|
|
119
|
+
};
|
|
89
120
|
let off = placeable ? 22 : 0;
|
|
90
121
|
off += 18;
|
|
91
122
|
let guard = 0;
|
|
@@ -134,6 +165,12 @@ function readWmf(bytes) {
|
|
|
134
165
|
case 496:
|
|
135
166
|
objects[pu(0)] = void 0;
|
|
136
167
|
break;
|
|
168
|
+
case 247:
|
|
169
|
+
case 322:
|
|
170
|
+
case 505:
|
|
171
|
+
case 1791:
|
|
172
|
+
put({ kind: "other" });
|
|
173
|
+
break;
|
|
137
174
|
case 762:
|
|
138
175
|
put({
|
|
139
176
|
kind: "pen",
|
|
@@ -222,6 +259,79 @@ function readWmf(bytes) {
|
|
|
222
259
|
dc.brush = brush;
|
|
223
260
|
}
|
|
224
261
|
break;
|
|
262
|
+
case 2368:
|
|
263
|
+
case 2881:
|
|
264
|
+
case 3907:
|
|
265
|
+
{
|
|
266
|
+
const rop = p32(0);
|
|
267
|
+
const f = fn === 2368 ? {
|
|
268
|
+
dib: 22,
|
|
269
|
+
srcH: 4,
|
|
270
|
+
srcW: 5,
|
|
271
|
+
ySrc: 2,
|
|
272
|
+
xSrc: 3,
|
|
273
|
+
h: 4,
|
|
274
|
+
w: 5,
|
|
275
|
+
y: 6,
|
|
276
|
+
x: 7
|
|
277
|
+
} : fn === 2881 ? {
|
|
278
|
+
dib: 26,
|
|
279
|
+
srcH: 2,
|
|
280
|
+
srcW: 3,
|
|
281
|
+
ySrc: 4,
|
|
282
|
+
xSrc: 5,
|
|
283
|
+
h: 6,
|
|
284
|
+
w: 7,
|
|
285
|
+
y: 8,
|
|
286
|
+
x: 9
|
|
287
|
+
} : {
|
|
288
|
+
dib: 28,
|
|
289
|
+
srcH: 3,
|
|
290
|
+
srcW: 4,
|
|
291
|
+
ySrc: 5,
|
|
292
|
+
xSrc: 6,
|
|
293
|
+
h: 7,
|
|
294
|
+
w: 8,
|
|
295
|
+
y: 9,
|
|
296
|
+
x: 10
|
|
297
|
+
};
|
|
298
|
+
if (f.dib + 12 > size * 2) {
|
|
299
|
+
const hex = rop === 66 ? "000000" : rop === 16711778 ? "FFFFFF" : void 0;
|
|
300
|
+
const brush = dc.brush;
|
|
301
|
+
if (hex !== void 0) dc.brush = {
|
|
302
|
+
kind: "brush",
|
|
303
|
+
colorHex: hex,
|
|
304
|
+
hollow: false
|
|
305
|
+
};
|
|
306
|
+
const shift = fn === 2368 ? 1 : 0;
|
|
307
|
+
const [h, w, y, x] = [
|
|
308
|
+
p(f.h + shift),
|
|
309
|
+
p(f.w + shift),
|
|
310
|
+
p(f.y + shift),
|
|
311
|
+
p(f.x + shift)
|
|
312
|
+
];
|
|
313
|
+
paint(rectSegments(x, y, x + w, y + h), true, false);
|
|
314
|
+
dc.brush = brush;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
blit({
|
|
318
|
+
dibAt: f.dib,
|
|
319
|
+
dest: {
|
|
320
|
+
x: p(f.x),
|
|
321
|
+
y: p(f.y),
|
|
322
|
+
w: p(f.w),
|
|
323
|
+
h: p(f.h)
|
|
324
|
+
},
|
|
325
|
+
src: {
|
|
326
|
+
x: p(f.xSrc),
|
|
327
|
+
y: p(f.ySrc),
|
|
328
|
+
w: p(f.srcW),
|
|
329
|
+
h: p(f.srcH)
|
|
330
|
+
},
|
|
331
|
+
rop
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
225
335
|
case 804:
|
|
226
336
|
case 805:
|
|
227
337
|
{
|
|
@@ -250,7 +360,7 @@ function readWmf(bytes) {
|
|
|
250
360
|
const count = pu(0);
|
|
251
361
|
const text = readString(bytes, off + 8, count, false);
|
|
252
362
|
const words = count + 1 >> 1;
|
|
253
|
-
pushText(
|
|
363
|
+
pushText(emit, dc, text, p(1 + words + 1), p(1 + words));
|
|
254
364
|
}
|
|
255
365
|
break;
|
|
256
366
|
case 2610:
|
|
@@ -260,7 +370,7 @@ function readWmf(bytes) {
|
|
|
260
370
|
const count = pu(2);
|
|
261
371
|
const hasRect = (pu(3) & 6) !== 0;
|
|
262
372
|
const text = readString(bytes, off + 6 + (4 + (hasRect ? 4 : 0)) * 2, count, false);
|
|
263
|
-
pushText(
|
|
373
|
+
pushText(emit, dc, text, x, y);
|
|
264
374
|
}
|
|
265
375
|
break;
|
|
266
376
|
default:
|
|
@@ -287,16 +397,22 @@ function readWmf(bytes) {
|
|
|
287
397
|
skipped: [...skipped]
|
|
288
398
|
};
|
|
289
399
|
}
|
|
290
|
-
function pushText(
|
|
400
|
+
function pushText(emit, dc, text, x, y) {
|
|
291
401
|
if (text.trim() === "") return;
|
|
292
|
-
|
|
402
|
+
const em = Math.abs(dc.font?.heightLu ?? 12);
|
|
403
|
+
const drawn = symbolPrims(text, dc, x, y, em);
|
|
404
|
+
if (drawn) {
|
|
405
|
+
for (const prim of drawn) emit(prim);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
emit({
|
|
293
409
|
kind: "text",
|
|
294
|
-
text,
|
|
410
|
+
text: fromSymbolFont(text, dc.font?.family),
|
|
295
411
|
x,
|
|
296
412
|
y,
|
|
297
413
|
alignH: dc.alignH,
|
|
298
414
|
alignBaseline: dc.alignBaseline,
|
|
299
|
-
sizeLu:
|
|
415
|
+
sizeLu: em,
|
|
300
416
|
colorHex: dc.textColorHex,
|
|
301
417
|
...dc.font?.family ? { fontFamily: dc.font.family } : {},
|
|
302
418
|
...dc.font?.bold ? { bold: true } : {},
|
|
@@ -304,6 +420,37 @@ function pushText(prims, dc, text, x, y) {
|
|
|
304
420
|
...dc.font?.escapement ? { escapement: dc.font.escapement } : {}
|
|
305
421
|
});
|
|
306
422
|
}
|
|
423
|
+
function shiftPrim(prim, dx, dy) {
|
|
424
|
+
if (prim.kind === "text") return {
|
|
425
|
+
...prim,
|
|
426
|
+
x: prim.x + dx,
|
|
427
|
+
y: prim.y + dy
|
|
428
|
+
};
|
|
429
|
+
if (prim.kind === "image") return {
|
|
430
|
+
...prim,
|
|
431
|
+
x: prim.x + dx,
|
|
432
|
+
y: prim.y + dy
|
|
433
|
+
};
|
|
434
|
+
return {
|
|
435
|
+
...prim,
|
|
436
|
+
paths: prim.paths.map((path) => ({
|
|
437
|
+
...path,
|
|
438
|
+
segments: path.segments.map((sg) => "x" in sg ? {
|
|
439
|
+
...sg,
|
|
440
|
+
x: sg.x + dx,
|
|
441
|
+
y: sg.y + dy,
|
|
442
|
+
..."x1" in sg ? {
|
|
443
|
+
x1: sg.x1 + dx,
|
|
444
|
+
y1: sg.y1 + dy
|
|
445
|
+
} : {},
|
|
446
|
+
..."x2" in sg ? {
|
|
447
|
+
x2: sg.x2 + dx,
|
|
448
|
+
y2: sg.y2 + dy
|
|
449
|
+
} : {}
|
|
450
|
+
} : sg)
|
|
451
|
+
}))
|
|
452
|
+
};
|
|
453
|
+
}
|
|
307
454
|
function penStyle(style) {
|
|
308
455
|
switch (style & 15) {
|
|
309
456
|
case 1: return "dash";
|
|
@@ -367,5 +514,31 @@ function polySegments(pts, closed) {
|
|
|
367
514
|
if (closed) segs.push({ op: "close" });
|
|
368
515
|
return segs;
|
|
369
516
|
}
|
|
517
|
+
/**
|
|
518
|
+
* The symbols a text record draws, as filled outlines, or `undefined` when the
|
|
519
|
+
* string is not one the shapes cover.
|
|
520
|
+
*
|
|
521
|
+
* Both fonts advance one em per symbol and fill that em, sitting from 0.2 em
|
|
522
|
+
* below the baseline to 0.8 em above it — measured off Webdings itself.
|
|
523
|
+
*
|
|
524
|
+
* @param text The string as stored.
|
|
525
|
+
* @param dc The device context (font, colour, alignment).
|
|
526
|
+
* @param x The reference point's x, in logical units.
|
|
527
|
+
* @param y Its y — the text's top unless the context says baseline.
|
|
528
|
+
* @param em The font's height in logical units.
|
|
529
|
+
* @returns One filled path per character, or `undefined`.
|
|
530
|
+
*/
|
|
531
|
+
function symbolPrims(text, dc, x, y, em) {
|
|
532
|
+
const shapes = symbolGeometryOf(text, dc.font?.family);
|
|
533
|
+
if (!shapes) return void 0;
|
|
534
|
+
const width = em * shapes.length;
|
|
535
|
+
const left = dc.alignH === "center" ? x - width / 2 : dc.alignH === "right" ? x - width : x;
|
|
536
|
+
const top = dc.alignBaseline ? y - em * .8 : y;
|
|
537
|
+
return shapes.map((shape, i) => ({
|
|
538
|
+
kind: "path",
|
|
539
|
+
paths: [symbolOutline(shape, left + i * em, top, em)],
|
|
540
|
+
fillColorHex: dc.textColorHex
|
|
541
|
+
}));
|
|
542
|
+
}
|
|
370
543
|
//#endregion
|
|
371
544
|
export { isWmf, readWmf };
|
|
@@ -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;
|