ooxml.js 2.5.2 → 2.6.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 (42) hide show
  1. package/README.md +1 -1
  2. package/dist/index.cjs +22 -0
  3. package/dist/index.d.cts +3 -2
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +3 -2
  6. package/dist/typed/docx/numbering.cjs +86 -0
  7. package/dist/typed/docx/numbering.d.cts +23 -0
  8. package/dist/typed/docx/numbering.d.ts +23 -0
  9. package/dist/typed/docx/numbering.js +83 -0
  10. package/dist/typed/docx/read.cjs +115 -15
  11. package/dist/typed/docx/read.d.cts +8 -0
  12. package/dist/typed/docx/read.d.ts +8 -0
  13. package/dist/typed/docx/read.js +117 -17
  14. package/dist/typed/docx/styles.cjs +26 -2
  15. package/dist/typed/docx/styles.js +26 -2
  16. package/dist/typed/pptx/read.cjs +5 -20
  17. package/dist/typed/pptx/read.js +5 -20
  18. package/dist/typed/shared/drawingml.cjs +112 -5
  19. package/dist/typed/shared/drawingml.d.cts +19 -2
  20. package/dist/typed/shared/drawingml.d.ts +19 -2
  21. package/dist/typed/shared/drawingml.js +111 -6
  22. package/dist/typed/shared/units.cjs +10 -0
  23. package/dist/typed/shared/units.d.cts +4 -1
  24. package/dist/typed/shared/units.d.ts +4 -1
  25. package/dist/typed/shared/units.js +8 -1
  26. package/dist/typed/xlsx/build.cjs +83 -55
  27. package/dist/typed/xlsx/build.js +83 -55
  28. package/dist/typed/xlsx/content.cjs +85 -15
  29. package/dist/typed/xlsx/content.js +85 -15
  30. package/dist/typed/xlsx/number-format.cjs +324 -0
  31. package/dist/typed/xlsx/number-format.d.cts +52 -0
  32. package/dist/typed/xlsx/number-format.d.ts +52 -0
  33. package/dist/typed/xlsx/number-format.js +312 -0
  34. package/dist/typed/xlsx/serial.cjs +109 -0
  35. package/dist/typed/xlsx/serial.d.cts +11 -0
  36. package/dist/typed/xlsx/serial.d.ts +11 -0
  37. package/dist/typed/xlsx/serial.js +102 -0
  38. package/dist/typed/xlsx/styles.cjs +73 -0
  39. package/dist/typed/xlsx/styles.d.cts +21 -0
  40. package/dist/typed/xlsx/styles.d.ts +21 -0
  41. package/dist/typed/xlsx/styles.js +69 -0
  42. package/package.json +1 -1
@@ -1,11 +1,14 @@
1
+ import { base64ToBytes } from "../../util/base64.js";
1
2
  import { attr, childrenWithTag, elementsWithTag, resolveRelationships, rootElement, textContent } from "../util.js";
2
3
  import { DocumentMetadataSchema, readCoreProperties } from "../shared/metadata.js";
3
- import { twipsToPt } from "../shared/units.js";
4
+ import { sniffImageFormat } from "../../image/sniff.js";
5
+ import { eighthPointsToPt, emuToPt, twipsToPt } from "../shared/units.js";
4
6
  import { EMPTY_THEME, readTheme } from "../shared/drawingml.js";
5
7
  import { assignSourcePaths } from "../shared/source-path.js";
6
8
  import { resolveParagraphProperties, resolveRunProperties } from "./styles.js";
9
+ import { NumberingDefinitionSchema, readNumberingDefinitions } from "./numbering.js";
7
10
  import { z } from "zod";
8
- import { ContentSectionSchema, PAGE_SIZE_LETTER, rgbHexToColor } from "document-schema.js";
11
+ import { COLOR_BLACK, ContentSectionSchema, PAGE_SIZE_LETTER, rgbHexToColor } from "document-schema.js";
9
12
  //#region src/typed/docx/read.ts
