reamkit 1.2.0 → 1.4.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.
Files changed (48) hide show
  1. package/README.md +10 -6
  2. package/dist/esm/core/converter/facade.d.ts +2 -2
  3. package/dist/esm/core/converter/facade.js +12 -0
  4. package/dist/esm/core/converter/ream.d.ts +1 -1
  5. package/dist/esm/core/converter/ream.js +14 -3
  6. package/dist/esm/core/document-model/types.d.ts +2 -0
  7. package/dist/esm/core/drawingml/chart-geometry.d.ts +1 -1
  8. package/dist/esm/core/drawingml/chart-geometry.js +79 -117
  9. package/dist/esm/core/drawingml/chart-parser.d.ts +3 -0
  10. package/dist/esm/core/drawingml/chart-parser.js +28 -1
  11. package/dist/esm/core/numbering/apply.js +2 -1
  12. package/dist/esm/core/opc/index.d.ts +3 -0
  13. package/dist/esm/core/opc/index.js +1 -0
  14. package/dist/esm/core/opc/opc-writer.d.ts +28 -0
  15. package/dist/esm/core/opc/opc-writer.js +60 -0
  16. package/dist/esm/core/opc/package.js +3 -2
  17. package/dist/esm/core/opc/relationship-types.d.ts +1 -0
  18. package/dist/esm/core/opc/relationship-types.js +5 -2
  19. package/dist/esm/excel/print-model.d.ts +3 -0
  20. package/dist/esm/excel/print-model.js +4 -8
  21. package/dist/esm/excel/sheet-drawing.d.ts +9 -0
  22. package/dist/esm/excel/sheet-drawing.js +113 -0
  23. package/dist/esm/excel/worksheet-parser.d.ts +1 -0
  24. package/dist/esm/excel/worksheet-parser.js +4 -1
  25. package/dist/esm/excel/xlsx-reader.js +41 -0
  26. package/dist/esm/excel/xlsx-to-pdf.js +25 -18
  27. package/dist/esm/index.d.ts +2 -0
  28. package/dist/esm/index.js +2 -1
  29. package/dist/esm/layout/page-doc.d.ts +1 -0
  30. package/dist/esm/layout/styled-layout.d.ts +2 -0
  31. package/dist/esm/layout/styled-layout.js +321 -171
  32. package/dist/esm/pdf/encryption.d.ts +34 -0
  33. package/dist/esm/pdf/encryption.js +143 -0
  34. package/dist/esm/pdf/index.d.ts +2 -1
  35. package/dist/esm/pdf/styled-page-emitter.d.ts +2 -0
  36. package/dist/esm/pdf/styled-page-emitter.js +25 -7
  37. package/dist/esm/pdf/styled-page-renderer.d.ts +1 -0
  38. package/dist/esm/pdf/styled-page-renderer.js +17 -2
  39. package/dist/esm/pdf/writer.d.ts +2 -0
  40. package/dist/esm/pdf/writer.js +6 -1
  41. package/dist/esm/word/document-parser.js +51 -13
  42. package/dist/esm/word/docx-reader.js +7 -11
  43. package/dist/esm/word/docx-to-pdf.js +23 -13
  44. package/dist/esm/word/docx-writer.d.ts +4 -0
  45. package/dist/esm/word/docx-writer.js +602 -0
  46. package/dist/esm/word/drawing-parser.d.ts +1 -0
  47. package/dist/esm/word/drawing-parser.js +37 -2
  48. package/package.json +4 -3
