reamkit 1.21.0 → 1.22.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/document-model/types.d.ts +60 -0
- 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 +27 -3
- package/dist/esm/core/drawingml/colors.js +30 -6
- package/dist/esm/core/drawingml/preset-geometry.js +236 -0
- package/dist/esm/core/metafile/emf.js +2 -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 +35 -2
- package/dist/esm/core/vector.d.ts +5 -0
- package/dist/esm/excel/sheet-shape-parser.js +1 -12
- 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 +38 -0
- package/dist/esm/layout/page-doc.js +34 -18
- package/dist/esm/layout/styled-layout.js +174 -49
- 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 +614 -444
- 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 +69 -5
- package/dist/esm/pptx/placeholder-cascade.js +162 -25
- package/dist/esm/pptx/pptx-reader.js +247 -39
- package/dist/esm/pptx/slide-parser.d.ts +72 -10
- package/dist/esm/pptx/slide-parser.js +310 -82
- package/dist/esm/pptx/sp-helpers.js +19 -4
- package/dist/esm/pptx/table-style.d.ts +56 -0
- package/dist/esm/pptx/table-style.js +161 -0
- package/dist/esm/svg/svg-writer.js +53 -5
- package/dist/esm/word/docx-reader.js +2 -2
- package/dist/esm/word/drawing-parser.d.ts +34 -0
- package/dist/esm/word/drawing-parser.js +159 -13
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PathBuilder } from "../vector.js";
|
|
2
2
|
import { applyTransform, cloneDc, colorRef, newDeviceContext } from "./picture.js";
|
|
3
|
+
import { fromSymbolFont } from "./symbol-fonts.js";
|
|
3
4
|
//#region src/core/metafile/emf.ts
|
|
4
5
|
/** Whether the bytes open with an EMF header (MS-EMF §2.3.4.2: type 1 + " EMF"). */
|
|
5
6
|
function isEmf(bytes) {
|
|
@@ -371,7 +372,7 @@ function readEmf(bytes) {
|
|
|
371
372
|
const font = dc.font;
|
|
372
373
|
prims.push({
|
|
373
374
|
kind: "text",
|
|
374
|
-
text,
|
|
375
|
+
text: fromSymbolFont(text, font?.family),
|
|
375
376
|
x: p.x,
|
|
376
377
|
y: p.y,
|
|
377
378
|
alignH: dc.alignH,
|
|
@@ -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,6 @@
|
|
|
1
1
|
import { PathBuilder } from "../vector.js";
|
|
2
2
|
import { cloneDc, colorRef, newDeviceContext } from "./picture.js";
|
|
3
|
+
import { fromSymbolFont, symbolGeometryOf, symbolOutline } from "./symbol-fonts.js";
|
|
3
4
|
import { ellipseSegments } from "./emf.js";
|
|
4
5
|
//#region src/core/metafile/wmf.ts
|
|
5
6
|
var PLACEABLE_KEY = 2596720087;
|
|
@@ -289,14 +290,20 @@ function readWmf(bytes) {
|
|
|
289
290
|
}
|
|
290
291
|
function pushText(prims, dc, text, x, y) {
|
|
291
292
|
if (text.trim() === "") return;
|
|
293
|
+
const em = Math.abs(dc.font?.heightLu ?? 12);
|
|
294
|
+
const drawn = symbolPrims(text, dc, x, y, em);
|
|
295
|
+
if (drawn) {
|
|
296
|
+
prims.push(...drawn);
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
292
299
|
prims.push({
|
|
293
300
|
kind: "text",
|
|
294
|
-
text,
|
|
301
|
+
text: fromSymbolFont(text, dc.font?.family),
|
|
295
302
|
x,
|
|
296
303
|
y,
|
|
297
304
|
alignH: dc.alignH,
|
|
298
305
|
alignBaseline: dc.alignBaseline,
|
|
299
|
-
sizeLu:
|
|
306
|
+
sizeLu: em,
|
|
300
307
|
colorHex: dc.textColorHex,
|
|
301
308
|
...dc.font?.family ? { fontFamily: dc.font.family } : {},
|
|
302
309
|
...dc.font?.bold ? { bold: true } : {},
|
|
@@ -367,5 +374,31 @@ function polySegments(pts, closed) {
|
|
|
367
374
|
if (closed) segs.push({ op: "close" });
|
|
368
375
|
return segs;
|
|
369
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* The symbols a text record draws, as filled outlines, or `undefined` when the
|
|
379
|
+
* string is not one the shapes cover.
|
|
380
|
+
*
|
|
381
|
+
* Both fonts advance one em per symbol and fill that em, sitting from 0.2 em
|
|
382
|
+
* below the baseline to 0.8 em above it — measured off Webdings itself.
|
|
383
|
+
*
|
|
384
|
+
* @param text The string as stored.
|
|
385
|
+
* @param dc The device context (font, colour, alignment).
|
|
386
|
+
* @param x The reference point's x, in logical units.
|
|
387
|
+
* @param y Its y — the text's top unless the context says baseline.
|
|
388
|
+
* @param em The font's height in logical units.
|
|
389
|
+
* @returns One filled path per character, or `undefined`.
|
|
390
|
+
*/
|
|
391
|
+
function symbolPrims(text, dc, x, y, em) {
|
|
392
|
+
const shapes = symbolGeometryOf(text, dc.font?.family);
|
|
393
|
+
if (!shapes) return void 0;
|
|
394
|
+
const width = em * shapes.length;
|
|
395
|
+
const left = dc.alignH === "center" ? x - width / 2 : dc.alignH === "right" ? x - width : x;
|
|
396
|
+
const top = dc.alignBaseline ? y - em * .8 : y;
|
|
397
|
+
return shapes.map((shape, i) => ({
|
|
398
|
+
kind: "path",
|
|
399
|
+
paths: [symbolOutline(shape, left + i * em, top, em)],
|
|
400
|
+
fillColorHex: dc.textColorHex
|
|
401
|
+
}));
|
|
402
|
+
}
|
|
370
403
|
//#endregion
|
|
371
404
|
export { isWmf, readWmf };
|
|
@@ -49,6 +49,11 @@ export interface GradientStop {
|
|
|
49
49
|
readonly offset: number;
|
|
50
50
|
/** Stop colour as 6-hex, no leading `#`. */
|
|
51
51
|
readonly colorHex: string;
|
|
52
|
+
/**
|
|
53
|
+
* §20.1.2.3.1 `a:alpha` — how opaque THIS stop is, `0..1`; absent is opaque.
|
|
54
|
+
* The colour beside it is the stop's own, not composited over the paper.
|
|
55
|
+
*/
|
|
56
|
+
readonly alpha?: number;
|
|
52
57
|
}
|
|
53
58
|
/**
|
|
54
59
|
* A gradient fill — the format-agnostic vocabulary shared by the shape model
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { emuToPt, pt } from "../core/ir/units.js";
|
|
2
2
|
import { poAttr, poChildren, poFirstChild, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
|
|
3
|
-
import {
|
|
3
|
+
import { placeholderColors, resolveColorNode } from "../core/drawingml/colors.js";
|
|
4
4
|
import { parseFill, parseLine, parseShadow, parseXfrm, shadowFromOuterShdw } from "../word/drawing-parser.js";
|
|
5
5
|
import { parseGeometry, parseTxBody } from "../pptx/slide-parser.js";
|
|
6
6
|
import { parseXml } from "../pptx/pptx-reader.js";
|
|
@@ -387,17 +387,6 @@ function styleFill(sp, ns, colors, themeFillStyles) {
|
|
|
387
387
|
} : themed;
|
|
388
388
|
}
|
|
389
389
|
/**
|
|
390
|
-
* §20.1.4.2.10 — inside a theme's style list, `phClr` stands for "the colour the
|
|
391
|
-
* reference names". Every other colour resolves as it always did.
|
|
392
|
-
*
|
|
393
|
-
* @param colors The workbook's own resolver.
|
|
394
|
-
* @param phHex The colour the `a:fillRef` / `a:lnRef` carries.
|
|
395
|
-
* @returns A resolver that answers `phClr` with that colour, transforms and all.
|
|
396
|
-
*/
|
|
397
|
-
function placeholderColors(colors, phHex) {
|
|
398
|
-
return (raw) => "scheme" in raw && raw.scheme === "phClr" ? applyColorMods(phHex, raw.mods ?? []) : colors(raw);
|
|
399
|
-
}
|
|
400
|
-
/**
|
|
401
390
|
* The shadow `<xdr:style><a:effectRef>` names, if it names one.
|
|
402
391
|
*
|
|
403
392
|
* §20.1.4.2.8, the same mechanism as the fill and the outline beside it: a
|
|
@@ -29,7 +29,7 @@ export declare function readXlsx(xlsx: Uint8Array, options?: ProjectSheetOptions
|
|
|
29
29
|
*/
|
|
30
30
|
export declare function readXlsxToSheetDoc(xlsx: Uint8Array): SheetDoc;
|
|
31
31
|
/**
|
|
32
|
-
* The OOXML `.xlsx` {@link DocumentReader}: sniffs the OPC ZIP for
|
|
32
|
+
* The OOXML `.xlsx` {@link DocumentReader}: sniffs the OPC ZIP's directory for
|
|
33
33
|
* `xl/workbook.xml` and reads it into a {@link SheetDoc}. The reader's native
|
|
34
34
|
* tree is the SheetDoc; the facade/Ream project it to a {@link FlowDoc} for
|
|
35
35
|
* rendering (E-SHEET SB1).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ResourceStore } from "../core/ir/resources.js";
|
|
2
2
|
import { FEATURES } from "../core/ir/features.js";
|
|
3
3
|
import { detectImageFormat } from "../core/images.js";
|
|
4
|
-
import { bytesInclude,
|
|
4
|
+
import { bytesInclude, packageHasPart } from "../core/bytes.js";
|
|
5
5
|
import { DEFAULT_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
|
|
6
6
|
import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
|
|
7
7
|
import { parseTheme, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
|
|
@@ -651,7 +651,7 @@ function lighten(hex, amount) {
|
|
|
651
651
|
return `${hx(ch(16))}${hx(ch(8))}${hx(ch(0))}`;
|
|
652
652
|
}
|
|
653
653
|
/**
|
|
654
|
-
* The OOXML `.xlsx` {@link DocumentReader}: sniffs the OPC ZIP for
|
|
654
|
+
* The OOXML `.xlsx` {@link DocumentReader}: sniffs the OPC ZIP's directory for
|
|
655
655
|
* `xl/workbook.xml` and reads it into a {@link SheetDoc}. The reader's native
|
|
656
656
|
* tree is the SheetDoc; the facade/Ream project it to a {@link FlowDoc} for
|
|
657
657
|
* rendering (E-SHEET SB1).
|
|
@@ -660,7 +660,7 @@ var xlsxReader = {
|
|
|
660
660
|
id: "xlsx",
|
|
661
661
|
produces: "sheet",
|
|
662
662
|
supports: new Set([FEATURES.text, FEATURES.tables]),
|
|
663
|
-
sniff: (bytes) => bytes[0] === 80 && bytes[1] === 75 &&
|
|
663
|
+
sniff: (bytes) => bytes[0] === 80 && bytes[1] === 75 && packageHasPart(bytes, "xl/workbook.xml"),
|
|
664
664
|
read: (bytes) => ({
|
|
665
665
|
doc: readXlsxToSheetDoc(bytes),
|
|
666
666
|
losses: []
|
|
@@ -242,6 +242,24 @@ export interface PageItemBase {
|
|
|
242
242
|
* is treated as an artifact. Ignored when not tagging.
|
|
243
243
|
*/
|
|
244
244
|
readonly structId?: number;
|
|
245
|
+
/**
|
|
246
|
+
* §20.4.2.3 `@behindDoc` — the item is BEHIND the page's content: a
|
|
247
|
+
* watermark, a slide's backdrop. Such items paint before everything else, in
|
|
248
|
+
* their own order. Without that they rode the ordinary passes, where every
|
|
249
|
+
* shape paints after every image — so a slide's white backdrop covered the
|
|
250
|
+
* photograph the slide is made of (corpus: tdf156808, tdf157635, tdf156856).
|
|
251
|
+
*/
|
|
252
|
+
readonly behind?: boolean;
|
|
253
|
+
/**
|
|
254
|
+
* The picture this item belongs to, when it is part of one. A metafile is a
|
|
255
|
+
* list of drawing orders, and text among them is BOTH over what came before
|
|
256
|
+
* and under what comes after: an embedded diagram writes a label, lays a
|
|
257
|
+
* panel over it and writes the label again, offset, as its own drop shadow.
|
|
258
|
+
* Painted in the ordinary passes — every shape, then every line — the buried
|
|
259
|
+
* copy would show through the panel. Items sharing this id are held out of
|
|
260
|
+
* those passes and painted together, in list order.
|
|
261
|
+
*/
|
|
262
|
+
readonly pictureId?: number;
|
|
245
263
|
/**
|
|
246
264
|
* Tagged PDF: explicitly mark this item as a pagination artifact (running
|
|
247
265
|
* header/footer, §14.8.2.2.2). Distinguishes header/footer text from
|
|
@@ -314,6 +332,19 @@ export interface ImageItem extends PageItemBase {
|
|
|
314
332
|
readonly gain: number;
|
|
315
333
|
readonly black: number;
|
|
316
334
|
};
|
|
335
|
+
/**
|
|
336
|
+
* §20.1.8.4 `a:alphaModFix` — how opaque the picture is drawn, 0…1. A slide
|
|
337
|
+
* backed by a photograph at 70 % shows a pale wash of it, not the photograph.
|
|
338
|
+
*/
|
|
339
|
+
readonly alpha?: number;
|
|
340
|
+
/**
|
|
341
|
+
* §20.1.8.23 `a:duotone` — the picture painted between two colours instead of
|
|
342
|
+
* its own: its dark end is the first, its light end the second.
|
|
343
|
+
*/
|
|
344
|
+
readonly duotone?: {
|
|
345
|
+
readonly shadowHex: string;
|
|
346
|
+
readonly highlightHex: string;
|
|
347
|
+
};
|
|
317
348
|
/** §20.1.7.6 — degrees clockwise about the box's centre. */
|
|
318
349
|
readonly rotationDeg?: number;
|
|
319
350
|
/** §20.1.7.6 — the picture drawn mirrored in its box. */
|
|
@@ -340,11 +371,18 @@ export interface ShapeItem extends PageItemBase {
|
|
|
340
371
|
/** A positioned item on a laid-out page: a text line, border, fill, image, or vector shape. */
|
|
341
372
|
export type PageItem = TextLineItem | BorderItem | FillItem | ImageItem | ShapeItem;
|
|
342
373
|
export interface PagePaintPlan {
|
|
374
|
+
/** What sits behind the page's content, in its own order — painted first. */
|
|
375
|
+
readonly behind: ReadonlyArray<PageItem>;
|
|
343
376
|
readonly fills: ReadonlyArray<FillItem>;
|
|
344
377
|
readonly images: ReadonlyArray<ImageItem>;
|
|
345
378
|
readonly borders: ReadonlyArray<BorderItem>;
|
|
346
379
|
readonly shapes: ReadonlyArray<ShapeItem>;
|
|
347
380
|
readonly lines: ReadonlyArray<TextLineItem>;
|
|
381
|
+
/**
|
|
382
|
+
* Pictures, each as its own list in the order the picture draws — one entry
|
|
383
|
+
* per {@link PageItemBase.pictureId}. They paint where the shape pass does.
|
|
384
|
+
*/
|
|
385
|
+
readonly pictures: ReadonlyArray<ReadonlyArray<PageItem>>;
|
|
348
386
|
}
|
|
349
387
|
export declare function paintPlan(commands: ReadonlyArray<PageItem>): PagePaintPlan;
|
|
350
388
|
export interface LaidOutDocument {
|
|
@@ -5,30 +5,46 @@ function paintPlan(commands) {
|
|
|
5
5
|
const borders = [];
|
|
6
6
|
const shapes = [];
|
|
7
7
|
const lines = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
8
|
+
const pictures = /* @__PURE__ */ new Map();
|
|
9
|
+
const behind = [];
|
|
10
|
+
for (const c of commands) {
|
|
11
|
+
if (c.behind === true) {
|
|
12
|
+
behind.push(c);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (c.pictureId !== void 0) {
|
|
16
|
+
const group = pictures.get(c.pictureId);
|
|
17
|
+
if (group) group.push(c);
|
|
18
|
+
else pictures.set(c.pictureId, [c]);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
switch (c.type) {
|
|
22
|
+
case "fill":
|
|
23
|
+
fills.push(c);
|
|
24
|
+
break;
|
|
25
|
+
case "image":
|
|
26
|
+
images.push(c);
|
|
27
|
+
break;
|
|
28
|
+
case "border":
|
|
29
|
+
borders.push(c);
|
|
30
|
+
break;
|
|
31
|
+
case "shape":
|
|
32
|
+
shapes.push(c);
|
|
33
|
+
break;
|
|
34
|
+
case "line":
|
|
35
|
+
lines.push(c);
|
|
36
|
+
break;
|
|
37
|
+
default: assertNeverPageItem(c);
|
|
38
|
+
}
|
|
25
39
|
}
|
|
26
40
|
return {
|
|
41
|
+
behind,
|
|
27
42
|
fills,
|
|
28
43
|
images,
|
|
29
44
|
borders,
|
|
30
45
|
shapes,
|
|
31
|
-
lines
|
|
46
|
+
lines,
|
|
47
|
+
pictures: [...pictures.values()]
|
|
32
48
|
};
|
|
33
49
|
}
|
|
34
50
|
function assertNeverPageItem(item) {
|