10
13
  const CommentSchema = z.object({
11
14
  author: z.string().optional(),
@@ -21,7 +24,8 @@ const DocxDocumentSchema = z.object({
21
24
  comments: z.array(CommentSchema),
22
25
  footnotes: z.array(FootnoteSchema),
23
26
  headers: z.array(z.string()),
24
- footers: z.array(z.string())
27
+ footers: z.array(z.string()),
28
+ numbering: z.record(z.string(), NumberingDefinitionSchema)
25
29
  });
26
30
  const DOCUMENT_PART_PATH = "word/document.xml";
27
31
  const STYLES_PART_PATH = "word/styles.xml";
@@ -88,6 +92,53 @@ function readRunText(run) {
88
92
  }
89
93
  return text;
90
94
  }
95
+ function readDrawingImage(drawing, rels, pkg) {
96
+ const container = childrenWithTag(drawing, "wp:inline")[0] ?? childrenWithTag(drawing, "wp:anchor")[0];
97
+ if (container === void 0) return;
98
+ const extent = childrenWithTag(container, "wp:extent")[0];
99
+ const cx = extent === void 0 ? void 0 : attr(extent, "cx");
100
+ const cy = extent === void 0 ? void 0 : attr(extent, "cy");
101
+ if (cx === void 0 || cy === void 0) return;
102
+ const docPr = childrenWithTag(container, "wp:docPr")[0];
103
+ const altText = docPr === void 0 ? void 0 : attr(docPr, "descr") ?? attr(docPr, "title");
104
+ const blip = elementsWithTag(container.children, "a:blip")[0];
105
+ const rId = blip === void 0 ? void 0 : attr(blip, "r:embed");
106
+ const rel = rId === void 0 ? void 0 : rels.get(rId);
107
+ const mediaPart = rel === void 0 ? void 0 : pkg.parts[rel.target];
108
+ if (mediaPart?.kind !== "binary") return;
109
+ const format = sniffImageFormat(base64ToBytes(mediaPart.base64));
110
+ if (format === void 0) return;
111
+ const image = {
112
+ kind: "image",
113
+ format,
114
+ base64: mediaPart.base64,
115
+ widthPt: emuToPt(Number(cx)),
116
+ heightPt: emuToPt(Number(cy))
117
+ };
118
+ if (altText !== void 0) image.altText = altText;
119
+ return image;
120
+ }
121
+ function collectDrawings(nodes, out) {
122
+ for (const node of nodes) {
123
+ if (node.type !== "element") continue;
124
+ if (node.tag === "w:del") continue;
125
+ if (node.tag === "w:drawing") {
126
+ out.push(node);
127
+ continue;
128
+ }
129
+ collectDrawings(node.children, out);
130
+ }
131
+ }
132
+ function readParagraphImages(paragraph, rels, pkg) {
133
+ const drawings = [];
134
+ collectDrawings(paragraph.children, drawings);
135
+ const images = [];
136
+ for (const drawing of drawings) {
137
+ const image = readDrawingImage(drawing, rels, pkg);
138
+ if (image !== void 0) images.push(image);
139
+ }
140
+ return images;
141
+ }
91
142
  function readRun(run, paragraph, context) {
92
143
  const props = resolveRunProperties(run, paragraph, context);
93
144
  return {
@@ -155,7 +206,51 @@ function readCellShading(tcPr) {
155
206
  const fill = shd === void 0 ? void 0 : attr(shd, "w:fill");
156
207
  return fill === void 0 || fill === "auto" || fill === "none" ? void 0 : rgbHexToColor(fill);
157
208
  }
158
- function readRawCell(tc, context, rels) {
209
+ const BORDER_STYLE_MAP = /* @__PURE__ */ new Map([
210
+ ["single", "solid"],
211
+ ["thick", "solid"],
212
+ ["triple", "solid"],
213
+ ["outset", "solid"],
214
+ ["inset", "solid"],
215
+ ["threeDEmboss", "solid"],
216
+ ["threeDEngrave", "solid"],
217
+ ["dashed", "dashed"],
218
+ ["dashSmallGap", "dashed"],
219
+ ["dashDotStroked", "dashed"],
220
+ ["dotDash", "dashed"],
221
+ ["dotted", "dotted"],
222
+ ["dotDotDash", "dotted"],
223
+ ["double", "double"],
224
+ ["doubleWave", "double"]
225
+ ]);
226
+ const DEFAULT_BORDER_WIDTH_EIGHTH_POINTS = 4;
227
+ function readCellBorderEdge(tcBorders, tag) {
228
+ const edge = tcBorders === void 0 ? void 0 : childrenWithTag(tcBorders, tag)[0];
229
+ const val = edge === void 0 ? void 0 : attr(edge, "w:val");
230
+ if (edge === void 0 || val === void 0 || val === "nil" || val === "none") return;
231
+ const sz = attr(edge, "w:sz");
232
+ const colorVal = attr(edge, "w:color");
233
+ return {
234
+ color: colorVal === void 0 || colorVal === "auto" ? COLOR_BLACK : rgbHexToColor(colorVal),
235
+ widthPt: eighthPointsToPt(sz === void 0 ? DEFAULT_BORDER_WIDTH_EIGHTH_POINTS : Number(sz)),
236
+ style: BORDER_STYLE_MAP.get(val) ?? "solid"
237
+ };
238
+ }
239
+ function readCellBorders(tcPr) {
240
+ const tcBorders = tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "w:tcBorders")[0];
241
+ if (tcBorders === void 0) return;
242
+ const borders = {};
243
+ const left = readCellBorderEdge(tcBorders, "w:left") ?? readCellBorderEdge(tcBorders, "w:start");
244
+ const right = readCellBorderEdge(tcBorders, "w:right") ?? readCellBorderEdge(tcBorders, "w:end");
245
+ const top = readCellBorderEdge(tcBorders, "w:top");
246
+ const bottom = readCellBorderEdge(tcBorders, "w:bottom");
247
+ if (left !== void 0) borders.left = left;
248
+ if (right !== void 0) borders.right = right;
249
+ if (top !== void 0) borders.top = top;
250
+ if (bottom !== void 0) borders.bottom = bottom;
251
+ return Object.keys(borders).length === 0 ? void 0 : borders;
252
+ }
253
+ function readRawCell(tc, context, rels, pkg) {
159
254
  const tcPr = childrenWithTag(tc, "w:tcPr")[0];
160
255
  const gridSpanEl = tcPr === void 0 ? void 0 : childrenWithTag(tcPr, "w:gridSpan")[0];
161
256
  const gridSpanVal = gridSpanEl === void 0 ? void 0 : attr(gridSpanEl, "w:val");
@@ -165,13 +260,14 @@ function readRawCell(tc, context, rels) {
165
260
  gridSpan: gridSpanVal === void 0 ? 1 : Number(gridSpanVal),
166
261
  isVMergeContinuation: vMergeVal === "continue",
167
262
  background: readCellShading(tcPr),
168
- blocks: readBodyBlocks(tc.children, context, rels)
263
+ borders: readCellBorders(tcPr),
264
+ blocks: readBodyBlocks(tc.children, context, rels, pkg)
169
265
  };
170
266
  }
171
- function readTable(tbl, context, rels) {
267
+ function readTable(tbl, context, rels, pkg) {
172
268
  const tblGrid = childrenWithTag(tbl, "w:tblGrid")[0];
173
269
  const columnWidthsPt = tblGrid === void 0 ? [] : childrenWithTag(tblGrid, "w:gridCol").map((col) => twipsToPt(Number(attr(col, "w:w") ?? "0")));
174
- const rawRows = childrenWithTag(tbl, "w:tr").map((tr) => childrenWithTag(tr, "w:tc").map((tc) => readRawCell(tc, context, rels)));
270
+ const rawRows = childrenWithTag(tbl, "w:tr").map((tr) => childrenWithTag(tr, "w:tc").map((tc) => readRawCell(tc, context, rels, pkg)));
175
271
  const rowColumnIndices = rawRows.map((row) => {
176
272
  const indices = [];
177
273
  let col = 0;
@@ -197,31 +293,33 @@ function readTable(tbl, context, rels) {
197
293
  blocks: cell.blocks,
198
294
  colSpan: cell.gridSpan > 1 ? cell.gridSpan : void 0,
199
295
  rowSpan: rowSpan > 1 ? rowSpan : void 0,
200
- background: cell.background
296
+ background: cell.background,
297
+ borders: cell.borders
201
298
  };
202
299
  }) }))
203
300
  };
204
301
  }