@@ -0,0 +1,602 @@
1
+ import { FEATURES } from "../core/ir/features.js";
2
+ import { detectImageFormat } from "../core/images.js";
3
+ import { EMPTY_STYLE_SHEET, resolveParagraphProperties, resolveRunProperties } from "../core/style-cascade/resolver.js";
4
+ import "../core/style-cascade/index.js";
5
+ import { buildOpcPackage } from "../core/opc/opc-writer.js";
6
+ import "../core/opc/index.js";
7
+ //#region src/word/docx-writer.ts
8
+ var encoder = new TextEncoder();
9
+ var DEFAULT_RUN = resolveRunProperties({}, {}, EMPTY_STYLE_SHEET);
10
+ var DEFAULT_PARA = resolveParagraphProperties({}, EMPTY_STYLE_SHEET);
11
+ var DOC_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
12
+ var NUMBERING_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml";
13
+ var REL_OFFICE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
14
+ var REL_NUMBERING = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
15
+ var REL_HYPERLINK = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink";
16
+ var REL_IMAGE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
17
+ var NUMBERING_PART = "word/numbering.xml";
18
+ var EMU_PER_PT = 12700;
19
+ var RASTER_MEDIA = {
20
+ png: {
21
+ ext: "png",
22
+ contentType: "image/png"
23
+ },
24
+ jpeg: {
25
+ ext: "jpeg",
26
+ contentType: "image/jpeg"
27
+ },
28
+ jpeg2000: {
29
+ ext: "jp2",
30
+ contentType: "image/jp2"
31
+ }
32
+ };
33
+ function mediaInfo(bytes) {
34
+ const raster = detectImageFormat(bytes);
35
+ if (raster) return RASTER_MEDIA[raster];
36
+ const b = (i) => bytes[i] ?? -1;
37
+ if (b(0) === 71 && b(1) === 73 && b(2) === 70 && b(3) === 56) return {
38
+ ext: "gif",
39
+ contentType: "image/gif"
40
+ };
41
+ if (b(0) === 66 && b(1) === 77) return {
42
+ ext: "bmp",
43
+ contentType: "image/bmp"
44
+ };
45
+ if (b(0) === 73 && b(1) === 73 && b(2) === 42 || b(0) === 77 && b(1) === 77) return {
46
+ ext: "tiff",
47
+ contentType: "image/tiff"
48
+ };
49
+ if (b(0) === 1 && b(1) === 0 && b(2) === 0 && b(3) === 0 && b(40) === 32 && b(41) === 69 && b(42) === 77 && b(43) === 70) return {
50
+ ext: "emf",
51
+ contentType: "image/x-emf"
52
+ };
53
+ if (b(0) === 215 && b(1) === 205 && b(2) === 198 && b(3) === 154 || b(0) === 1 && b(1) === 0 && b(2) === 9 && b(3) === 0) return {
54
+ ext: "wmf",
55
+ contentType: "image/x-wmf"
56
+ };
57
+ if (b(0) === 37 && b(1) === 80 && b(2) === 68 && b(3) === 70) return {
58
+ ext: "pdf",
59
+ contentType: "application/pdf"
60
+ };
61
+ }
62
+ var HEADER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml";
63
+ var FOOTER_CONTENT_TYPE = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml";
64
+ var REL_HEADER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header";
65
+ var REL_FOOTER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer";
66
+ function newScope() {
67
+ return {
68
+ rels: [],
69
+ relSeq: 0,
70
+ relIdByResource: /* @__PURE__ */ new Map()
71
+ };
72
+ }
73
+ function writeDocx(flow) {
74
+ const losses = [];
75
+ const body = [];
76
+ const state = {
77
+ resources: flow.resources,
78
+ mediaParts: [],
79
+ mediaFileByResource: /* @__PURE__ */ new Map(),
80
+ bookmarkSeq: 0,
81
+ drawingSeq: 0
82
+ };
83
+ const docScope = newScope();
84
+ const extraParts = [];
85
+ const extraPartRels = [];
86
+ const hfCache = /* @__PURE__ */ new Map();
87
+ const sections = flow.sections.length > 0 ? flow.sections : flow.section ? [{
88
+ properties: flow.section,
89
+ endIndex: flow.body.length
90
+ }] : [];
91
+ const sectPrByClosingIndex = /* @__PURE__ */ new Map();
92
+ let finalSectPr = "";
93
+ sections.forEach((sec, i) => {
94
+ const refs = emitHeadersFooters(flow, sec.properties, state, docScope, extraParts, extraPartRels, hfCache, losses);
95
+ const sp = sectPrXml(sec.properties, refs);
96
+ if (i === sections.length - 1) finalSectPr = sp;
97
+ else sectPrByClosingIndex.set(sec.endIndex - 1, sp);
98
+ });
99
+ flow.body.forEach((el, idx) => {
100
+ emitBlock(body, el, losses, state, docScope, sectPrByClosingIndex.get(idx));
101
+ });
102
+ if (finalSectPr) body.push(finalSectPr);
103
+ const documentXml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><w:body>${body.join("")}</w:body></w:document>`;
104
+ const numberingPart = flow.body.some((el) => el.kind === "paragraph" && el.paragraph.properties.numbering !== void 0) && flow.numbering ? {
105
+ path: NUMBERING_PART,
106
+ data: encoder.encode(numberingXml(flow.numbering)),
107
+ contentType: NUMBERING_CONTENT_TYPE
108
+ } : void 0;
109
+ if (numberingPart) docScope.rels.push({
110
+ id: `rId${++docScope.relSeq}`,
111
+ type: REL_NUMBERING,
112
+ target: "numbering.xml",
113
+ targetMode: "Internal"
114
+ });
115
+ const partRelationships = [...docScope.rels.length > 0 ? [{
116
+ sourcePart: "word/document.xml",
117
+ relationships: docScope.rels
118
+ }] : [], ...extraPartRels];
119
+ return {
120
+ bytes: buildOpcPackage({
121
+ parts: [
122
+ {
123
+ path: "word/document.xml",
124
+ data: encoder.encode(documentXml),
125
+ contentType: DOC_CONTENT_TYPE
126
+ },
127
+ ...numberingPart ? [numberingPart] : [],
128
+ ...extraParts,
129
+ ...state.mediaParts
130
+ ],
131
+ rootRelationships: [{
132
+ id: "rId1",
133
+ type: REL_OFFICE_DOCUMENT,
134
+ target: "word/document.xml",
135
+ targetMode: "Internal"
136
+ }],
137
+ ...partRelationships.length > 0 ? { partRelationships } : {}
138
+ }),
139
+ losses
140
+ };
141
+ }
142
+ function emitHeadersFooters(flow, section, state, docScope, extraParts, extraPartRels, hfCache, losses) {
143
+ const refs = {
144
+ headers: [],
145
+ footers: []
146
+ };
147
+ if (!section || !flow.headersFooters) return refs;
148
+ const emitOne = (kind, relationshipId, type) => {
149
+ const cached = hfCache.get(relationshipId);
150
+ if (cached !== void 0) return cached;
151
+ const content = flow.headersFooters.get(relationshipId);
152
+ if (!content) return void 0;
153
+ const n = extraParts.filter((p) => p.path.includes(`/${kind}`)).length + 1;
154
+ const path = `word/${kind}${n}.xml`;
155
+ const root = kind === "header" ? "w:hdr" : "w:ftr";
156
+ const scope = newScope();
157
+ const inner = [];
158
+ for (const el of content) emitBlock(inner, el, losses, state, scope);
159
+ const xml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><${root} xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">${inner.join("")}</${root}>`;
160
+ extraParts.push({
161
+ path,
162
+ data: encoder.encode(xml),
163
+ contentType: kind === "header" ? HEADER_CONTENT_TYPE : FOOTER_CONTENT_TYPE
164
+ });
165
+ if (scope.rels.length > 0) extraPartRels.push({
166
+ sourcePart: path,
167
+ relationships: scope.rels
168
+ });
169
+ const relId = `rId${++docScope.relSeq}`;
170
+ docScope.rels.push({
171
+ id: relId,
172
+ type: kind === "header" ? REL_HEADER : REL_FOOTER,
173
+ target: `${kind}${n}.xml`,
174
+ targetMode: "Internal"
175
+ });
176
+ hfCache.set(relationshipId, relId);
177
+ return relId;
178
+ };
179
+ for (const h of section.headers) {
180
+ const relId = emitOne("header", h.relationshipId, h.type);
181
+ if (relId) refs.headers.push({
182
+ type: h.type,
183
+ relId
184
+ });
185
+ }
186
+ for (const f of section.footers) {
187
+ const relId = emitOne("footer", f.relationshipId, f.type);
188
+ if (relId) refs.footers.push({
189
+ type: f.type,
190
+ relId
191
+ });
192
+ }
193
+ return refs;
194
+ }
195
+ var docxWriter = {
196
+ id: "docx",
197
+ consumes: "flow",
198
+ supports: new Set([FEATURES.text]),
199
+ write: (doc) => writeDocx(doc)
200
+ };
201
+ function emitBlock(out, el, losses, state, scope, closingSectPr) {
202
+ if (el.kind === "paragraph") {
203
+ out.push(paragraphXml(el.paragraph, state, scope, closingSectPr));
204
+ return;
205
+ }
206
+ if (el.kind === "table") {
207
+ out.push(tableXml(el.table, losses, state, scope));
208
+ if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
209
+ return;
210
+ }
211
+ if (el.kind === "image") {
212
+ const drawing = drawingXml(el.image.resource, el.image.width, el.image.height, el.image.altText, state, scope);
213
+ if (drawing) out.push(`<w:p>${pPrWithSect(el.image.paragraphProperties, closingSectPr)}<w:r>${drawing}</w:r></w:p>`);
214
+ else {
215
+ losses.push({
216
+ severity: "dropped",
217
+ feature: FEATURES.images,
218
+ detail: "image bytes missing"
219
+ });
220
+ if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
221
+ }
222
+ return;
223
+ }
224
+ if (el.kind === "shape") {
225
+ const drawing = shapeDrawingXml(el.shape, losses, state, scope);
226
+ out.push(`<w:p>${pPrWithSect(el.shape.paragraphProperties, closingSectPr)}<w:r>${drawing}</w:r></w:p>`);
227
+ return;
228
+ }
229
+ if (closingSectPr) out.push(`<w:p><w:pPr>${closingSectPr}</w:pPr></w:p>`);
230
+ losses.push({
231
+ severity: "dropped",
232
+ feature: FEATURES.charts,
233
+ detail: `${el.kind} not written by the docx writer (v0)`
234
+ });
235
+ }
236
+ function drawingXml(resource, widthPt, heightPt, altText, state, scope) {
237
+ if (resource === void 0) return "";
238
+ const relId = mediaRelId(resource, state, scope);
239
+ if (relId === void 0) return "";
240
+ const cx = Math.round(widthPt * EMU_PER_PT);
241
+ const cy = Math.round(heightPt * EMU_PER_PT);
242
+ const id = ++state.drawingSeq;
243
+ return `<w:drawing><wp:inline xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${id}" name="Image ${id}"${altText ? ` descr="${escapeAttr(altText)}"` : ""}/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="${id}" name="Image ${id}"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="${relId}"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing>`;
244
+ }
245
+ var WPS_URI = "http://schemas.microsoft.com/office/word/2010/wordprocessingShape";
246
+ function shapeDrawingXml(shape, losses, state, scope) {
247
+ const cx = Math.round(shape.width * EMU_PER_PT);
248
+ const cy = Math.round(shape.height * EMU_PER_PT);
249
+ const id = ++state.drawingSeq;
250
+ const descr = shape.altText ? ` descr="${escapeAttr(shape.altText)}"` : "";
251
+ const spPr = `<wps:spPr>${xfrmXml(shape.transform, cx, cy)}${geomXml(shape.geometry)}${fillXml(shape.fill)}${shape.line ? lineXml(shape.line) : ""}</wps:spPr>`;
252
+ const txbx = shape.text ? txbxXml(shape.text, losses, state, scope) : "";
253
+ return `<w:drawing><wp:inline xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><wp:extent cx="${cx}" cy="${cy}"/><wp:docPr id="${id}" name="Shape ${id}"${descr}/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="${WPS_URI}"><wps:wsp xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape"><wps:cNvSpPr/>` + spPr + txbx + bodyPrXml(shape.text) + "</wps:wsp></a:graphicData></a:graphic></wp:inline></w:drawing>";
254
+ }
255
+ function xfrmXml(t, cx, cy) {
256
+ return `<a:xfrm${t?.rotation60k !== void 0 ? ` rot="${t.rotation60k}"` : ""}${t?.flipH ? " flipH=\"1\"" : ""}${t?.flipV ? " flipV=\"1\"" : ""}><a:off x="0" y="0"/><a:ext cx="${cx}" cy="${cy}"/></a:xfrm>`;
257
+ }
258
+ function geomXml(g) {
259
+ if (g.kind === "custom" && g.custom) {
260
+ const cmds = g.custom.commands.map((c) => {
261
+ switch (c.cmd) {
262
+ case "move": return `<a:moveTo><a:pt x="${c.x}" y="${c.y}"/></a:moveTo>`;
263
+ case "line": return `<a:lnTo><a:pt x="${c.x}" y="${c.y}"/></a:lnTo>`;
264
+ case "cubic": return `<a:cubicBezTo><a:pt x="${c.x1}" y="${c.y1}"/><a:pt x="${c.x2}" y="${c.y2}"/><a:pt x="${c.x}" y="${c.y}"/></a:cubicBezTo>`;
265
+ case "quad": return `<a:quadBezTo><a:pt x="${c.x1}" y="${c.y1}"/><a:pt x="${c.x}" y="${c.y}"/></a:quadBezTo>`;
266
+ case "arc": return `<a:arcTo wR="${c.wR}" hR="${c.hR}" stAng="${c.stAng}" swAng="${c.swAng}"/>`;
267
+ case "close": return "<a:close/>";
268
+ }
269
+ }).join("");
270
+ const { pathWidth: w, pathHeight: h } = g.custom;
271
+ return `<a:custGeom><a:avLst/><a:gdLst/><a:rect l="0" t="0" r="${w}" b="${h}"/><a:pathLst><a:path w="${w}" h="${h}">${cmds}</a:path></a:pathLst></a:custGeom>`;
272
+ }
273
+ const gds = g.adjust && g.adjust.size > 0 ? [...g.adjust].map(([n, v]) => `<a:gd name="${escapeAttr(n)}" fmla="val ${v}"/>`).join("") : "";
274
+ return `<a:prstGeom prst="${escapeAttr(g.preset ?? "rect")}"><a:avLst>${gds}</a:avLst></a:prstGeom>`;
275
+ }
276
+ function fillXml(f) {
277
+ return f.kind === "solid" && f.colorHex ? `<a:solidFill><a:srgbClr val="${f.colorHex}"/></a:solidFill>` : "<a:noFill/>";
278
+ }
279
+ function lineXml(l) {
280
+ const w = l.width !== void 0 ? ` w="${Math.round(l.width * EMU_PER_PT)}"` : "";
281
+ const cap = l.cap === "round" ? " cap=\"rnd\"" : l.cap === "square" ? " cap=\"sq\"" : l.cap === "flat" ? " cap=\"flat\"" : "";
282
+ const inner = [];
283
+ if (l.fill === "none") inner.push("<a:noFill/>");
284
+ else if (l.colorHex) inner.push(`<a:solidFill><a:srgbClr val="${l.colorHex}"/></a:solidFill>`);
285
+ if (l.dash) inner.push(`<a:prstDash val="${l.dash}"/>`);
286
+ return `<a:ln${w}${cap}>${inner.join("")}</a:ln>`;
287
+ }
288
+ function txbxXml(text, losses, state, scope) {
289
+ const inner = [];
290
+ for (const el of text.content) emitBlock(inner, el, losses, state, scope);
291
+ return `<wps:txbx><w:txbxContent>${inner.join("")}</w:txbxContent></wps:txbx>`;
292
+ }
293
+ function bodyPrXml(text) {
294
+ if (!text) return "<wps:bodyPr/>";
295
+ const ins = (v, name) => v !== void 0 ? ` ${name}="${Math.round(v * EMU_PER_PT)}"` : "";
296
+ const anchor = text.anchor ? ` anchor="${text.anchor}"` : "";
297
+ return "<wps:bodyPr" + ins(text.insetLeft, "lIns") + ins(text.insetTop, "tIns") + ins(text.insetRight, "rIns") + ins(text.insetBottom, "bIns") + anchor + "/>";
298
+ }
299
+ function mediaRelId(resource, state, scope) {
300
+ const existingRel = scope.relIdByResource.get(resource);
301
+ if (existingRel !== void 0) return existingRel;
302
+ let target = state.mediaFileByResource.get(resource);
303
+ if (target === void 0) {
304
+ const bytes = state.resources.get(resource);
305
+ if (!bytes) return void 0;
306
+ const info = mediaInfo(bytes);
307
+ if (!info) return void 0;
308
+ target = `media/image${state.mediaParts.length + 1}.${info.ext}`;
309
+ state.mediaParts.push({
310
+ path: `word/${target}`,
311
+ data: bytes,
312
+ contentType: info.contentType
313
+ });
314
+ state.mediaFileByResource.set(resource, target);
315
+ }
316
+ const relId = `rId${++scope.relSeq}`;
317
+ scope.rels.push({
318
+ id: relId,
319
+ type: REL_IMAGE,
320
+ target,
321
+ targetMode: "Internal"
322
+ });
323
+ scope.relIdByResource.set(resource, relId);
324
+ return relId;
325
+ }
326
+ function tableXml(table, losses, state, scope) {
327
+ const grid = table.grid.map((w) => `<w:gridCol w:w="${twips(w)}"/>`).join("");
328
+ const rows = table.rows.map((row) => rowXml(row, losses, state, scope)).join("");
329
+ return `<w:tbl>${tblPrXml(table.properties)}<w:tblGrid>${grid}</w:tblGrid>${rows}</w:tbl>`;
330
+ }
331
+ function tblPrXml(p) {
332
+ const out = [];
333
+ if (p.widthType !== void 0) {
334
+ const w = p.widthType === "pct" ? Math.round((p.widthFraction ?? 0) * 5e3) : p.widthPt !== void 0 ? twips(p.widthPt) : 0;
335
+ out.push(`<w:tblW w:w="${w}" w:type="${p.widthType}"/>`);
336
+ }
337
+ if (p.alignment && p.alignment !== "left") out.push(`<w:jc w:val="${p.alignment}"/>`);
338
+ const borders = bordersXml("w:tblBorders", p.borders);
339
+ if (borders) out.push(borders);
340
+ const margins = cellMarginsXml("w:tblCellMar", p.defaultCellMargins);
341
+ if (margins) out.push(margins);
342
+ return out.length > 0 ? `<w:tblPr>${out.join("")}</w:tblPr>` : "";
343
+ }
344
+ function rowXml(row, losses, state, scope) {
345
+ const trPr = [];
346
+ if (row.properties.height !== void 0) {
347
+ const rule = row.properties.heightRule ?? "atLeast";
348
+ trPr.push(`<w:trHeight w:val="${twips(row.properties.height)}" w:hRule="${rule}"/>`);
349
+ }
350
+ if (row.properties.isHeader) trPr.push("<w:tblHeader/>");
351
+ if (row.properties.cantSplit) trPr.push("<w:cantSplit/>");
352
+ return `<w:tr>${trPr.length > 0 ? `<w:trPr>${trPr.join("")}</w:trPr>` : ""}${row.cells.map((cell) => cellXml(cell, losses, state, scope)).join("")}</w:tr>`;
353
+ }
354
+ function cellXml(cell, losses, state, scope) {
355
+ const content = [];
356
+ for (const child of cell.content) emitBlock(content, child, losses, state, scope);
357
+ if (content.length === 0) content.push("<w:p/>");
358
+ return `<w:tc>${tcPrXml(cell.properties)}${content.join("")}</w:tc>`;
359
+ }
360
+ function tcPrXml(p) {
361
+ const out = [];
362
+ if (p.width !== void 0) out.push(`<w:tcW w:w="${twips(p.width)}" w:type="dxa"/>`);
363
+ if (p.colSpan !== void 0 && p.colSpan > 1) out.push(`<w:gridSpan w:val="${p.colSpan}"/>`);
364
+ if (p.merge !== void 0) out.push(p.merge === "start" ? "<w:vMerge w:val=\"restart\"/>" : "<w:vMerge w:val=\"continue\"/>");
365
+ const borders = bordersXml("w:tcBorders", p.borders);
366
+ if (borders) out.push(borders);
367
+ const margins = cellMarginsXml("w:tcMar", p.margins);
368
+ if (margins) out.push(margins);
369
+ if (p.shading) out.push(`<w:shd w:val="clear" w:color="auto" w:fill="${p.shading.colorHex}"/>`);
370
+ return out.length > 0 ? `<w:tcPr>${out.join("")}</w:tcPr>` : "";
371
+ }
372
+ var BORDER_SIDES = [
373
+ ["top", "w:top"],
374
+ ["left", "w:left"],
375
+ ["bottom", "w:bottom"],
376
+ ["right", "w:right"],
377
+ ["insideH", "w:insideH"],
378
+ ["insideV", "w:insideV"]
379
+ ];
380
+ function bordersXml(tag, borders) {
381
+ if (!borders) return "";
382
+ const sides = BORDER_SIDES.map(([key, el]) => {
383
+ const b = borders[key];
384
+ if (!b) return "";
385
+ const sz = b.width !== void 0 ? ` w:sz="${Math.round(b.width * 8)}"` : "";
386
+ const color = b.colorHex !== void 0 ? ` w:color="${b.colorHex}"` : "";
387
+ return `<${el} w:val="${b.style}"${sz}${color}/>`;
388
+ }).join("");
389
+ return sides ? `<${tag}>${sides}</${tag}>` : "";
390
+ }
391
+ function cellMarginsXml(tag, margins) {
392
+ if (!margins) return "";
393
+ const inner = [
394
+ ["top", "w:top"],
395
+ ["left", "w:left"],
396
+ ["bottom", "w:bottom"],
397
+ ["right", "w:right"]
398
+ ].map(([key, el]) => {
399
+ const v = margins[key];
400
+ return v !== void 0 ? `<${el} w:w="${twips(v)}" w:type="dxa"/>` : "";
401
+ }).join("");
402
+ return inner ? `<${tag}>${inner}</${tag}>` : "";
403
+ }
404
+ function paragraphXml(p, state, scope, closingSectPr) {
405
+ const visible = p.runs.filter((run) => !run.listMarker && run.math === void 0 && (run.text !== "" || run.inlineImage !== void 0 || run.pageBreak || run.href !== void 0 || run.anchor !== void 0));
406
+ const inner = [];
407
+ let i = 0;
408
+ while (i < visible.length) {
409
+ const run = visible[i];
410
+ const key = run.href ?? run.anchor;
411
+ if (key === void 0) {
412
+ inner.push(runXml(run, state, scope));
413
+ i++;
414
+ continue;
415
+ }
416
+ let j = i + 1;
417
+ while (j < visible.length && (visible[j].href ?? visible[j].anchor) === key) j++;
418
+ const group = visible.slice(i, j).map((r) => runXml(r, state, scope)).join("");
419
+ inner.push(hyperlinkXml(run, group === "" ? "<w:r/>" : group, state, scope));
420
+ i = j;
421
+ }
422
+ const bookmarks = (p.bookmarks ?? []).map((name) => {
423
+ const id = state.bookmarkSeq++;
424
+ return `<w:bookmarkStart w:id="${id}" w:name="${escapeAttr(name)}"/><w:bookmarkEnd w:id="${id}"/>`;
425
+ }).join("");
426
+ const pPrInner = pPrBody(p.properties) + (closingSectPr ?? "");
427
+ return `<w:p>${pPrInner !== "" ? `<w:pPr>${pPrInner}</w:pPr>` : ""}${bookmarks}${inner.join("")}</w:p>`;
428
+ }
429
+ function hyperlinkXml(run, inner, _state, scope) {
430
+ if (run.href !== void 0) {
431
+ const id = `rId${++scope.relSeq}`;
432
+ scope.rels.push({
433
+ id,
434
+ type: REL_HYPERLINK,
435
+ target: run.href,
436
+ targetMode: "External"
437
+ });
438
+ return `<w:hyperlink r:id="${id}">${inner}</w:hyperlink>`;
439
+ }
440
+ return `<w:hyperlink w:anchor="${escapeAttr(run.anchor)}">${inner}</w:hyperlink>`;
441
+ }
442
+ function runXml(run, state, scope) {
443
+ const rPr = rPrXml(run.properties);
444
+ if (run.inlineImage !== void 0) {
445
+ const img = run.inlineImage;
446
+ const drawing = drawingXml(img.resource, img.width, img.height, void 0, state, scope);
447
+ if (drawing) return `<w:r>${rPr}${drawing}</w:r>`;
448
+ if (run.text === "" && !run.pageBreak) return "";
449
+ }
450
+ const brk = run.pageBreak ? "<w:br w:type=\"page\"/>" : "";
451
+ if (run.text === "") return brk ? `<w:r>${rPr}${brk}</w:r>` : "";
452
+ return `<w:r>${rPr}<w:t xml:space="preserve">${escapeXml(run.text)}</w:t>${brk}</w:r>`;
453
+ }
454
+ function rPrXml(r) {
455
+ const out = [];
456
+ if (r.bold !== DEFAULT_RUN.bold) out.push(toggle("w:b", r.bold));
457
+ if (r.italic !== DEFAULT_RUN.italic) out.push(toggle("w:i", r.italic));
458
+ if (r.strike !== DEFAULT_RUN.strike) out.push(toggle("w:strike", r.strike));
459
+ if (r.underline !== DEFAULT_RUN.underline) out.push(`<w:u w:val="${r.underline}"/>`);
460
+ const fonts = rFontsXml(r.fontFamily);
461
+ if (fonts) out.push(fonts);
462
+ if (r.fontSizePt !== DEFAULT_RUN.fontSizePt) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
463
+ if (r.colorHex !== DEFAULT_RUN.colorHex) out.push(`<w:color w:val="${r.colorHex}"/>`);
464
+ if (r.verticalAlign !== DEFAULT_RUN.verticalAlign) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
465
+ if (r.rtl !== DEFAULT_RUN.rtl) out.push(toggle("w:rtl", r.rtl));
466
+ if (r.lang !== void 0) out.push(`<w:lang w:val="${escapeAttr(r.lang)}"/>`);
467
+ return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
468
+ }
469
+ function pPrBody(p) {
470
+ const out = [];
471
+ if (p.numbering) out.push(`<w:numPr><w:ilvl w:val="${p.numbering.ilvl}"/><w:numId w:val="${escapeAttr(p.numbering.numId)}"/></w:numPr>`);
472
+ if (p.outlineLevel !== void 0) out.push(`<w:outlineLvl w:val="${p.outlineLevel}"/>`);
473
+ if (p.pageBreakBefore) out.push("<w:pageBreakBefore/>");
474
+ if (p.bidi !== DEFAULT_PARA.bidi) out.push(toggle("w:bidi", p.bidi));
475
+ const ind = indXml(p);
476
+ if (ind) out.push(ind);
477
+ const spacing = spacingXml(p);
478
+ if (spacing) out.push(spacing);
479
+ if (p.alignment !== DEFAULT_PARA.alignment) out.push(`<w:jc w:val="${p.alignment}"/>`);
480
+ return out.join("");
481
+ }
482
+ function pPrWithSect(p, closingSectPr) {
483
+ const inner = pPrBody(p) + (closingSectPr ?? "");
484
+ return inner !== "" ? `<w:pPr>${inner}</w:pPr>` : "";
485
+ }
486
+ function indXml(p) {
487
+ const attrs = [];
488
+ if (p.indentLeft !== DEFAULT_PARA.indentLeft) attrs.push(`w:left="${twips(p.indentLeft)}"`);
489
+ if (p.indentRight !== DEFAULT_PARA.indentRight) attrs.push(`w:right="${twips(p.indentRight)}"`);
490
+ if (p.indentFirstLine !== DEFAULT_PARA.indentFirstLine) if (p.indentFirstLine < 0) attrs.push(`w:hanging="${twips(-p.indentFirstLine)}"`);
491
+ else attrs.push(`w:firstLine="${twips(p.indentFirstLine)}"`);
492
+ return attrs.length > 0 ? `<w:ind ${attrs.join(" ")}/>` : "";
493
+ }
494
+ function spacingXml(p) {
495
+ const attrs = [];
496
+ if (p.spacingBefore !== DEFAULT_PARA.spacingBefore) attrs.push(`w:before="${twips(p.spacingBefore)}"`);
497
+ if (p.spacingAfter !== DEFAULT_PARA.spacingAfter) attrs.push(`w:after="${twips(p.spacingAfter)}"`);
498
+ if ((p.spacingLineRule !== DEFAULT_PARA.spacingLineRule || p.spacingLine !== DEFAULT_PARA.spacingLine) && p.spacingLine > 0) {
499
+ const lineVal = p.spacingLineRule === "auto" ? Math.round(p.spacingLine * 12) : twips(p.spacingLine);
500
+ attrs.push(`w:line="${lineVal}"`, `w:lineRule="${p.spacingLineRule}"`);
501
+ }
502
+ return attrs.length > 0 ? `<w:spacing ${attrs.join(" ")}/>` : "";
503
+ }
504
+ function rFontsXml(fonts) {
505
+ const d = DEFAULT_RUN.fontFamily;
506
+ const attrs = [];
507
+ if (fonts.ascii && fonts.ascii !== d.ascii) attrs.push(`w:ascii="${escapeAttr(fonts.ascii)}"`);
508
+ if (fonts.hAnsi && fonts.hAnsi !== d.hAnsi) attrs.push(`w:hAnsi="${escapeAttr(fonts.hAnsi)}"`);
509
+ if (fonts.cs && fonts.cs !== d.cs) attrs.push(`w:cs="${escapeAttr(fonts.cs)}"`);
510
+ return attrs.length > 0 ? `<w:rFonts ${attrs.join(" ")}/>` : "";
511
+ }
512
+ function toggle(tag, on) {
513
+ return on ? `<${tag}/>` : `<${tag} w:val="false"/>`;
514
+ }
515
+ function numberingXml(numbering) {
516
+ const out = ["<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>", "<w:numbering xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">"];
517
+ for (const abstractNum of numbering.abstractNums.values()) {
518
+ out.push(`<w:abstractNum w:abstractNumId="${escapeAttr(abstractNum.id)}">`);
519
+ for (const level of [...abstractNum.levels.values()].sort((a, b) => a.ilvl - b.ilvl)) out.push(levelXml(level));
520
+ out.push("</w:abstractNum>");
521
+ }
522
+ for (const inst of numbering.numInstances.values()) out.push(`<w:num w:numId="${escapeAttr(inst.numId)}"><w:abstractNumId w:val="${escapeAttr(inst.abstractNumId)}"/></w:num>`);
523
+ out.push("</w:numbering>");
524
+ return out.join("");
525
+ }
526
+ function levelXml(level) {
527
+ const inner = [
528
+ `<w:start w:val="${level.start}"/>`,
529
+ `<w:numFmt w:val="${level.format}"/>`,
530
+ `<w:lvlText w:val="${escapeAttr(level.lvlText)}"/>`
531
+ ];
532
+ const pPr = rawParaPrXml(level.paragraphProperties);
533
+ if (pPr) inner.push(pPr);
534
+ const rPr = rawRunPrXml(level.runProperties);
535
+ if (rPr) inner.push(rPr);
536
+ return `<w:lvl w:ilvl="${level.ilvl}">${inner.join("")}</w:lvl>`;
537
+ }
538
+ function rawParaPrXml(p) {
539
+ const attrs = [];
540
+ if (p.indentLeft !== void 0) attrs.push(`w:left="${twips(p.indentLeft)}"`);
541
+ if (p.indentRight !== void 0) attrs.push(`w:right="${twips(p.indentRight)}"`);
542
+ if (p.indentFirstLine !== void 0) if (p.indentFirstLine < 0) attrs.push(`w:hanging="${twips(-p.indentFirstLine)}"`);
543
+ else attrs.push(`w:firstLine="${twips(p.indentFirstLine)}"`);
544
+ const ind = attrs.length > 0 ? `<w:ind ${attrs.join(" ")}/>` : "";
545
+ const jc = p.alignment !== void 0 ? `<w:jc w:val="${p.alignment}"/>` : "";
546
+ return ind || jc ? `<w:pPr>${jc}${ind}</w:pPr>` : "";
547
+ }
548
+ function rawRunPrXml(r) {
549
+ const out = [];
550
+ if (r.bold !== void 0) out.push(toggle("w:b", r.bold));
551
+ if (r.italic !== void 0) out.push(toggle("w:i", r.italic));
552
+ if (r.strike !== void 0) out.push(toggle("w:strike", r.strike));
553
+ if (r.underline !== void 0) out.push(`<w:u w:val="${r.underline}"/>`);
554
+ const fonts = r.fontFamily ? rawRFontsXml(r.fontFamily) : "";
555
+ if (fonts) out.push(fonts);
556
+ if (r.fontSizePt !== void 0) out.push(`<w:sz w:val="${Math.round(r.fontSizePt * 2)}"/>`);
557
+ if (r.colorHex !== void 0) out.push(`<w:color w:val="${r.colorHex}"/>`);
558
+ if (r.verticalAlign !== void 0) out.push(`<w:vertAlign w:val="${r.verticalAlign}"/>`);
559
+ return out.length > 0 ? `<w:rPr>${out.join("")}</w:rPr>` : "";
560
+ }
561
+ function rawRFontsXml(fonts) {
562
+ const attrs = [];
563
+ if (fonts.ascii) attrs.push(`w:ascii="${escapeAttr(fonts.ascii)}"`);
564
+ if (fonts.hAnsi) attrs.push(`w:hAnsi="${escapeAttr(fonts.hAnsi)}"`);
565
+ if (fonts.cs) attrs.push(`w:cs="${escapeAttr(fonts.cs)}"`);
566
+ return attrs.length > 0 ? `<w:rFonts ${attrs.join(" ")}/>` : "";
567
+ }
568
+ function sectPrXml(s, hf) {
569
+ const parts = [];
570
+ for (const h of hf.headers) parts.push(`<w:headerReference w:type="${h.type}" r:id="${h.relId}"/>`);
571
+ for (const f of hf.footers) parts.push(`<w:footerReference w:type="${f.type}" r:id="${f.relId}"/>`);
572
+ if (s.pageSize) {
573
+ const orient = s.pageSize.orientation === "landscape" ? " w:orient=\"landscape\"" : "";
574
+ parts.push(`<w:pgSz w:w="${twips(s.pageSize.width)}" w:h="${twips(s.pageSize.height)}"${orient}/>`);
575
+ }
576
+ if (s.margins) {
577
+ const m = s.margins;
578
+ const header = m.header !== void 0 ? ` w:header="${twips(m.header)}"` : "";
579
+ const footer = m.footer !== void 0 ? ` w:footer="${twips(m.footer)}"` : "";
580
+ parts.push(`<w:pgMar w:top="${twips(m.top)}" w:right="${twips(m.right)}" w:bottom="${twips(m.bottom)}" w:left="${twips(m.left)}"${header}${footer}/>`);
581
+ }
582
+ if (s.columns) parts.push(colsXml(s.columns));
583
+ if (s.titlePg) parts.push("<w:titlePg/>");
584
+ if (parts.length === 0) return "";
585
+ return `<w:sectPr>${parts.join("")}</w:sectPr>`;
586
+ }
587
+ function colsXml(cols) {
588
+ if (cols.explicit && cols.explicit.length > 0) {
589
+ const inner = cols.explicit.map((c) => `<w:col w:w="${twips(c.widthPt)}" w:space="${twips(c.spacePt)}"/>`).join("");
590
+ return `<w:cols w:num="${cols.explicit.length}" w:equalWidth="0">${inner}</w:cols>`;
591
+ }
592
+ return `<w:cols w:num="${cols.count}" w:space="${twips(cols.spacePt)}"/>`;
593
+ }
594
+ var twips = (pt) => Math.round(pt * 20);
595
+ function escapeXml(s) {
596
+ return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
597
+ }
598
+ function escapeAttr(s) {
599
+ return escapeXml(s).replace(/"/g, "&quot;");
600
+ }
601
+ //#endregion
602
+ export { docxWriter, writeDocx };
@@ -35,3 +35,4 @@ export type DrawingContent = {
35
35
  export declare function resolveMc(altContent: PoNode): ReadonlyArray<PoNode>;
36
36
  export declare function expandMcChildren(children: ReadonlyArray<PoNode>): Array<PoNode>;
37
37
  export declare function parseDrawing(drawing: PoNode, resolveColor: ColorResolver, parseBody?: ParseBody): DrawingContent | null;
38
+ export declare function parseVmlPicture(node: PoNode): DrawingContent | null;
@@ -1,4 +1,4 @@
1
- import { emuToPt } from "../core/ir/units.js";
1
+ import { emuToPt, pt } from "../core/ir/units.js";
2
2
  import { poAttr, poChildren, poFindDescendant, poIntAttr, poIs, poTag, poText } from "../core/po-helpers.js";
3
3
  import { resolveColorNode } from "../core/drawingml/colors.js";
4
4
  //#region src/word/drawing-parser.ts
@@ -115,6 +115,41 @@ function parseDrawing(drawing, resolveColor, parseBody) {
115
115
  };
116
116
  return null;
117
117
  }
118
+ function parseVmlPicture(node) {
119
+ const imagedata = poFindDescendant(node, "v:imagedata");
120
+ if (!imagedata) return null;
121
+ const imageId = poAttr(imagedata, "id");
122
+ if (imageId === void 0) return null;
123
+ const shape = poFindDescendant(node, "v:shape") ?? poFindDescendant(node, "v:rect") ?? poFindDescendant(node, "v:oval");
124
+ const width = vmlStyleLength(shape, "width");
125
+ const height = vmlStyleLength(shape, "height");
126
+ if (width === void 0 || height === void 0) return null;
127
+ const altText = (shape ? poAttr(shape, "alt") : void 0)?.trim() || poAttr(imagedata, "title")?.trim() || void 0;
128
+ return {
129
+ kind: "image",
130
+ imageId,
131
+ width,
132
+ height,
133
+ ...altText ? { altText } : {}
134
+ };
135
+ }
136
+ var VML_UNIT_TO_PT = {
137
+ pt: 1,
138
+ in: 72,
139
+ px: .75,
140
+ cm: 72 / 2.54,
141
+ mm: 72 / 25.4,
142
+ pc: 12
143
+ };
144
+ function vmlStyleLength(shape, prop) {
145
+ const style = shape ? poAttr(shape, "style") : void 0;
146
+ if (style === void 0) return void 0;
147
+ const m = new RegExp(`(?:^|;)\\s*${prop}\\s*:\\s*(-?[0-9.]+)(pt|in|px|cm|mm|pc)?`, "i").exec(style);
148
+ if (!m) return void 0;
149
+ const value = Number.parseFloat(m[1]);
150
+ if (!Number.isFinite(value) || value <= 0) return void 0;
151
+ return pt(value * (VML_UNIT_TO_PT[(m[2] ?? "px").toLowerCase()] ?? 1));
152
+ }
118
153
  function parseWsp(graphicData, extentCx, extentCy, resolveColor, parseBody) {
119
154
  const wsp = expandMcChildren(poChildren(graphicData)).find((c) => poIs(c, "wps:wsp"));
120
155
  if (!wsp) return null;
@@ -395,4 +430,4 @@ function colorFromGradient(grad, resolveColor) {
395
430
  return (toHex(r) + toHex(g) + toHex(b)).toUpperCase();
396
431
  }
397
432
  //#endregion
398
- export { expandMcChildren, parseDrawing };
433
+ export { expandMcChildren, parseDrawing, parseVmlPicture };