reamkit 1.31.0 → 1.32.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/README.md +10 -0
- package/dist/esm/core/bidi/index.d.ts +10 -0
- package/dist/esm/core/bidi/index.js +18 -2
- package/dist/esm/core/converter/facade.js +10 -5
- package/dist/esm/core/converter/project.js +1 -0
- package/dist/esm/core/converter/ream.js +17 -6
- package/dist/esm/core/converter/sheet-images.d.ts +17 -0
- package/dist/esm/core/converter/sheet-images.js +33 -0
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +112 -0
- package/dist/esm/core/drawingml/chart-geometry.d.ts +21 -8
- package/dist/esm/core/drawingml/chart-geometry.js +198 -108
- package/dist/esm/core/drawingml/chart-parser.js +73 -2
- package/dist/esm/core/drawingml/colors.d.ts +6 -0
- package/dist/esm/core/drawingml/colors.js +23 -3
- package/dist/esm/core/drawingml/shape-render.d.ts +3 -1
- package/dist/esm/core/drawingml/shape-render.js +4 -2
- package/dist/esm/core/font/measure.d.ts +9 -0
- package/dist/esm/core/font/measure.js +9 -1
- package/dist/esm/core/fonts/families.js +4 -2
- package/dist/esm/core/fonts/scripts.js +4 -2
- package/dist/esm/core/ir/flow.d.ts +6 -0
- package/dist/esm/core/ir/sheet.d.ts +43 -0
- package/dist/esm/core/number-format.js +16 -11
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +96 -0
- package/dist/esm/core/style-cascade/resolver.js +4 -2
- package/dist/esm/excel/column-bands.d.ts +39 -6
- package/dist/esm/excel/column-bands.js +41 -17
- package/dist/esm/excel/comments-parser.js +19 -0
- package/dist/esm/excel/conditional-format.d.ts +7 -3
- package/dist/esm/excel/conditional-format.js +77 -39
- package/dist/esm/excel/formula/context.d.ts +18 -0
- package/dist/esm/excel/formula/eval.js +51 -0
- package/dist/esm/excel/formula/index.d.ts +2 -2
- package/dist/esm/excel/formula/lexer.d.ts +1 -1
- package/dist/esm/excel/formula/lexer.js +41 -0
- package/dist/esm/excel/formula/parser.d.ts +25 -0
- package/dist/esm/excel/formula/parser.js +95 -0
- package/dist/esm/excel/print-model.d.ts +38 -1
- package/dist/esm/excel/print-model.js +522 -80
- package/dist/esm/excel/shared-strings-parser.d.ts +9 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -1
- package/dist/esm/excel/sheet-drawing.d.ts +38 -2
- package/dist/esm/excel/sheet-drawing.js +47 -13
- package/dist/esm/excel/sheet-shape-parser.d.ts +6 -2
- package/dist/esm/excel/sheet-shape-parser.js +18 -6
- package/dist/esm/excel/sheet-to-flow.d.ts +17 -0
- package/dist/esm/excel/sheet-to-flow.js +434 -47
- package/dist/esm/excel/styles-parser.d.ts +9 -0
- package/dist/esm/excel/styles-parser.js +80 -26
- package/dist/esm/excel/table-parser.js +5 -0
- package/dist/esm/excel/table-style-presets.d.ts +26 -0
- package/dist/esm/excel/table-style-presets.js +1555 -0
- package/dist/esm/excel/table-style.d.ts +13 -0
- package/dist/esm/excel/table-style.js +75 -0
- package/dist/esm/excel/tint.d.ts +10 -0
- package/dist/esm/excel/tint.js +75 -0
- package/dist/esm/excel/vml-drawing.d.ts +41 -3
- package/dist/esm/excel/vml-drawing.js +143 -10
- package/dist/esm/excel/worksheet-parser.js +89 -15
- package/dist/esm/excel/xls/biff-reader.js +10 -2
- package/dist/esm/excel/xlsx-reader.js +195 -14
- package/dist/esm/excel/xlsx-writer.js +8 -7
- package/dist/esm/html/html-writer.js +202 -20
- package/dist/esm/layout/fit-pages.d.ts +11 -0
- package/dist/esm/layout/fit-pages.js +86 -0
- package/dist/esm/layout/line-paint.d.ts +58 -0
- package/dist/esm/layout/line-paint.js +107 -0
- package/dist/esm/layout/page-doc.d.ts +51 -0
- package/dist/esm/layout/page-doc.js +141 -1
- package/dist/esm/layout/styled-layout.d.ts +7 -0
- package/dist/esm/layout/styled-layout.js +274 -51
- package/dist/esm/layout/turned-section.js +14 -2
- package/dist/esm/markdown/markdown-writer.js +17 -6
- package/dist/esm/pdf/styled-page-emitter.js +49 -71
- package/dist/esm/pdf/styled-page-renderer.js +1 -1
- package/dist/esm/pdf-reader/font.js +3 -3
- package/dist/esm/svg/svg-text.d.ts +58 -0
- package/dist/esm/svg/svg-text.js +322 -0
- package/dist/esm/svg/svg-writer.js +135 -71
- package/dist/esm/word/docx-writer.js +11 -2
- package/package.json +5 -1
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { pageLayers, paintPlan } from "../layout/page-doc.js";
|
|
1
2
|
import { FEATURES } from "../core/ir/features.js";
|
|
2
3
|
import { svgPathData } from "../core/vector.js";
|
|
3
4
|
import { gradientSvgDef } from "../core/drawingml/shape-render.js";
|
|
4
|
-
import {
|
|
5
|
+
import { BORDER_DASHES, washVeil } from "../layout/line-paint.js";
|
|
5
6
|
import { toBase64 } from "../core/bytes.js";
|
|
7
|
+
import { SvgGlyphs, emitSvgLine } from "./svg-text.js";
|
|
6
8
|
//#region src/svg/svg-writer.ts
|
|
7
9
|
var PAGE_GAP = 12;
|
|
8
10
|
/**
|
|
@@ -23,17 +25,25 @@ function writeSvg(laid, opts = {}) {
|
|
|
23
25
|
const width = Math.max(1, ...laid.pages.map((p) => p.width));
|
|
24
26
|
const height = laid.pages.reduce((s, p) => s + p.height, 0) + gap * Math.max(0, laid.pages.length - 1);
|
|
25
27
|
const parts = [];
|
|
26
|
-
|
|
28
|
+
const ids = { n: 0 };
|
|
29
|
+
const glyphs = new SvgGlyphs();
|
|
30
|
+
const ctx = {
|
|
31
|
+
glyphs,
|
|
32
|
+
ids,
|
|
33
|
+
laid,
|
|
34
|
+
image: (out, placed) => emitPlaced(out, placed, laid, ids),
|
|
35
|
+
shape: (out, shape) => emitShape(out, shape, ids)
|
|
36
|
+
};
|
|
27
37
|
let yOffset = 0;
|
|
28
|
-
const idc = { n: 0 };
|
|
29
38
|
laid.pages.forEach((page, i) => {
|
|
30
39
|
parts.push(`<g transform="translate(0 ${fmt(yOffset)})" data-page="${i + 1}">`);
|
|
31
40
|
parts.push(`<rect x="0" y="0" width="${fmt(page.width)}" height="${fmt(page.height)}" fill="#ffffff" stroke="#cccccc"/>`);
|
|
32
|
-
emitPage(parts, page,
|
|
41
|
+
emitPage(parts, page, ctx);
|
|
33
42
|
parts.push("</g>");
|
|
34
43
|
yOffset += page.height + gap;
|
|
35
44
|
});
|
|
36
45
|
parts.push("</svg>");
|
|
46
|
+
parts.unshift(`<svg xmlns="http://www.w3.org/2000/svg" width="${fmt(width)}" height="${fmt(height)}" viewBox="0 0 ${fmt(width)} ${fmt(height)}">`, glyphs.defsXml());
|
|
37
47
|
return {
|
|
38
48
|
bytes: new TextEncoder().encode(parts.join("\n")),
|
|
39
49
|
losses
|
|
@@ -54,11 +64,24 @@ var svgWriter = {
|
|
|
54
64
|
]),
|
|
55
65
|
write: (doc, opts) => writeSvg(doc, opts ?? {})
|
|
56
66
|
};
|
|
57
|
-
function emitPage(out, page,
|
|
58
|
-
const
|
|
59
|
-
|
|
67
|
+
function emitPage(out, page, ctx) {
|
|
68
|
+
for (const layer of pageLayers(page.commands)) {
|
|
69
|
+
const w = layer.window;
|
|
70
|
+
if (!w) {
|
|
71
|
+
emitLayer(out, layer.items, ctx);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const id = `win${String(ctx.ids.n++)}`;
|
|
75
|
+
out.push(`<clipPath id="${id}"><rect x="${fmt(w.x)}" y="${fmt(w.y)}" width="${fmt(w.width)}" height="${fmt(w.height)}"/></clipPath>`, `<g clip-path="url(#${id})">`);
|
|
76
|
+
emitLayer(out, layer.items, ctx);
|
|
77
|
+
out.push("</g>");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function emitLayer(out, commands, ctx) {
|
|
81
|
+
const plan = paintPlan(commands);
|
|
82
|
+
for (const item of plan.behind) emitPageItem(out, item, ctx);
|
|
60
83
|
for (const f of plan.fills) out.push(`<rect x="${fmt(f.x)}" y="${fmt(f.y)}" width="${fmt(f.width)}" height="${fmt(f.height)}" fill="#${f.fillColorHex}"/>`);
|
|
61
|
-
for (const img of plan.images) emitImage(out, img,
|
|
84
|
+
for (const img of plan.images) emitImage(out, img, ctx);
|
|
62
85
|
for (const b of plan.borders) {
|
|
63
86
|
const x2 = b.x + b.width;
|
|
64
87
|
const yTop = b.y;
|
|
@@ -84,104 +107,148 @@ function emitPage(out, page, laid, losses, idc) {
|
|
|
84
107
|
x2,
|
|
85
108
|
yBottom
|
|
86
109
|
];
|
|
87
|
-
|
|
110
|
+
const dash = b.borderStyle !== void 0 ? BORDER_DASHES.get(b.borderStyle) : void 0;
|
|
111
|
+
out.push(`<line x1="${fmt(ax)}" y1="${fmt(ay)}" x2="${fmt(bx)}" y2="${fmt(by)}" stroke="#${b.borderColorHex}" stroke-width="${fmt(b.borderSizePt)}"${dash ? ` stroke-dasharray="${dash.map(fmt).join(" ")}"` : ""}/>`);
|
|
88
112
|
}
|
|
89
|
-
for (const sh of plan.shapes) emitShape(out, sh.shape,
|
|
90
|
-
for (const picture of plan.pictures) for (const item of picture) emitPageItem(out, item,
|
|
91
|
-
for (const run of plan.ordered) for (const item of run) emitPageItem(out, item,
|
|
92
|
-
for (const t of plan.lines)
|
|
113
|
+
for (const sh of plan.shapes) emitShape(out, sh.shape, ctx.ids);
|
|
114
|
+
for (const picture of plan.pictures) for (const item of picture) emitPageItem(out, item, ctx);
|
|
115
|
+
for (const run of plan.ordered) for (const item of run) emitPageItem(out, item, ctx);
|
|
116
|
+
for (const t of plan.lines) emitSvgLine(out, t, ctx);
|
|
93
117
|
}
|
|
94
118
|
/**
|
|
95
|
-
* One picture
|
|
96
|
-
* dark end and its light end —
|
|
97
|
-
*
|
|
98
|
-
*
|
|
119
|
+
* One picture item, its placement and its effects: §20.1.8.23 `a:duotone`
|
|
120
|
+
* recolours it between its dark end and its light end — luminance into every
|
|
121
|
+
* channel, then a two-entry transfer table per channel — and a picture FILL
|
|
122
|
+
* (§20.1.8.14) is clipped to the outline of the shape it fills.
|
|
99
123
|
*
|
|
100
124
|
* @param out The SVG fragment sink.
|
|
101
125
|
* @param img The image item.
|
|
102
|
-
* @param
|
|
103
|
-
* @param idc The shared id counter, for the filter's id.
|
|
126
|
+
* @param ctx The document, its id counter, its drawing.
|
|
104
127
|
*/
|
|
105
|
-
function emitImage(out, img,
|
|
106
|
-
|
|
107
|
-
if (!href) return;
|
|
108
|
-
let filter = "";
|
|
128
|
+
function emitImage(out, img, ctx) {
|
|
129
|
+
let filter;
|
|
109
130
|
if (img.duotone) {
|
|
110
|
-
const id = `duo${String(
|
|
131
|
+
const id = `duo${String(ctx.ids.n++)}`;
|
|
111
132
|
const chan = (hex, at) => parseInt(hex.slice(at, at + 2), 16) / 255;
|
|
112
133
|
const table = (at) => `${fmt(chan(img.duotone.shadowHex, at))} ${fmt(chan(img.duotone.highlightHex, at))}`;
|
|
113
134
|
out.push(`<filter id="${id}" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/><feComponentTransfer><feFuncR type="table" tableValues="${table(0)}"/><feFuncG type="table" tableValues="${table(2)}"/><feFuncB type="table" tableValues="${table(4)}"/></feComponentTransfer></filter>`);
|
|
114
|
-
filter =
|
|
135
|
+
filter = id;
|
|
136
|
+
}
|
|
137
|
+
let clipped = false;
|
|
138
|
+
if (img.clip) {
|
|
139
|
+
const id = `pic${String(ctx.ids.n++)}`;
|
|
140
|
+
const [a, b, c, d, e, f] = img.clip.transform;
|
|
141
|
+
out.push(`<clipPath id="${id}">` + img.clip.paths.map((p) => `<path d="${pathData(p.segments)}" transform="matrix(${fmt(a)} ${fmt(b)} ${fmt(c)} ${fmt(d)} ${fmt(e)} ${fmt(f)})"/>`).join("") + `</clipPath>`, `<g clip-path="url(#${id})">`);
|
|
142
|
+
clipped = true;
|
|
143
|
+
}
|
|
144
|
+
emitPlaced(out, {
|
|
145
|
+
resourceName: img.imageResourceName,
|
|
146
|
+
x: img.x,
|
|
147
|
+
y: img.y,
|
|
148
|
+
width: img.width,
|
|
149
|
+
height: img.height,
|
|
150
|
+
...img.crop ? { crop: img.crop } : {},
|
|
151
|
+
...img.rotationDeg !== void 0 ? { rotationDeg: img.rotationDeg } : {},
|
|
152
|
+
...img.flipH === true ? { flipH: true } : {},
|
|
153
|
+
...img.flipV === true ? { flipV: true } : {},
|
|
154
|
+
...img.alpha !== void 0 ? { alpha: img.alpha } : {}
|
|
155
|
+
}, ctx.laid, ctx.ids, filter, img.wash);
|
|
156
|
+
if (clipped) out.push("</g>");
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* A picture in its box, as the PDF places one: turned about the box's centre
|
|
160
|
+
* (clockwise, as DrawingML measures), mirrored about it, and — cropped by
|
|
161
|
+
* `a:srcRect` (§20.1.8.55) — drawn larger than the box with the box as its clip,
|
|
162
|
+
* so the part that was kept fills it. A wash (§14.1.2.10) is the veil laid over
|
|
163
|
+
* it.
|
|
164
|
+
*/
|
|
165
|
+
function emitPlaced(out, placed, laid, ids, filter, wash) {
|
|
166
|
+
const href = imageHref(placed.resourceName, laid);
|
|
167
|
+
if (!href) return;
|
|
168
|
+
const { x, y, width, height } = placed;
|
|
169
|
+
const cx = x + width / 2;
|
|
170
|
+
const cy = y + height / 2;
|
|
171
|
+
const turns = [];
|
|
172
|
+
if (placed.rotationDeg) turns.push(`rotate(${fmt(placed.rotationDeg)} ${fmt(cx)} ${fmt(cy)})`);
|
|
173
|
+
if (placed.flipH === true || placed.flipV === true) {
|
|
174
|
+
const sx = placed.flipH === true ? -1 : 1;
|
|
175
|
+
const sy = placed.flipV === true ? -1 : 1;
|
|
176
|
+
turns.push(`matrix(${String(sx)} 0 0 ${String(sy)} ${fmt(sx === -1 ? 2 * cx : 0)} ${fmt(sy === -1 ? 2 * cy : 0)})`);
|
|
115
177
|
}
|
|
116
|
-
|
|
178
|
+
const open = turns.length > 0 ? `<g transform="${turns.join(" ")}">` : "";
|
|
179
|
+
if (open) out.push(open);
|
|
180
|
+
const crop = placed.crop;
|
|
181
|
+
let clipId;
|
|
182
|
+
let drawn = {
|
|
183
|
+
x,
|
|
184
|
+
y,
|
|
185
|
+
width,
|
|
186
|
+
height
|
|
187
|
+
};
|
|
188
|
+
if (crop) {
|
|
189
|
+
const keptW = 1 - crop.left - crop.right;
|
|
190
|
+
const keptH = 1 - crop.top - crop.bottom;
|
|
191
|
+
if (keptW > 0 && keptH > 0) {
|
|
192
|
+
const fullW = width / keptW;
|
|
193
|
+
const fullH = height / keptH;
|
|
194
|
+
drawn = {
|
|
195
|
+
x: x - crop.left * fullW,
|
|
196
|
+
y: y - crop.top * fullH,
|
|
197
|
+
width: fullW,
|
|
198
|
+
height: fullH
|
|
199
|
+
};
|
|
200
|
+
clipId = `crop${String(ids.n++)}`;
|
|
201
|
+
out.push(`<clipPath id="${clipId}"><rect x="${fmt(x)}" y="${fmt(y)}" width="${fmt(width)}" height="${fmt(height)}"/></clipPath>`);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const alpha = placed.alpha !== void 0 && placed.alpha < 1 ? ` opacity="${fmt(placed.alpha)}"` : "";
|
|
205
|
+
out.push(`<image x="${fmt(drawn.x)}" y="${fmt(drawn.y)}" width="${fmt(drawn.width)}" height="${fmt(drawn.height)}" href="${href}" preserveAspectRatio="none"${clipId ? ` clip-path="url(#${clipId})"` : ""}${filter ? ` filter="url(#${filter})"` : ""}${alpha}/>`);
|
|
206
|
+
const veil = washVeil(wash);
|
|
207
|
+
if (veil) {
|
|
208
|
+
const grey = Math.round(veil.grey * 255).toString(16).padStart(2, "0");
|
|
209
|
+
out.push(`<rect x="${fmt(x)}" y="${fmt(y)}" width="${fmt(width)}" height="${fmt(height)}" fill="#${grey}${grey}${grey}" opacity="${fmt(veil.alpha)}"/>`);
|
|
210
|
+
}
|
|
211
|
+
if (open) out.push("</g>");
|
|
117
212
|
}
|
|
118
213
|
/**
|
|
119
214
|
* One page item, whatever its kind — for the runs that paint in their own order
|
|
120
215
|
* (what stands behind the content, and a picture's own primitives) rather than
|
|
121
216
|
* in the by-kind passes.
|
|
122
217
|
*
|
|
123
|
-
* @param out
|
|
124
|
-
* @param item
|
|
125
|
-
* @param
|
|
126
|
-
* @param losses Where an unrenderable item records itself.
|
|
127
|
-
* @param idc The shared id counter for generated defs.
|
|
218
|
+
* @param out The SVG fragment sink.
|
|
219
|
+
* @param item The item to draw.
|
|
220
|
+
* @param ctx The document, its glyphs, its id counter and its drawing.
|
|
128
221
|
*/
|
|
129
|
-
function emitPageItem(out, item,
|
|
222
|
+
function emitPageItem(out, item, ctx) {
|
|
130
223
|
if (item.type === "shape") {
|
|
131
|
-
emitShape(out, item.shape,
|
|
224
|
+
emitShape(out, item.shape, ctx.ids);
|
|
132
225
|
return;
|
|
133
226
|
}
|
|
134
227
|
if (item.type === "line") {
|
|
135
|
-
|
|
228
|
+
emitSvgLine(out, item, ctx);
|
|
136
229
|
return;
|
|
137
230
|
}
|
|
138
231
|
if (item.type === "image") {
|
|
139
|
-
emitImage(out, item,
|
|
232
|
+
emitImage(out, item, ctx);
|
|
140
233
|
return;
|
|
141
234
|
}
|
|
142
235
|
if (item.type === "fill") out.push(`<rect x="${fmt(item.x)}" y="${fmt(item.y)}" width="${fmt(item.width)}" height="${fmt(item.height)}" fill="#${item.fillColorHex}"/>`);
|
|
143
236
|
}
|
|
144
|
-
function
|
|
145
|
-
const clip = item.clip;
|
|
146
|
-
if (clip) {
|
|
147
|
-
const id = `clip${idc.n++}`;
|
|
148
|
-
out.push(`<clipPath id="${id}"><rect x="${fmt(clip.x)}" y="${fmt(clip.y)}" width="${fmt(clip.width)}" height="${fmt(clip.height)}"/></clipPath>`, `<g clip-path="url(#${id})">`);
|
|
149
|
-
}
|
|
150
|
-
const y = item.baselineY;
|
|
151
|
-
let x = item.originX;
|
|
152
|
-
const rot = item.rotationDeg ? ` transform="rotate(${fmt(-item.rotationDeg)} ${fmt(item.originX)} ${fmt(item.baselineY)})"` : "";
|
|
153
|
-
for (const tok of item.line.tokens) {
|
|
154
|
-
if (tok.kind === "image") {
|
|
155
|
-
x += tok.widthPt;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
if (tok.kind === "math") {
|
|
159
|
-
losses.push({
|
|
160
|
-
severity: "dropped",
|
|
161
|
-
feature: FEATURES.math,
|
|
162
|
-
detail: "inline math box not rendered by the SVG writer (v0)"
|
|
163
|
-
});
|
|
164
|
-
x += tok.widthPt;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (tok.text.trim().length > 0) out.push(`<text x="${fmt(x)}" y="${fmt(y)}"${rot} font-family="sans-serif" font-size="${fmt(tok.fontSizePt)}" fill="#${tok.resolvedRun.colorHex}">${escapeXml(tok.text)}</text>`);
|
|
168
|
-
x += tok.widthPt;
|
|
169
|
-
}
|
|
170
|
-
if (clip) out.push("</g>");
|
|
171
|
-
}
|
|
172
|
-
function emitShape(out, shape, idc) {
|
|
237
|
+
function emitShape(out, shape, ids) {
|
|
173
238
|
const [a, b, c, d, e, f] = shape.transform;
|
|
174
239
|
const transform = `matrix(${fmt(a)} ${fmt(b)} ${fmt(c)} ${fmt(d)} ${fmt(e)} ${fmt(f)})`;
|
|
175
240
|
let fill;
|
|
176
241
|
if (shape.fillGradient) {
|
|
177
|
-
const id = `grad${
|
|
242
|
+
const id = `grad${String(ids.n++)}`;
|
|
178
243
|
out.push(gradientSvgDef(id, shape.fillGradient));
|
|
179
244
|
fill = `url(#${id})`;
|
|
180
245
|
} else fill = shape.fillColorHex ? `#${shape.fillColorHex}` : "none";
|
|
181
|
-
const
|
|
246
|
+
const fillAlpha = shape.fillAlpha !== void 0 && shape.fillAlpha < 1 && fill !== "none" ? ` fill-opacity="${fmt(shape.fillAlpha)}"` : "";
|
|
247
|
+
const s = shape.stroke;
|
|
248
|
+
const stroke = s ? ` stroke="#${s.colorHex}" stroke-width="${fmt(s.widthPt)}"` + (s.cap !== void 0 ? ` stroke-linecap="${s.cap}"` : "") + (s.join !== void 0 ? ` stroke-linejoin="${s.join}"` : "") + (s.dash && s.dash.length > 0 ? ` stroke-dasharray="${s.dash.map(fmt).join(" ")}"` : "") : "";
|
|
182
249
|
const shadow = shape.shadow;
|
|
183
250
|
if (shadow) {
|
|
184
|
-
const id = `shadow${
|
|
251
|
+
const id = `shadow${String(ids.n++)}`;
|
|
185
252
|
if (shadow.blurPt > 0) out.push(`<filter id="${id}" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="${fmt(shadow.blurPt / 2)}"/></filter>`);
|
|
186
253
|
const shTransform = `matrix(${fmt(a)} ${fmt(b)} ${fmt(c)} ${fmt(d)} ${fmt(e + shadow.dxPt)} ${fmt(f + shadow.dyPt)})`;
|
|
187
254
|
out.push(`<g opacity="${fmt(shadow.alpha)}"${shadow.blurPt > 0 ? ` filter="url(#${id})"` : ""}>`);
|
|
@@ -194,7 +261,7 @@ function emitShape(out, shape, idc) {
|
|
|
194
261
|
for (const path of shape.paths) {
|
|
195
262
|
const d2 = pathData(path.segments);
|
|
196
263
|
const rule = path.fillRule === "evenodd" ? " fill-rule=\"evenodd\"" : "";
|
|
197
|
-
out.push(`<path d="${d2}" fill="${fill}"${rule}${stroke} transform="${transform}"/>`);
|
|
264
|
+
out.push(`<path d="${d2}" fill="${fill}"${fillAlpha}${rule}${stroke} transform="${transform}"/>`);
|
|
198
265
|
}
|
|
199
266
|
}
|
|
200
267
|
function pathData(segments) {
|
|
@@ -209,9 +276,6 @@ function imageHref(resourceName, laid) {
|
|
|
209
276
|
return `data:${res.prepared.mimeType};base64,${toBase64(bytes)}`;
|
|
210
277
|
}
|
|
211
278
|
}
|
|
212
|
-
function escapeXml(s) {
|
|
213
|
-
return s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """);
|
|
214
|
-
}
|
|
215
279
|
function fmt(n) {
|
|
216
280
|
const r = Math.round(n * 100) / 100;
|
|
217
281
|
return Object.is(r, -0) ? "0" : String(r);
|
|
@@ -156,7 +156,8 @@ function writeDocx(flow) {
|
|
|
156
156
|
familiesUsed: /* @__PURE__ */ new Map(),
|
|
157
157
|
...flow.faceOutlines ? { faceOutlines: flow.faceOutlines } : {},
|
|
158
158
|
facesUsed: /* @__PURE__ */ new Set(),
|
|
159
|
-
zRanks: zRanksOf(flow)
|
|
159
|
+
zRanks: zRanksOf(flow),
|
|
160
|
+
overlaid: /* @__PURE__ */ new Set()
|
|
160
161
|
};
|
|
161
162
|
const docScope = newScope();
|
|
162
163
|
const extraParts = [];
|
|
@@ -355,7 +356,10 @@ function zRanksOf(flow) {
|
|
|
355
356
|
for (const el of blocks) {
|
|
356
357
|
const z = el.kind === "image" ? el.image.float?.zOrder : el.kind === "shape" ? el.shape.float?.zOrder : el.kind === "chart" ? el.chart.float?.zOrder : void 0;
|
|
357
358
|
if (z !== void 0 && Number.isFinite(z)) seen.add(z);
|
|
358
|
-
if (el.kind === "table")
|
|
359
|
+
if (el.kind === "table") {
|
|
360
|
+
for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
|
|
361
|
+
visit(el.table.overlay?.drawings ?? []);
|
|
362
|
+
}
|
|
359
363
|
}
|
|
360
364
|
};
|
|
361
365
|
visit(flow.body);
|
|
@@ -593,6 +597,11 @@ function emitBlock(out, el, losses, state, scope, closingSectPr) {
|
|
|
593
597
|
}
|
|
594
598
|
if (el.kind === "table") {
|
|
595
599
|
out.push(tableXml(el.table, losses, state, scope));
|
|
600
|
+
for (const drawing of el.table.overlay?.drawings ?? []) {
|
|
601
|
+
if (state.overlaid.has(drawing)) continue;
|
|
602
|
+
state.overlaid.add(drawing);
|
|
603
|
+
emitBlock(out, drawing, losses, state, scope);
|
|
604
|
+
}
|
|
596
605
|
if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
|
|
597
606
|
return;
|
|
598
607
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reamkit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.32.0",
|
|
4
4
|
"description": "Ream — convert DOCX, XLSX, PPTX, PDF and legacy DOC, XLS and PPT to PDF, SVG, HTML, Markdown, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Alex Krassavin <info@reamkit.dev>",
|
|
@@ -84,6 +84,10 @@
|
|
|
84
84
|
"corpus:pixel": "tsx scripts/corpus/pixel-scout.ts",
|
|
85
85
|
"stand": "tsx stand/serve.ts",
|
|
86
86
|
"stand:build": "tsx stand/build.ts",
|
|
87
|
+
"stand:html": "tsx stand/serve.ts html",
|
|
88
|
+
"stand:html:build": "tsx stand/html-build.ts",
|
|
89
|
+
"stand:svg": "tsx stand/serve.ts svg",
|
|
90
|
+
"stand:svg:build": "tsx stand/svg-build.ts",
|
|
87
91
|
"typecheck:dist": "tsc -p tsconfig.json --noEmit"
|
|
88
92
|
},
|
|
89
93
|
"dependencies": {
|