205
- function readBodyBlocks(nodes, context, rels) {
302
+ function readBodyBlocks(nodes, context, rels, pkg) {
206
303
  const blocks = [];
207
304
  for (const node of nodes) {
208
305
  if (node.type !== "element") continue;
209
306
  if (node.tag === "w:p") {
210
307
  if (hasPageBreakBefore(node)) blocks.push({ kind: "pageBreak" });
211
308
  blocks.push(readParagraph(node, context, rels));
212
- } else if (node.tag === "w:tbl") blocks.push(readTable(node, context, rels));
309
+ blocks.push(...readParagraphImages(node, rels, pkg));
310
+ } else if (node.tag === "w:tbl") blocks.push(readTable(node, context, rels, pkg));
213
311
  else if (node.tag === "w:sdt") {
214
312
  const sdtContent = childrenWithTag(node, "w:sdtContent")[0];
215
- if (sdtContent !== void 0) blocks.push(...readBodyBlocks(sdtContent.children, context, rels));
216
- } else if (node.tag === "w:ins") blocks.push(...readBodyBlocks(node.children, context, rels));
313
+ if (sdtContent !== void 0) blocks.push(...readBodyBlocks(sdtContent.children, context, rels, pkg));
314
+ } else if (node.tag === "w:ins") blocks.push(...readBodyBlocks(node.children, context, rels, pkg));
217
315
  else if (node.tag === "mc:AlternateContent") {
218
316
  const target = childrenWithTag(node, "mc:Fallback")[0] ?? childrenWithTag(node, "mc:Choice")[0];
219
- if (target !== void 0) blocks.push(...readBodyBlocks(target.children, context, rels));
317
+ if (target !== void 0) blocks.push(...readBodyBlocks(target.children, context, rels, pkg));
220
318
  }
221
319
  }
222
320
  return blocks;
223
321
  }
224
- function readSections(body, context, rels) {
322
+ function readSections(body, context, rels, pkg) {
225
323
  const sections = [];
226
324
  let currentBlocks = [];
227
325
  for (const node of body.children) {
@@ -240,6 +338,7 @@ function readSections(body, context, rels) {
240
338
  const sectPr = pPr === void 0 ? void 0 : childrenWithTag(pPr, "w:sectPr")[0];
241
339
  if (hasPageBreakBefore(node)) currentBlocks.push({ kind: "pageBreak" });
242
340
  currentBlocks.push(readParagraph(node, context, rels));
341
+ currentBlocks.push(...readParagraphImages(node, rels, pkg));
243
342
  if (sectPr !== void 0) {
244
343
  sections.push({
245
344
  pageSize: readPageSize(sectPr),
@@ -250,7 +349,7 @@ function readSections(body, context, rels) {
250
349
  }
251
350
  continue;
252
351
  }
253
- currentBlocks.push(...readBodyBlocks([node], context, rels));
352
+ currentBlocks.push(...readBodyBlocks([node], context, rels, pkg));
254
353
  }
255
354
  if (currentBlocks.length > 0 || sections.length === 0) sections.push({
256
355
  pageSize: PAGE_SIZE_LETTER,
@@ -317,11 +416,12 @@ function readDocx(pkg) {
317
416
  };
318
417
  return {
319
418
  metadata: readCoreProperties(pkg),
320
- sections: readSections(body, context, docRels),
419
+ sections: readSections(body, context, docRels, pkg),
321
420
  comments: readComments(pkg),
322
421
  footnotes: readFootnotes(pkg),
323
422
  headers: readHeaderFooterText(pkg, "word/header"),
324
- footers: readHeaderFooterText(pkg, "word/footer")
423
+ footers: readHeaderFooterText(pkg, "word/footer"),
424
+ numbering: readNumberingDefinitions(pkg)
325
425
  };
326
426
  }
327
427
  //#endregion
@@ -34,8 +34,32 @@ function readUnderline(u) {
34
34
  const val = require_typed_util.attr(u, "w:val");
35
35
  return val !== void 0 && val !== "none";
36
36
  }
37
- function readRunColor(colorEl) {
37
+ const THEME_COLOR_SLOT = /* @__PURE__ */ new Map([
38
+ ["dark1", "dk1"],
39
+ ["light1", "lt1"],
40
+ ["dark2", "dk2"],
41
+ ["light2", "lt2"],
42
+ ["accent1", "accent1"],
43
+ ["accent2", "accent2"],
44
+ ["accent3", "accent3"],
45
+ ["accent4", "accent4"],
46
+ ["accent5", "accent5"],
47
+ ["accent6", "accent6"],
48
+ ["hyperlink", "hlink"],
49
+ ["followedHyperlink", "folHlink"],
50
+ ["background1", "lt1"],
51
+ ["text1", "dk1"],
52
+ ["background2", "lt2"],
53
+ ["text2", "dk2"]
54
+ ]);
55
+ function readRunColor(colorEl, theme) {
38
56
  if (colorEl === void 0) return;
57
+ const themeColor = require_typed_util.attr(colorEl, "w:themeColor");
58
+ if (themeColor !== void 0) {
59
+ const slot = THEME_COLOR_SLOT.get(themeColor);
60
+ const resolved = slot === void 0 ? void 0 : theme.colorScheme.get(slot);
61
+ if (resolved !== void 0) return resolved;
62
+ }
39
63
  const val = require_typed_util.attr(colorEl, "w:val");
40
64
  return val === void 0 || val === "auto" ? void 0 : (0, document_schema_js.rgbHexToColor)(val);
41
65
  }
@@ -58,7 +82,7 @@ function readRunPropertiesLayer(rPr, theme) {
58
82
  strike: readToggle(require_typed_util.childrenWithTag(rPr, "w:strike")[0]),
59
83
  fontFamily: readRunFontFamily(require_typed_util.childrenWithTag(rPr, "w:rFonts")[0], theme),
60
84
  sizePt: szVal === void 0 ? void 0 : require_typed_shared_units.halfPointsToPt(Number(szVal)),
61
- color: readRunColor(require_typed_util.childrenWithTag(rPr, "w:color")[0])
85
+ color: readRunColor(require_typed_util.childrenWithTag(rPr, "w:color")[0], theme)
62
86
  };
63
87
  }
64
88
  function readAlignment(jc) {
@@ -33,8 +33,32 @@ function readUnderline(u) {
33
33
  const val = attr(u, "w:val");
34
34
  return val !== void 0 && val !== "none";
35
35
  }
36
- function readRunColor(colorEl) {
36
+ const THEME_COLOR_SLOT = /* @__PURE__ */ new Map([
37
+ ["dark1", "dk1"],
38
+ ["light1", "lt1"],
39
+ ["dark2", "dk2"],
40
+ ["light2", "lt2"],
41
+ ["accent1", "accent1"],
42
+ ["accent2", "accent2"],
43
+ ["accent3", "accent3"],
44
+ ["accent4", "accent4"],
45
+ ["accent5", "accent5"],
46
+ ["accent6", "accent6"],
47
+ ["hyperlink", "hlink"],
48
+ ["followedHyperlink", "folHlink"],
49
+ ["background1", "lt1"],
50
+ ["text1", "dk1"],
51
+ ["background2", "lt2"],
52
+ ["text2", "dk2"]
53
+ ]);
54
+ function readRunColor(colorEl, theme) {
37
55
  if (colorEl === void 0) return;
56
+ const themeColor = attr(colorEl, "w:themeColor");
57
+ if (themeColor !== void 0) {
58
+ const slot = THEME_COLOR_SLOT.get(themeColor);
59
+ const resolved = slot === void 0 ? void 0 : theme.colorScheme.get(slot);
60
+ if (resolved !== void 0) return resolved;
61
+ }
38
62
  const val = attr(colorEl, "w:val");
39
63
  return val === void 0 || val === "auto" ? void 0 : rgbHexToColor(val);
40
64
  }
@@ -57,7 +81,7 @@ function readRunPropertiesLayer(rPr, theme) {
57
81
  strike: readToggle(childrenWithTag(rPr, "w:strike")[0]),
58
82
  fontFamily: readRunFontFamily(childrenWithTag(rPr, "w:rFonts")[0], theme),
59
83
  sizePt: szVal === void 0 ? void 0 : halfPointsToPt(Number(szVal)),
60
- color: readRunColor(childrenWithTag(rPr, "w:color")[0])
84
+ color: readRunColor(childrenWithTag(rPr, "w:color")[0], theme)
61
85
  };
62
86
  }
63
87
  function readAlignment(jc) {
@@ -169,9 +169,10 @@ function resolveShapeFrame(shape, context, parentTransform) {
169
169
  widthPt: xfrm.widthPt,
170
170
  heightPt: xfrm.heightPt
171
171
  };
172
+ const rotationDeg = require_typed_shared_drawingml.composeShapeRotationDeg(parentTransform, xfrm.rotationDeg);
172
173
  return {
173
174
  frame: parentTransform === void 0 ? localFrame : require_typed_shared_drawingml.applyGroupTransform(parentTransform, localFrame),
174
- rotationDeg: xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg
175
+ rotationDeg: rotationDeg === 0 ? void 0 : rotationDeg
175
176
  };
176
177
  }
177
178
  function readSpShape(sp, context, slideRels, parentTransform) {
@@ -260,7 +261,8 @@ function readGraphicFrameShape(gf, context, slideRels, parentTransform) {
260
261
  heightPt: xfrm.heightPt
261
262
  };
262
263
  const frame = parentTransform === void 0 ? localFrame : require_typed_shared_drawingml.applyGroupTransform(parentTransform, localFrame);
263
- const rotationDeg = xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg;
264
+ const composedRotationDeg = require_typed_shared_drawingml.composeShapeRotationDeg(parentTransform, xfrm.rotationDeg);
265
+ const rotationDeg = composedRotationDeg === 0 ? void 0 : composedRotationDeg;
264
266
  const graphic = require_typed_util.childrenWithTag(gf, "a:graphic")[0];
265
267
  const graphicData = graphic === void 0 ? void 0 : require_typed_util.childrenWithTag(graphic, "a:graphicData")[0];
266
268
  const tbl = (graphicData === void 0 ? void 0 : require_typed_util.attr(graphicData, "uri")) === TABLE_GRAPHIC_URI && graphicData !== void 0 ? require_typed_util.childrenWithTag(graphicData, "a:tbl")[0] : void 0;
@@ -287,28 +289,11 @@ function walkShapeTreeChildren(children, parentTransform, context, slideRels, pk
287
289
  if (shape !== void 0) out.push(shape);
288
290
  } else if (node.tag === "p:grpSp") {
289
291
  const grpSpPr = require_typed_util.childrenWithTag(node, "p:grpSpPr")[0];
290
- const composed = composeGroupTransform(require_typed_shared_drawingml.readGroupXfrm(grpSpPr === void 0 ? void 0 : require_typed_util.childrenWithTag(grpSpPr, "a:xfrm")[0]), parentTransform);
292
+ const composed = require_typed_shared_drawingml.composeGroupTransform(require_typed_shared_drawingml.readGroupXfrm(grpSpPr === void 0 ? void 0 : require_typed_util.childrenWithTag(grpSpPr, "a:xfrm")[0]), parentTransform);
291
293
  walkShapeTreeChildren(node.children, composed, context, slideRels, pkg, out);
292
294
  }
293
295
  }
294
296
  }
295
- function composeGroupTransform(own, parent) {
296
- if (own === void 0) return;
297
- if (parent === void 0) return own;
298
- const absolute = require_typed_shared_drawingml.applyGroupTransform(parent, {
299
- xPt: own.offXPt,
300
- yPt: own.offYPt,
301
- widthPt: own.extWidthPt,
302
- heightPt: own.extHeightPt
303
- });
304
- return {
305
- ...own,
306
- offXPt: absolute.xPt,
307
- offYPt: absolute.yPt,
308
- extWidthPt: absolute.widthPt,
309
- extHeightPt: absolute.heightPt
310
- };
311
- }
312
297
  const NOTES_SLIDE_REL_SUFFIX = "/notesSlide";
313
298
  function readNotes(pkg, slidePath) {
314
299
  let notesPath;
@@ -3,7 +3,7 @@ import { attr, childrenWithTag, elementsWithTag, resolveRelationships, rootEleme
3
3
  import { DocumentMetadataSchema, readCoreProperties } from "../shared/metadata.js";
4
4
  import { sniffImageFormat } from "../../image/sniff.js";
5
5
  import { drawingMlFontSizeToPt, emuToPt } from "../shared/units.js";
6
- import { applyGroupTransform, readGroupXfrm, readSolidFillColor, readXfrm } from "../shared/drawingml.js";
6
+ import { applyGroupTransform, composeGroupTransform, composeShapeRotationDeg, readGroupXfrm, readSolidFillColor, readXfrm } from "../shared/drawingml.js";
7
7
  import { assignSourcePaths } from "../shared/source-path.js";
8
8
  import { readPlaceholderKey, readRunPropertiesFromElement, resolveDefaultRunProperties, resolvePlaceholderXfrm, resolveSlideInheritance } from "./inherit.js";
9
9
  import { z } from "zod";
@@ -168,9 +168,10 @@ function resolveShapeFrame(shape, context, parentTransform) {
168
168
  widthPt: xfrm.widthPt,
169
169
  heightPt: xfrm.heightPt
170
170
  };
171
+ const rotationDeg = composeShapeRotationDeg(parentTransform, xfrm.rotationDeg);
171
172
  return {
172
173
  frame: parentTransform === void 0 ? localFrame : applyGroupTransform(parentTransform, localFrame),
173
- rotationDeg: xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg
174
+ rotationDeg: rotationDeg === 0 ? void 0 : rotationDeg
174
175
  };
175
176
  }
176
177
  function readSpShape(sp, context, slideRels, parentTransform) {
@@ -259,7 +260,8 @@ function readGraphicFrameShape(gf, context, slideRels, parentTransform) {
259
260
  heightPt: xfrm.heightPt
260
261
  };
261
262
  const frame = parentTransform === void 0 ? localFrame : applyGroupTransform(parentTransform, localFrame);
262
- const rotationDeg = xfrm.rotationDeg === 0 ? void 0 : xfrm.rotationDeg;
263
+ const composedRotationDeg = composeShapeRotationDeg(parentTransform, xfrm.rotationDeg);
264
+ const rotationDeg = composedRotationDeg === 0 ? void 0 : composedRotationDeg;
263
265
  const graphic = childrenWithTag(gf, "a:graphic")[0];
264
266
  const graphicData = graphic === void 0 ? void 0 : childrenWithTag(graphic, "a:graphicData")[0];
265
267
  const tbl = (graphicData === void 0 ? void 0 : attr(graphicData, "uri")) === TABLE_GRAPHIC_URI && graphicData !== void 0 ? childrenWithTag(graphicData, "a:tbl")[0] : void 0;
@@ -291,23 +293,6 @@ function walkShapeTreeChildren(children, parentTransform, context, slideRels, pk
291
293
  }
292
294
  }
293
295
  }
294
- function composeGroupTransform(own, parent) {
295
- if (own === void 0) return;
296
- if (parent === void 0) return own;
297
- const absolute = applyGroupTransform(parent, {
298
- xPt: own.offXPt,
299
- yPt: own.offYPt,
300
- widthPt: own.extWidthPt,
301
- heightPt: own.extHeightPt
302
- });
303
- return {
304
- ...own,
305
- offXPt: absolute.xPt,
306
- offYPt: absolute.yPt,
307
- extWidthPt: absolute.widthPt,
308
- extHeightPt: absolute.heightPt
309
- };
310
- }
311
296
  const NOTES_SLIDE_REL_SUFFIX = "/notesSlide";
312
297
  function readNotes(pkg, slidePath) {
313
298
  let notesPath;
@@ -164,22 +164,129 @@ function readGroupXfrm(xfrm) {
164
164
  childOffXPt: require_typed_shared_units.emuToPt(Number(cx)),
165
165
  childOffYPt: require_typed_shared_units.emuToPt(Number(cy)),
166
166
  childExtWidthPt: require_typed_shared_units.emuToPt(Number(ccx)),
167
- childExtHeightPt: require_typed_shared_units.emuToPt(Number(ccy))
167
+ childExtHeightPt: require_typed_shared_units.emuToPt(Number(ccy)),
168
+ rotationDeg: base.rotationDeg,
169
+ flipH: base.flipH,
170
+ flipV: base.flipV
171
+ };
172
+ }
173
+ function normalizeDeg(deg) {
174
+ const mod = deg % 360;
175
+ return mod < 0 ? mod + 360 : mod;
176
+ }
177
+ function canonicalizeGroupRotation(rotationDeg, flipH, flipV) {
178
+ if (flipH && flipV) return {
179
+ angleDeg: rotationDeg + 180,
180
+ mirrored: false
181
+ };
182
+ if (flipV) return {
183
+ angleDeg: rotationDeg + 180,
184
+ mirrored: true
185
+ };
186
+ if (flipH) return {
187
+ angleDeg: rotationDeg,
188
+ mirrored: true
189
+ };
190
+ return {
191
+ angleDeg: rotationDeg,
192
+ mirrored: false
193
+ };
194
+ }
195
+ function composeRotation(outer, inner) {
196
+ if (!outer.mirrored) return {
197
+ angleDeg: normalizeDeg(outer.angleDeg + inner.angleDeg),
198
+ mirrored: inner.mirrored
199
+ };
200
+ return {
201
+ angleDeg: normalizeDeg(outer.angleDeg - inner.angleDeg),
202
+ mirrored: !inner.mirrored
203
+ };
204
+ }
205
+ function composeGroupTransform(own, parent) {
206
+ if (own === void 0) return;
207
+ const ownRotation = canonicalizeGroupRotation(own.rotationDeg, own.flipH, own.flipV);
208
+ if (parent === void 0) return {
209
+ offXPt: own.offXPt,
210
+ offYPt: own.offYPt,
211
+ extWidthPt: own.extWidthPt,
212
+ extHeightPt: own.extHeightPt,
213
+ childOffXPt: own.childOffXPt,
214
+ childOffYPt: own.childOffYPt,
215
+ childExtWidthPt: own.childExtWidthPt,
216
+ childExtHeightPt: own.childExtHeightPt,
217
+ compositeRotationDeg: normalizeDeg(ownRotation.angleDeg),
218
+ compositeMirrored: ownRotation.mirrored
219
+ };
220
+ const mapped = applyGroupTransform(parent, {
221
+ xPt: own.offXPt,
222
+ yPt: own.offYPt,
223
+ widthPt: own.extWidthPt,
224
+ heightPt: own.extHeightPt
225
+ });
226
+ const composite = composeRotation({
227
+ angleDeg: parent.compositeRotationDeg,
228
+ mirrored: parent.compositeMirrored
229
+ }, ownRotation);
230
+ return {
231
+ offXPt: mapped.xPt,
232
+ offYPt: mapped.yPt,
233
+ extWidthPt: mapped.widthPt,
234
+ extHeightPt: mapped.heightPt,
235
+ childOffXPt: own.childOffXPt,
236
+ childOffYPt: own.childOffYPt,
237
+ childExtWidthPt: own.childExtWidthPt,
238
+ childExtHeightPt: own.childExtHeightPt,
239
+ compositeRotationDeg: composite.angleDeg,
240
+ compositeMirrored: composite.mirrored
168
241
  };
169
242
  }
170
243
  function applyGroupTransform(group, childFrame) {
171
244
  const scaleX = group.childExtWidthPt === 0 ? 1 : group.extWidthPt / group.childExtWidthPt;
172
245
  const scaleY = group.childExtHeightPt === 0 ? 1 : group.extHeightPt / group.childExtHeightPt;
246
+ const widthPt = childFrame.widthPt * scaleX;
247
+ const heightPt = childFrame.heightPt * scaleY;
248
+ const canonicalX = group.offXPt + (childFrame.xPt - group.childOffXPt) * scaleX;
249
+ const canonicalY = group.offYPt + (childFrame.yPt - group.childOffYPt) * scaleY;
250
+ if (group.compositeRotationDeg === 0 && !group.compositeMirrored) return {
251
+ xPt: canonicalX,
252
+ yPt: canonicalY,
253
+ widthPt,
254
+ heightPt
255
+ };
256
+ const groupCenterX = group.offXPt + group.extWidthPt / 2;
257
+ const groupCenterY = group.offYPt + group.extHeightPt / 2;
258
+ const boxCenterX = canonicalX + widthPt / 2;
259
+ const boxCenterY = canonicalY + heightPt / 2;
260
+ let dx = boxCenterX - groupCenterX;
261
+ const dy = boxCenterY - groupCenterY;
262
+ if (group.compositeMirrored) dx = -dx;
263
+ const rad = group.compositeRotationDeg * Math.PI / 180;
264
+ const cos = Math.cos(rad);
265
+ const sin = Math.sin(rad);
266
+ const rotatedX = dx * cos - dy * sin;
267
+ const rotatedY = dx * sin + dy * cos;
173
268
  return {
174
- xPt: group.offXPt + (childFrame.xPt - group.childOffXPt) * scaleX,
175
- yPt: group.offYPt + (childFrame.yPt - group.childOffYPt) * scaleY,
176
- widthPt: childFrame.widthPt * scaleX,
177
- heightPt: childFrame.heightPt * scaleY
269
+ xPt: groupCenterX + rotatedX - widthPt / 2,
270
+ yPt: groupCenterY + rotatedY - heightPt / 2,
271
+ widthPt,
272
+ heightPt
178
273
  };
179
274
  }
275
+ function composeShapeRotationDeg(parentTransform, ownRotationDeg) {
276
+ if (parentTransform === void 0) return normalizeDeg(ownRotationDeg);
277
+ return composeRotation({
278
+ angleDeg: parentTransform.compositeRotationDeg,
279
+ mirrored: parentTransform.compositeMirrored
280
+ }, {
281
+ angleDeg: ownRotationDeg,
282
+ mirrored: false
283
+ }).angleDeg;
284
+ }
180
285
  //#endregion
181
286
  exports.EMPTY_THEME = EMPTY_THEME;
182
287
  exports.applyGroupTransform = applyGroupTransform;
288
+ exports.composeGroupTransform = composeGroupTransform;
289
+ exports.composeShapeRotationDeg = composeShapeRotationDeg;
183
290
  exports.readColorMap = readColorMap;
184
291
  exports.readGroupXfrm = readGroupXfrm;
185
292
  exports.readSchemeColor = readSchemeColor;
@@ -24,6 +24,20 @@ declare function resolveSchemeColorSlot(schemeVal: string, colorMap: ReadonlyMap
24
24
  declare function readSchemeColor(schemeClrEl: XmlElement, colorMap: ReadonlyMap<string, string>, theme: DrawingTheme): Color | undefined;
25
25
  declare function readSrgbColor(srgbClrEl: XmlElement): Color | undefined;
26
26
  declare function readSolidFillColor(solidFillEl: XmlElement | undefined, colorMap: ReadonlyMap<string, string>, theme: DrawingTheme): Color | undefined;
27
+ interface GroupOwnXfrm {
28
+ readonly offXPt: number;
29
+ readonly offYPt: number;
30
+ readonly extWidthPt: number;
31
+ readonly extHeightPt: number;
32
+ readonly childOffXPt: number;
33
+ readonly childOffYPt: number;
34
+ readonly childExtWidthPt: number;
35
+ readonly childExtHeightPt: number;
36
+ readonly rotationDeg: number;
37
+ readonly flipH: boolean;
38
+ readonly flipV: boolean;
39
+ }
40
+ declare function readGroupXfrm(xfrm: XmlElement | undefined): GroupOwnXfrm | undefined;
27
41
  interface GroupChildTransform {
28
42
  readonly offXPt: number;
29
43
  readonly offYPt: number;
@@ -33,8 +47,11 @@ interface GroupChildTransform {
33
47
  readonly childOffYPt: number;
34
48
  readonly childExtWidthPt: number;
35
49
  readonly childExtHeightPt: number;
50
+ readonly compositeRotationDeg: number;
51
+ readonly compositeMirrored: boolean;
36
52
  }
37
- declare function readGroupXfrm(xfrm: XmlElement | undefined): GroupChildTransform | undefined;
53
+ declare function composeGroupTransform(own: GroupOwnXfrm | undefined, parent: GroupChildTransform | undefined): GroupChildTransform | undefined;
38
54
  declare function applyGroupTransform(group: GroupChildTransform, childFrame: Box): Box;
55
+ declare function composeShapeRotationDeg(parentTransform: GroupChildTransform | undefined, ownRotationDeg: number): number;
39
56
  //#endregion
40
- export { DrawingTheme, DrawingXfrm, EMPTY_THEME, GroupChildTransform, applyGroupTransform, readColorMap, readGroupXfrm, readSchemeColor, readSolidFillColor, readSrgbColor, readTheme, readXfrm, resolveSchemeColorSlot, resolveThemeFontReference };
57
+ export { DrawingTheme, DrawingXfrm, EMPTY_THEME, GroupChildTransform, GroupOwnXfrm, applyGroupTransform, composeGroupTransform, composeShapeRotationDeg, readColorMap, readGroupXfrm, readSchemeColor, readSolidFillColor, readSrgbColor, readTheme, readXfrm, resolveSchemeColorSlot, resolveThemeFontReference };
@@ -24,6 +24,20 @@ declare function resolveSchemeColorSlot(schemeVal: string, colorMap: ReadonlyMap
24
24
  declare function readSchemeColor(schemeClrEl: XmlElement, colorMap: ReadonlyMap<string, string>, theme: DrawingTheme): Color | undefined;
25
25
  declare function readSrgbColor(srgbClrEl: XmlElement): Color | undefined;
26
26
  declare function readSolidFillColor(solidFillEl: XmlElement | undefined, colorMap: ReadonlyMap<string, string>, theme: DrawingTheme): Color | undefined;
27
+ interface GroupOwnXfrm {
28
+ readonly offXPt: number;
29
+ readonly offYPt: number;
30
+ readonly extWidthPt: number;
31
+ readonly extHeightPt: number;
32
+ readonly childOffXPt: number;
33
+ readonly childOffYPt: number;
34
+ readonly childExtWidthPt: number;
35
+ readonly childExtHeightPt: number;
36
+ readonly rotationDeg: number;
37
+ readonly flipH: boolean;
38
+ readonly flipV: boolean;
39
+ }
40
+ declare function readGroupXfrm(xfrm: XmlElement | undefined): GroupOwnXfrm | undefined;
27
41
  interface GroupChildTransform {
28
42
  readonly offXPt: number;
29
43
  readonly offYPt: number;
@@ -33,8 +47,11 @@ interface GroupChildTransform {
33
47
  readonly childOffYPt: number;
34
48
  readonly childExtWidthPt: number;
35
49
  readonly childExtHeightPt: number;
50
+ readonly compositeRotationDeg: number;
51
+ readonly compositeMirrored: boolean;
36
52
  }
37
- declare function readGroupXfrm(xfrm: XmlElement | undefined): GroupChildTransform | undefined;
53
+ declare function composeGroupTransform(own: GroupOwnXfrm | undefined, parent: GroupChildTransform | undefined): GroupChildTransform | undefined;
38
54
  declare function applyGroupTransform(group: GroupChildTransform, childFrame: Box): Box;
55
+ declare function composeShapeRotationDeg(parentTransform: GroupChildTransform | undefined, ownRotationDeg: number): number;
39
56
  //#endregion
40
- export { DrawingTheme, DrawingXfrm, EMPTY_THEME, GroupChildTransform, applyGroupTransform, readColorMap, readGroupXfrm, readSchemeColor, readSolidFillColor, readSrgbColor, readTheme, readXfrm, resolveSchemeColorSlot, resolveThemeFontReference };
57
+ export { DrawingTheme, DrawingXfrm, EMPTY_THEME, GroupChildTransform, GroupOwnXfrm, applyGroupTransform, composeGroupTransform, composeShapeRotationDeg, readColorMap, readGroupXfrm, readSchemeColor, readSolidFillColor, readSrgbColor, readTheme, readXfrm, resolveSchemeColorSlot, resolveThemeFontReference };