reamkit 1.15.4 → 1.17.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 (127) hide show
  1. package/dist/esm/core/bidi/segments.js +1 -2
  2. package/dist/esm/core/converter/facade.d.ts +5 -0
  3. package/dist/esm/core/converter/project.js +5 -1
  4. package/dist/esm/core/converter/ream.d.ts +6 -0
  5. package/dist/esm/core/converter/ream.js +34 -8
  6. package/dist/esm/core/document-model/index.d.ts +1 -1
  7. package/dist/esm/core/document-model/types.d.ts +659 -7
  8. package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
  9. package/dist/esm/core/drawingml/chart-geometry.js +424 -92
  10. package/dist/esm/core/drawingml/chart-parser.js +301 -11
  11. package/dist/esm/core/drawingml/colors.d.ts +7 -7
  12. package/dist/esm/core/drawingml/colors.js +84 -18
  13. package/dist/esm/core/drawingml/preset-geometry.js +240 -6
  14. package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
  15. package/dist/esm/core/drawingml/shape-render.js +116 -3
  16. package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
  17. package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
  18. package/dist/esm/core/drawingml/theme-parser.js +92 -1
  19. package/dist/esm/core/font/measure.d.ts +5 -0
  20. package/dist/esm/core/font/measure.js +21 -1
  21. package/dist/esm/core/font/ttf-subset.js +26 -1
  22. package/dist/esm/core/images.d.ts +2 -2
  23. package/dist/esm/core/images.js +353 -43
  24. package/dist/esm/core/indexed-colors.d.ts +11 -0
  25. package/dist/esm/core/indexed-colors.js +81 -0
  26. package/dist/esm/core/ir/flow.d.ts +23 -1
  27. package/dist/esm/core/ir/sheet.d.ts +61 -0
  28. package/dist/esm/{excel → core}/number-format.d.ts +37 -0
  29. package/dist/esm/core/number-format.js +800 -0
  30. package/dist/esm/core/numbering/apply.d.ts +5 -3
  31. package/dist/esm/core/numbering/apply.js +42 -11
  32. package/dist/esm/core/numbering/index.js +2 -0
  33. package/dist/esm/core/numbering/state.d.ts +13 -1
  34. package/dist/esm/core/numbering/state.js +256 -15
  35. package/dist/esm/core/opc/alternate-content.d.ts +13 -0
  36. package/dist/esm/core/opc/alternate-content.js +72 -0
  37. package/dist/esm/core/opc/core-properties.js +1 -0
  38. package/dist/esm/core/opc/package.d.ts +14 -1
  39. package/dist/esm/core/opc/package.js +43 -4
  40. package/dist/esm/core/opc/relationships.js +1 -0
  41. package/dist/esm/core/opc/xml-entities.d.ts +12 -0
  42. package/dist/esm/core/opc/xml-entities.js +91 -0
  43. package/dist/esm/core/po-helpers.js +16 -1
  44. package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
  45. package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
  46. package/dist/esm/core/style-cascade/resolver.js +66 -11
  47. package/dist/esm/core/style-cascade/table.js +35 -11
  48. package/dist/esm/core/style-cascade/types.d.ts +42 -1
  49. package/dist/esm/core/style-cascade/types.js +4 -0
  50. package/dist/esm/core/vector.d.ts +30 -0
  51. package/dist/esm/excel/activex-parser.js +1 -0
  52. package/dist/esm/excel/column-bands.d.ts +26 -1
  53. package/dist/esm/excel/column-bands.js +156 -20
  54. package/dist/esm/excel/comments-parser.js +5 -3
  55. package/dist/esm/excel/conditional-format.d.ts +25 -2
  56. package/dist/esm/excel/conditional-format.js +63 -19
  57. package/dist/esm/excel/escaped-text.d.ts +9 -0
  58. package/dist/esm/excel/escaped-text.js +20 -0
  59. package/dist/esm/excel/form-control-parser.js +1 -0
  60. package/dist/esm/excel/formula/dates.js +1 -1
  61. package/dist/esm/excel/header-footer.d.ts +9 -1
  62. package/dist/esm/excel/header-footer.js +162 -14
  63. package/dist/esm/excel/index.d.ts +1 -1
  64. package/dist/esm/excel/index.js +2 -2
  65. package/dist/esm/excel/pivot-table-parser.js +1 -0
  66. package/dist/esm/excel/print-model.d.ts +75 -0
  67. package/dist/esm/excel/print-model.js +899 -77
  68. package/dist/esm/excel/printer-settings.d.ts +16 -0
  69. package/dist/esm/excel/printer-settings.js +36 -0
  70. package/dist/esm/excel/rich-value.d.ts +13 -0
  71. package/dist/esm/excel/rich-value.js +120 -0
  72. package/dist/esm/excel/shared-strings-parser.js +11 -7
  73. package/dist/esm/excel/sheet-drawing.d.ts +11 -0
  74. package/dist/esm/excel/sheet-drawing.js +26 -3
  75. package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
  76. package/dist/esm/excel/sheet-shape-parser.js +461 -32
  77. package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
  78. package/dist/esm/excel/sheet-to-flow.js +553 -36
  79. package/dist/esm/excel/slicer-parser.js +1 -0
  80. package/dist/esm/excel/styles-parser.d.ts +30 -2
  81. package/dist/esm/excel/styles-parser.js +177 -40
  82. package/dist/esm/excel/table-parser.js +1 -0
  83. package/dist/esm/excel/vml-drawing.d.ts +68 -0
  84. package/dist/esm/excel/vml-drawing.js +158 -0
  85. package/dist/esm/excel/workbook-parser.d.ts +5 -0
  86. package/dist/esm/excel/workbook-parser.js +5 -1
  87. package/dist/esm/excel/worksheet-parser.d.ts +2 -1
  88. package/dist/esm/excel/worksheet-parser.js +150 -61
  89. package/dist/esm/excel/xlsx-reader.js +242 -11
  90. package/dist/esm/excel/xlsx-to-pdf.js +12 -1
  91. package/dist/esm/html/html-writer.js +29 -6
  92. package/dist/esm/layout/page-doc.d.ts +87 -1
  93. package/dist/esm/layout/styled-layout.d.ts +46 -2
  94. package/dist/esm/layout/styled-layout.js +2345 -274
  95. package/dist/esm/pdf/cid-font.js +20 -9
  96. package/dist/esm/pdf/objects.d.ts +13 -0
  97. package/dist/esm/pdf/objects.js +18 -1
  98. package/dist/esm/pdf/shading.js +76 -6
  99. package/dist/esm/pdf/styled-page-emitter.js +355 -49
  100. package/dist/esm/pdf/text-page-renderer.js +1 -0
  101. package/dist/esm/pdf/vector-graphics.d.ts +31 -2
  102. package/dist/esm/pdf/vector-graphics.js +103 -3
  103. package/dist/esm/pptx/pptx-reader.js +2 -0
  104. package/dist/esm/pptx/slide-parser.d.ts +21 -4
  105. package/dist/esm/pptx/slide-parser.js +98 -24
  106. package/dist/esm/svg/svg-writer.js +23 -4
  107. package/dist/esm/word/document-parser.d.ts +96 -7
  108. package/dist/esm/word/document-parser.js +538 -116
  109. package/dist/esm/word/docx-reader.js +135 -43
  110. package/dist/esm/word/docx-writer.js +6 -1
  111. package/dist/esm/word/drawing-parser.d.ts +86 -5
  112. package/dist/esm/word/drawing-parser.js +1590 -54
  113. package/dist/esm/word/index.d.ts +4 -4
  114. package/dist/esm/word/numbering-parser.d.ts +2 -1
  115. package/dist/esm/word/numbering-parser.js +108 -21
  116. package/dist/esm/word/paragraph-properties.d.ts +11 -1
  117. package/dist/esm/word/paragraph-properties.js +219 -10
  118. package/dist/esm/word/run-properties.js +45 -1
  119. package/dist/esm/word/settings-parser.d.ts +24 -0
  120. package/dist/esm/word/settings-parser.js +32 -5
  121. package/dist/esm/word/shading.d.ts +11 -0
  122. package/dist/esm/word/shading.js +64 -0
  123. package/dist/esm/word/styles-parser.js +9 -2
  124. package/dist/esm/word/table-parser.d.ts +9 -1
  125. package/dist/esm/word/table-parser.js +182 -30
  126. package/package.json +7 -3
  127. package/dist/esm/excel/number-format.js +0 -476
@@ -1,9 +1,10 @@
1
1
  import { ResourceStore } from "../core/ir/resources.js";
2
2
  import { FEATURES } from "../core/ir/features.js";
3
+ import { detectImageFormat } from "../core/images.js";
3
4
  import { bytesInclude, bytesIncludePartName } from "../core/bytes.js";
4
5
  import { DEFAULT_THEME_PALETTE, makeColorResolver } from "../core/drawingml/colors.js";
5
6
  import { parseChart, withChartColorStyle } from "../core/drawingml/chart-parser.js";
6
- import { parseTheme } from "../core/drawingml/theme-parser.js";
7
+ import { parseTheme, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths } from "../core/drawingml/theme-parser.js";
7
8
  import { isOoxmlRel } from "../core/opc/relationship-types.js";
8
9
  import { OpcPackage } from "../core/opc/package.js";
9
10
  import { parseCoreProperties } from "../core/opc/core-properties.js";
@@ -11,8 +12,8 @@ import "../core/opc/index.js";
11
12
  import { parseAreaRef } from "./defined-name-ref.js";
12
13
  import { parseSharedStrings } from "./shared-strings-parser.js";
13
14
  import { parseWorkbook } from "./workbook-parser.js";
14
- import { parseWorksheet } from "./worksheet-parser.js";
15
15
  import { EMPTY_XLSX_STYLES, parseXlsxStyles } from "./styles-parser.js";
16
+ import { parseWorksheet } from "./worksheet-parser.js";
16
17
  import "./index.js";
17
18
  import { resolveCellText } from "./print-model.js";
18
19
  import { parseSheetDrawing } from "./sheet-drawing.js";
@@ -21,14 +22,20 @@ import { parsePivotTablePart } from "./pivot-table-parser.js";
21
22
  import { parseSlicerCachePart, parseSlicerPart } from "./slicer-parser.js";
22
23
  import { parseLegacyComments, parsePersons, parseThreadedComments } from "./comments-parser.js";
23
24
  import { parseFormControlProps } from "./form-control-parser.js";
25
+ import { parseVmlDrawing } from "./vml-drawing.js";
26
+ import { parsePrinterSettings } from "./printer-settings.js";
27
+ import { parseRichValueText } from "./rich-value.js";
24
28
  import { activeXBinRelId, activeXType, activeXTypeFromPart, parseActiveX, parseActiveXBin } from "./activex-parser.js";
25
- import { parseSheetShapes } from "./sheet-shape-parser.js";
29
+ import { parseDiagramFrames, parseDiagramShapes, parseSheetShapes } from "./sheet-shape-parser.js";
26
30
  import { projectSheetDoc } from "./sheet-to-flow.js";
27
31
  //#region src/excel/xlsx-reader.ts
28
32
  var WORKBOOK_PART = "xl/workbook.xml";
29
33
  var SHARED_STRINGS_PART = "xl/sharedStrings.xml";
30
34
  var STYLES_PART = "xl/styles.xml";
31
35
  var CORE_PROPS_PART = "docProps/core.xml";
36
+ var METADATA_PART = "xl/metadata.xml";
37
+ var RICH_VALUE_STRUCTURE_PART = "xl/richData/rdrichvaluestructure.xml";
38
+ var RICH_VALUE_PART = "xl/richData/rdrichvalue.xml";
32
39
  var SLICER_REL_TAIL = "/slicer";
33
40
  var SLICER_CACHE_REL_TAIL = "/slicerCache";
34
41
  var THREADED_COMMENTS_REL_TAIL = "/threadedComment";
@@ -80,9 +87,11 @@ function readXlsxToSheetDoc(xlsx) {
80
87
  texts: [],
81
88
  runs: []
82
89
  };
83
- const stylesData = pkg.getPart(STYLES_PART);
84
- const styles = stylesData ? parseXlsxStyles(stylesData) : EMPTY_XLSX_STYLES;
85
90
  const workbookRels = pkg.getPartRelationships(WORKBOOK_PART);
91
+ const themePalette = buildThemePalette(pkg, workbookRels);
92
+ const richValueText = parseRichValueText(pkg.getPart(METADATA_PART), pkg.getPart(RICH_VALUE_STRUCTURE_PART), pkg.getPart(RICH_VALUE_PART));
93
+ const stylesData = pkg.getPart(STYLES_PART);
94
+ const styles = stylesData ? parseXlsxStyles(stylesData, themePalette) : EMPTY_XLSX_STYLES;
86
95
  const persons = /* @__PURE__ */ new Map();
87
96
  for (const rel of workbookRels) {
88
97
  if (!rel.type.endsWith(PERSON_REL_TAIL)) continue;
@@ -93,7 +102,12 @@ function readXlsxToSheetDoc(xlsx) {
93
102
  const resources = new ResourceStore();
94
103
  const palette = buildThemePalette(pkg, workbookRels);
95
104
  const resolveColor = makeColorResolver(palette);
105
+ const themeLineWidths = buildThemeLineWidths(pkg, workbookRels);
106
+ const themeFillStyles = buildThemeFillStyles(pkg, workbookRels);
107
+ const themeEffectStyles = buildThemeEffectStyles(pkg, workbookRels);
96
108
  const sheetsOut = [];
109
+ let embeddedObjects = 0;
110
+ let metafilePictures = 0;
97
111
  const tableIndex = /* @__PURE__ */ new Map();
98
112
  const pendingSlicers = [];
99
113
  for (let sheetIdx = 0; sheetIdx < sheets.length; sheetIdx++) {
@@ -102,7 +116,9 @@ function readXlsxToSheetDoc(xlsx) {
102
116
  if (!sheetRel) continue;
103
117
  const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, sheetRel);
104
118
  if (!resolved) continue;
105
- const worksheet = parseWorksheet(resolved.data);
119
+ let worksheet = parseWorksheet(resolved.data, themePalette);
120
+ worksheet = withPrinterPageSetup(worksheet, pkg, resolved.path, pkg.getPartRelationships(resolved.path));
121
+ worksheet = withRichValues(worksheet, richValueText);
106
122
  const charts = [];
107
123
  const images = [];
108
124
  let shapes;
@@ -121,22 +137,39 @@ function readXlsxToSheetDoc(xlsx) {
121
137
  charts.push({
122
138
  chartPartPath: ref.chartPartPath,
123
139
  widthPt: ref.widthPt,
124
- heightPt: ref.heightPt
140
+ heightPt: ref.heightPt,
141
+ xPt: ref.xPt,
142
+ yPt: ref.yPt
125
143
  });
126
144
  }
127
145
  for (const pic of pictures) {
128
146
  const bytes = pkg.getPart(pic.imagePartPath);
129
147
  if (!bytes) continue;
148
+ if (detectImageFormat(bytes) === null) metafilePictures++;
130
149
  images.push({
131
150
  resourceId: resources.put(bytes),
132
151
  widthPt: pic.widthPt,
133
- heightPt: pic.heightPt
152
+ heightPt: pic.heightPt,
153
+ xPt: pic.xPt,
154
+ yPt: pic.yPt
134
155
  });
135
156
  }
136
157
  if (bytesInclude(drawing.data, ":sp>") || bytesInclude(drawing.data, ":sp ")) {
137
- const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor);
158
+ const parsed = parseSheetShapes(drawing.data, worksheet, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles);
138
159
  if (parsed.length > 0) shapes = parsed;
139
160
  }
161
+ const frames = parseDiagramFrames(drawing.data, worksheet);
162
+ if (frames.length > 0) {
163
+ const dsp = pkg.getPartRelationships(drawing.path).filter((r) => r.type.endsWith("/diagramDrawing"));
164
+ const fromDiagrams = [];
165
+ frames.forEach((frame, i) => {
166
+ const rel = dsp[i];
167
+ const part = rel ? pkg.resolveRelatedPart(drawing.path, rel) : void 0;
168
+ if (!part) return;
169
+ fromDiagrams.push(...parseDiagramShapes(part.data, frame, resolveColor, themeLineWidths, themeFillStyles, themeEffectStyles));
170
+ });
171
+ if (fromDiagrams.length > 0) shapes = [...shapes ?? [], ...fromDiagrams];
172
+ }
140
173
  }
141
174
  }
142
175
  let tables;
@@ -233,29 +266,40 @@ function readXlsxToSheetDoc(xlsx) {
233
266
  ...props
234
267
  };
235
268
  };
269
+ const legacyVml = readLegacyVml(pkg, resolved.path, wsRels, worksheet);
236
270
  let formControls;
237
271
  if (worksheet.formControls && worksheet.formControls.length > 0) {
238
272
  const resolvedControls = [];
239
273
  for (const fc of worksheet.formControls) {
274
+ if (fc.print === false) continue;
275
+ if (fc.shapeId !== void 0 && legacyVml.nonPrinting.has(fc.shapeId)) continue;
240
276
  const rel = wsRels.find((r) => r.id === fc.relId);
241
277
  const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
278
+ const box = fc.shapeId !== void 0 ? legacyVml.boxes.get(fc.shapeId) : void 0;
242
279
  if (part && ACTIVEX_PART.test(part.path)) {
243
280
  resolvedAx.push({
244
281
  ...activeXState(part),
245
282
  type: activeXTypeFromPart(part.data),
246
- ...fc.name ? { name: fc.name } : {}
283
+ ...fc.name ? { name: fc.name } : {},
284
+ ...box ? { box } : {}
247
285
  });
248
286
  continue;
249
287
  }
250
288
  const props = part ? parseFormControlProps(part.data) : {};
251
289
  resolvedControls.push({
252
290
  ...fc.name ? { name: fc.name } : {},
253
- ...props
291
+ ...props,
292
+ ...box ? { box } : {}
254
293
  });
255
294
  }
256
295
  if (resolvedControls.length > 0) formControls = resolvedControls;
257
296
  }
297
+ if (legacyVml.controls.length > 0) formControls = [...formControls ?? [], ...legacyVml.controls];
258
298
  if (worksheet.oleObjects && worksheet.oleObjects.length > 0) for (const ole of worksheet.oleObjects) {
299
+ if (!/^Forms\./i.test(ole.progId ?? "")) {
300
+ embeddedObjects++;
301
+ continue;
302
+ }
259
303
  const rel = wsRels.find((r) => r.id === ole.relId);
260
304
  const part = rel ? pkg.resolveRelatedPart(resolved.path, rel) : void 0;
261
305
  resolvedAx.push({
@@ -271,6 +315,7 @@ function readXlsxToSheetDoc(xlsx) {
271
315
  } : worksheet;
272
316
  sheetsOut.push({
273
317
  name: sheet.name,
318
+ ...sheet.hidden ? { hidden: true } : {},
274
319
  grid,
275
320
  ...charts.length > 0 ? { charts } : {},
276
321
  ...images.length > 0 ? { images } : {},
@@ -299,6 +344,10 @@ function readXlsxToSheetDoc(xlsx) {
299
344
  };
300
345
  }
301
346
  }
347
+ for (const [path, chart] of chartData) {
348
+ const resolved = withWorkbookData(chart, sheetsOut, styles, sharedStrings, date1904);
349
+ if (resolved !== chart) chartData.set(path, resolved);
350
+ }
302
351
  const coreData = pkg.getPart(CORE_PROPS_PART);
303
352
  const info = infoFromCore(coreData ? parseCoreProperties(coreData) : void 0);
304
353
  return {
@@ -311,9 +360,167 @@ function readXlsxToSheetDoc(xlsx) {
311
360
  date1904,
312
361
  ...chartData.size > 0 ? { chartData } : {},
313
362
  resources,
363
+ themePalette,
364
+ ...embeddedObjects > 0 ? { embeddedObjects } : {},
365
+ ...metafilePictures > 0 ? { metafilePictures } : {},
314
366
  ...info ? { info } : {}
315
367
  };
316
368
  }
369
+ /**
370
+ * Fill in the paper size and orientation a `<pageSetup>` leaves to its
371
+ * `printerSettings` part.
372
+ *
373
+ * `<pageSetup>` naming no `paperSize` does not mean "the default": Excel
374
+ * records the print dialog's choice in the DEVMODE of the related part, and
375
+ * LibreOffice reads it. simple-monthly-budget.xlsx and 45540_classic_Header.xlsx
376
+ * both print on Letter that way while we assumed A4 — the most visible
377
+ * difference on every page of either. What the sheet states itself always wins.
378
+ */
379
+ /**
380
+ * Replace the legacy stand-in in every cell that points at a rich value we can
381
+ * read. Spill.xlsx caches `#VALUE!` in three cells whose rich value says
382
+ * `#SPILL!` — the error Excel shows and the one that explains the sheet, since
383
+ * the file also records which cell three rows down does the blocking.
384
+ *
385
+ * @param worksheet The parsed worksheet.
386
+ * @param richValueText `vm` index → text, from {@link parseRichValueText}.
387
+ * @returns The worksheet, unchanged when nothing resolved (byte-identical path).
388
+ */
389
+ /**
390
+ * A chart with its uncached references resolved against the workbook.
391
+ *
392
+ * Only what is missing is filled in: a series that cached its values keeps
393
+ * them, and a reference naming a sheet this workbook does not have resolves to
394
+ * nothing rather than to zeros.
395
+ *
396
+ * @param chart The parsed chart.
397
+ * @param sheets Every sheet in the workbook, by tab order.
398
+ * @param styles The style table (for a referenced cell's number format).
399
+ * @param sharedStrings The shared-string table.
400
+ * @param date1904 The workbook's date system.
401
+ * @returns The chart, unchanged when nothing needed resolving.
402
+ */
403
+ function withWorkbookData(chart, sheets, styles, sharedStrings, date1904) {
404
+ const cellsOf = (ref) => {
405
+ if (ref === void 0) return void 0;
406
+ const area = resolveChartRef(ref, sheets);
407
+ if (!area) return void 0;
408
+ const out = [];
409
+ for (let row = area.startRow; row <= area.endRow; row++) for (let col = area.startColumn; col <= area.endColumn; col++) {
410
+ const cell = area.grid.cells.find((c) => c.row === row && c.column === col);
411
+ out.push(cell ? resolveCellText(cell, sharedStrings, styles, date1904) : "");
412
+ }
413
+ return out;
414
+ };
415
+ let changed = false;
416
+ const series = chart.series.map((s) => {
417
+ if (s.values.length > 0 && s.name !== void 0) return s;
418
+ const values = s.values.length > 0 ? s.values : cellsOf(s.valuesRef)?.map((t) => Number(t) || 0);
419
+ const name = s.name ?? cellsOf(s.nameRef)?.find((t) => t.length > 0);
420
+ if (!values && name === void 0) return s;
421
+ changed = true;
422
+ return {
423
+ ...s,
424
+ ...values ? { values } : {},
425
+ ...name !== void 0 ? { name } : {}
426
+ };
427
+ });
428
+ const categories = chart.categories.length > 0 ? chart.categories : cellsOf(chart.categoriesRef);
429
+ if (categories && categories.length > 0 && chart.categories.length === 0) changed = true;
430
+ if (!changed) return chart;
431
+ return {
432
+ ...chart,
433
+ series,
434
+ ...categories && categories.length > 0 ? { categories } : {}
435
+ };
436
+ }
437
+ /** `Sheet!A1:B2` → the sheet's grid and the 0-based rectangle it names. */
438
+ function resolveChartRef(ref, sheets) {
439
+ const bang = ref.lastIndexOf("!");
440
+ if (bang < 0) return void 0;
441
+ const name = ref.slice(0, bang).replace(/^'|'$/g, "").replace(/''/g, "'");
442
+ const sheet = sheets.find((s) => s.name === name);
443
+ if (!sheet) return void 0;
444
+ const area = parseAreaRef(ref.slice(bang + 1).replace(/\$/g, ""));
445
+ return area ? {
446
+ grid: sheet.grid,
447
+ ...area
448
+ } : void 0;
449
+ }
450
+ function withRichValues(worksheet, richValueText) {
451
+ if (richValueText.size === 0) return worksheet;
452
+ const resolves = (cell) => cell.valueMetadataIndex !== void 0 ? richValueText.get(cell.valueMetadataIndex) : void 0;
453
+ if (!worksheet.cells.some((cell) => resolves(cell) !== void 0)) return worksheet;
454
+ const cells = worksheet.cells.map((cell) => {
455
+ const text = resolves(cell);
456
+ return text === void 0 ? cell : {
457
+ ...cell,
458
+ rawValue: text
459
+ };
460
+ });
461
+ return {
462
+ ...worksheet,
463
+ cells
464
+ };
465
+ }
466
+ function withPrinterPageSetup(worksheet, pkg, sheetPath, wsRels) {
467
+ const setup = worksheet.pageSetup;
468
+ const relId = setup?.printerSettingsRelId;
469
+ if (!setup || relId === void 0) return worksheet;
470
+ const { printerSettingsRelId: _resolved, ...rest } = setup;
471
+ const rel = wsRels.find((r) => r.id === relId);
472
+ const part = rel ? pkg.resolveRelatedPart(sheetPath, rel) : void 0;
473
+ const printer = part ? parsePrinterSettings(part.data) : {};
474
+ return {
475
+ ...worksheet,
476
+ pageSetup: {
477
+ ...rest,
478
+ ...rest.paperSize === void 0 && printer.paperSize !== void 0 ? { paperSize: printer.paperSize } : {},
479
+ ...rest.orientation === void 0 && printer.orientation !== void 0 ? { orientation: printer.orientation } : {}
480
+ }
481
+ };
482
+ }
483
+ /**
484
+ * The sheet's form controls that live only in its legacy VML drawing (§18.3.1.36).
485
+ *
486
+ * Shapes that back an ActiveX control are skipped — their `o:spid` is the
487
+ * `shapeId` of a `<control>` element, which the caller has already resolved
488
+ * through the activeX part. What is left is the Forms-toolbar kind, whose
489
+ * caption and checked state exist nowhere else in the package.
490
+ */
491
+ function readLegacyVml(pkg, sheetPath, wsRels, worksheet) {
492
+ const empty = {
493
+ controls: [],
494
+ boxes: /* @__PURE__ */ new Map(),
495
+ nonPrinting: /* @__PURE__ */ new Set()
496
+ };
497
+ const relId = worksheet.legacyDrawingRelId;
498
+ if (relId === void 0) return empty;
499
+ const rel = wsRels.find((r) => r.id === relId);
500
+ const part = rel ? pkg.resolveRelatedPart(sheetPath, rel) : void 0;
501
+ if (!part) return empty;
502
+ const activeXShapeIds = new Set((worksheet.formControls ?? []).map((fc) => fc.shapeId).filter((id) => id !== void 0));
503
+ const drawing = parseVmlDrawing(part.data);
504
+ const out = [];
505
+ for (const shape of drawing.controls) {
506
+ if (shape.shapeId !== void 0 && activeXShapeIds.has(shape.shapeId)) continue;
507
+ out.push({
508
+ objectType: shape.objectType,
509
+ ...shape.caption ? {
510
+ name: shape.caption,
511
+ caption: shape.caption
512
+ } : {},
513
+ ...shape.checked ? { checked: true } : {},
514
+ ...shape.box ? { box: shape.box } : {},
515
+ ...shape.fontSizePt !== void 0 ? { fontSizePt: shape.fontSizePt } : {}
516
+ });
517
+ }
518
+ return {
519
+ controls: out,
520
+ boxes: drawing.boxes,
521
+ nonPrinting: drawing.nonPrinting
522
+ };
523
+ }
317
524
  function buildThemePalette(pkg, workbookRels) {
318
525
  const palette = new Map(DEFAULT_THEME_PALETTE);
319
526
  for (const rel of workbookRels) {
@@ -325,6 +532,30 @@ function buildThemePalette(pkg, workbookRels) {
325
532
  }
326
533
  return palette;
327
534
  }
535
+ function buildThemeLineWidths(pkg, workbookRels) {
536
+ for (const rel of workbookRels) {
537
+ if (!isOoxmlRel(rel.type, "theme")) continue;
538
+ const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, rel);
539
+ if (resolved) return parseThemeLineWidths(resolved.data);
540
+ }
541
+ return [];
542
+ }
543
+ function buildThemeEffectStyles(pkg, workbookRels) {
544
+ for (const rel of workbookRels) {
545
+ if (!isOoxmlRel(rel.type, "theme")) continue;
546
+ const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, rel);
547
+ if (resolved) return parseThemeEffectStyles(resolved.data);
548
+ }
549
+ return [];
550
+ }
551
+ function buildThemeFillStyles(pkg, workbookRels) {
552
+ for (const rel of workbookRels) {
553
+ if (!isOoxmlRel(rel.type, "theme")) continue;
554
+ const resolved = pkg.resolveRelatedPart(WORKBOOK_PART, rel);
555
+ if (resolved) return parseThemeFillStyles(resolved.data);
556
+ }
557
+ return [];
558
+ }
328
559
  function resolveTableStyle(t, palette) {
329
560
  const m = t.styleName ? /TableStyle(Light|Medium|Dark)(\d+)/i.exec(t.styleName) : null;
330
561
  if (!m) return t;
@@ -1,5 +1,6 @@
1
1
  import { fetchFontSet } from "../core/fonts/remote-fonts.js";
2
2
  import { FontRegistry } from "../core/font/font-registry.js";
3
+ import { createFontMeasure } from "../core/font/measure.js";
3
4
  import { signPdf } from "../pdf/signature.js";
4
5
  import { renderStyledPdf, renderStyledPdfEncrypted } from "../pdf/styled-page-renderer.js";
5
6
  import "../pdf/index.js";
@@ -7,6 +8,11 @@ import { readXlsx } from "./xlsx-reader.js";
7
8
  import { flowRenderOptions } from "../core/converter/project.js";
8
9
  //#region src/excel/xlsx-to-pdf.ts
9
10
  /**
11
+ * The point size Excel's column-width unit is quoted at — its default theme
12
+ * font is 11 pt, and 8.43 of its digits are the documented 64 px column.
13
+ */
14
+ var DEFAULT_WORKBOOK_FONT_PT = 11;
15
+ /**
10
16
  * Convert a .xlsx to PDF in one shot.
11
17
  *
12
18
  * @deprecated Use `Ream.parse(bytes).convert('pdf', options)` — one parse,
@@ -45,7 +51,12 @@ function prepareXlsxStyledRender(xlsx, options) {
45
51
  const fonts = options.fonts ?? (options.fontBytes ? { regular: options.fontBytes } : void 0);
46
52
  if (!fonts) throw new Error("convertXlsxToPdfSync requires options.fonts or options.fontBytes");
47
53
  const registry = FontRegistry.fromBytes(fonts);
48
- const { doc: flow } = readXlsx(xlsx, options.now !== void 0 ? { now: options.now } : {});
54
+ const { parsed } = registry.resolveByStyle(false, false);
55
+ const digitWidthPt = createFontMeasure(parsed).textWidthPt("0", DEFAULT_WORKBOOK_FONT_PT);
56
+ const { doc: flow } = readXlsx(xlsx, {
57
+ ...options.now !== void 0 ? { now: options.now } : {},
58
+ digitWidthPt
59
+ });
49
60
  const { fontBytes: _ignoreA, fonts: _ignoreB, section: sectionOverride, info: callerInfo, embedSource, now: _ignoreNow, attachments: callerAttachments, signature: _ignoreSig, layoutProfile: _ignoreProfile, ...renderOptions } = options;
50
61
  const section = sectionOverride ?? flow.section;
51
62
  const info = flow.info || callerInfo ? {
@@ -106,7 +106,11 @@ function collectReferencedAnchors(body) {
106
106
  for (const el of els) if (el.kind === "paragraph") {
107
107
  for (const r of el.paragraph.runs) if (r.anchor !== void 0) out.add(r.anchor);
108
108
  } else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
109
- else if (el.kind === "shape" && el.shape.text) visit(el.shape.text.content);
109
+ else if (el.kind === "shape") visitShape(el.shape);
110
+ };
111
+ const visitShape = (shape) => {
112
+ if (shape.text) visit(shape.text.content);
113
+ for (const child of shape.children ?? []) visitShape(child.shape);
110
114
  };
111
115
  visit(body);
112
116
  return out;
@@ -122,7 +126,11 @@ function collectNoteNumbers(flow) {
122
126
  if (r.commentRef !== void 0 && !comments.has(r.commentRef)) comments.set(r.commentRef, comments.size + 1);
123
127
  }
124
128
  else if (el.kind === "table") for (const row of el.table.rows) for (const cell of row.cells) visit(cell.content);
125
- else if (el.kind === "shape" && el.shape.text) visit(el.shape.text.content);
129
+ else if (el.kind === "shape") visitShape(el.shape);
130
+ };
131
+ const visitShape = (shape) => {
132
+ if (shape.text) visit(shape.text.content);
133
+ for (const child of shape.children ?? []) visitShape(child.shape);
126
134
  };
127
135
  visit(flow.body);
128
136
  return {
@@ -265,9 +273,20 @@ function wedgeSvg(w) {
265
273
  return `<path d="${svgPathData(b.build().segments, fmt)}" fill="#${w.fillHex}"${stroke}/>`;
266
274
  }
267
275
  function labelSvg(l, sceneH, anchor) {
268
- return `<text x="${fmt(l.x)}" y="${fmt(sceneH - l.y)}" font-size="${fmt(l.sizePt)}" font-family="sans-serif" fill="#${l.colorHex}" text-anchor="${anchor}">${escapeText(l.text)}</text>`;
276
+ const rot = l.rotationDeg ? ` transform="rotate(${fmt(-l.rotationDeg)} ${fmt(l.x)} ${fmt(sceneH - l.y)})"` : "";
277
+ return `<text x="${fmt(l.x)}" y="${fmt(sceneH - l.y)}"${rot} font-size="${fmt(l.sizePt)}" font-family="sans-serif" fill="#${l.colorHex}" text-anchor="${anchor}">${escapeText(l.text)}</text>`;
278
+ }
279
+ /** `RRGGBB` as the `r,g,b` triple a CSS `rgba()` takes. */
280
+ function hexToRgbCss(hex) {
281
+ const n = parseInt(hex, 16);
282
+ return `${String(n >> 16 & 255)},${String(n >> 8 & 255)},${String(n & 255)}`;
269
283
  }
270
284
  function emitShapeBlock(out, shape, ctx) {
285
+ const children = shape.children ?? [];
286
+ if (!(children.length > 0 && shape.fill.kind === "none" && shape.line === void 0 && (shape.text?.content.length ?? 0) === 0)) emitOneShape(out, shape, ctx);
287
+ for (const child of children) emitShapeBlock(out, child.shape, ctx);
288
+ }
289
+ function emitOneShape(out, shape, ctx) {
271
290
  const w = shape.width;
272
291
  const h = shape.height;
273
292
  const paths = buildShapePaths(shape.geometry, w, h);
@@ -278,9 +297,11 @@ function emitShapeBlock(out, shape, ctx) {
278
297
  const transform = ` transform="matrix(${flipTransform(buildShapeTransform(0, 0, w, h, t?.rotation60k ?? 0, t?.flipH ?? false, t?.flipV ?? false), h).map(fmt).join(" ")})"`;
279
298
  const svg = [svgOpen(w, h, shape.altText)];
280
299
  if (gradDef) svg.push(`<defs>${gradDef}</defs>`);
300
+ const shadow = shape.shadow;
301
+ const shadowFilter = shadow ? ` filter="drop-shadow(${fmt(shadow.dxPt)}px ${fmt(shadow.dyPt)}px ${fmt(shadow.blurPt / 2)}px rgba(${hexToRgbCss(shadow.colorHex)},${fmt(shadow.alpha)}))"` : "";
281
302
  for (const path of paths) {
282
303
  const rule = path.fillRule === "evenodd" ? " fill-rule=\"evenodd\"" : "";
283
- svg.push(`<path d="${svgPathData(path.segments, fmt)}" fill="${fill}"${rule}${stroke}${transform}/>`);
304
+ svg.push(`<path d="${svgPathData(path.segments, fmt)}" fill="${fill}"${rule}${stroke}${transform}${shadowFilter}/>`);
284
305
  }
285
306
  svg.push("</svg>");
286
307
  const figureCss = blockFigureCss(shape.paragraphProperties);
@@ -491,6 +512,7 @@ function emitCell(out, cell, table, ctx, pos) {
491
512
  pushBorder(css, "left", c?.left ?? (pos.firstCol ? t?.left : t?.insideV));
492
513
  pushBorder(css, "right", c?.right ?? (pos.lastCol ? t?.right : t?.insideV));
493
514
  if (cell.properties.shading) css.push(`background-color:#${cell.properties.shading.colorHex}`);
515
+ if (cell.properties.noWrap) css.push("white-space:nowrap", "overflow:hidden");
494
516
  if (cell.properties.dataBar) {
495
517
  const db = cell.properties.dataBar;
496
518
  const clamp = (n) => Math.max(0, Math.min(1, n));
@@ -611,7 +633,7 @@ function pieIconSvg(fill, color, empty) {
611
633
  function pushBorder(css, side, border) {
612
634
  if (!border || border.style === "none") return;
613
635
  const width = border.width ?? .5;
614
- const style = border.style === "double" ? "double" : border.style === "dotted" ? "dotted" : border.style === "dashed" ? "dashed" : "solid";
636
+ const style = border.style === "double" ? "double" : border.style === "dotted" ? "dotted" : border.style === "dashed" || border.style === "dashSmallGap" ? "dashed" : "solid";
615
637
  css.push(`border-${side}:${fmt(width)}pt ${style} #${border.colorHex ?? "000000"}`);
616
638
  }
617
639
  function emitImageBlock(out, image, ctx) {
@@ -629,7 +651,8 @@ function emitImageBlock(out, image, ctx) {
629
651
  var MIME_BY_FORMAT = {
630
652
  jpeg: "image/jpeg",
631
653
  png: "image/png",
632
- jpeg2000: "image/jp2"
654
+ jpeg2000: "image/jp2",
655
+ gif: "image/gif"
633
656
  };
634
657
  function dataUri(resource, store) {
635
658
  if (resource === void 0) return void 0;
@@ -1,7 +1,8 @@
1
+ import { BorderStyle, ImageCrop, PictureOutline, ShapeShadow } from '../core/document-model/index.js';
1
2
  import { Pt, ResourceId, ResourceStore } from '../core/ir/index.js';
2
3
  import { FontMeasure, ParsedTtf } from '../core/font/index.js';
3
4
  import { ResolvedParagraphProperties, ResolvedRunProperties } from '../core/style-cascade/index.js';
4
- import { PathSegment, VectorShape } from '../core/vector.js';
5
+ import { PathSegment, VectorPath, VectorShape } from '../core/vector.js';
5
6
  import { PreparedImage } from '../core/images.js';
6
7
  /** A font bound into a {@link LaidOutDocument}: the parsed face plus what layout/emit need from it. */
7
8
  export interface FontResource {
@@ -41,6 +42,17 @@ export interface TextToken {
41
42
  * element separate from the item body.
42
43
  */
43
44
  readonly listMarker?: true;
45
+ /**
46
+ * §17.3.3.1 — the token is the break of a `w:br w:type="column"`: what
47
+ * follows it belongs in the next column.
48
+ */
49
+ readonly columnBreak?: true;
50
+ /**
51
+ * §17.3.1.38 — the token IS a tab: its width is the distance to the stop it
52
+ * advances to, resolved once the line is known, and its text is whatever
53
+ * leader fills that gap.
54
+ */
55
+ readonly tab?: true;
44
56
  /**
45
57
  * The token falls inside a comment range (`commentRangeRefs`): the emitter
46
58
  * fills a soft highlight behind it (E-COMMENTS CM2c).
@@ -49,6 +61,12 @@ export interface TextToken {
49
61
  readonly resolvedRun: ResolvedRunProperties;
50
62
  readonly font: FontResource;
51
63
  readonly fontSizePt: number;
64
+ /**
65
+ * §17.3.2.42 / §18.4.2 `vertAlign` — how far off the baseline this token
66
+ * draws: positive for a superscript, negative for a subscript, absent on the
67
+ * baseline. The line's height is unchanged; only the glyphs move.
68
+ */
69
+ readonly risePt?: number;
52
70
  readonly widthPt: number;
53
71
  /**
54
72
  * UAX #9 embedding level of this token's characters (0 for pure-LTR docs).
@@ -62,6 +80,28 @@ export interface ImageToken {
62
80
  readonly imageResourceName: string;
63
81
  readonly widthPt: number;
64
82
  readonly heightPt: number;
83
+ /** §20.1.2.2.24 — the frame the picture is drawn with, when it has one. */
84
+ readonly outline?: PictureOutline;
85
+ /** §20.1.8.40 — the drop shadow under the picture, when it casts one. */
86
+ readonly shadow?: ShapeShadow;
87
+ /** §20.1.8.55 `a:srcRect` — the part of the source the frame shows. */
88
+ readonly crop?: ImageCrop;
89
+ /** §20.1.7.6 — degrees clockwise about the box's centre. */
90
+ readonly rotationDeg?: number;
91
+ /** §20.1.7.6 — the picture drawn mirrored in its box. */
92
+ readonly flipH?: boolean;
93
+ readonly flipV?: boolean;
94
+ /**
95
+ * §20.4.2.6 — where the picture itself sits inside the reserved box when the
96
+ * drawing asked for an effect extent: offsets from the box's left edge and
97
+ * from the baseline, plus the drawn size. Absent ⇒ the picture fills the box.
98
+ */
99
+ readonly drawBox?: {
100
+ readonly dxPt: number;
101
+ readonly dyPt: number;
102
+ readonly widthPt: number;
103
+ readonly heightPt: number;
104
+ };
65
105
  /** Constants kept to satisfy {@link Token} consumers — they never read these for images. */
66
106
  readonly isSpace: false;
67
107
  readonly bidiLevel: number;
@@ -114,6 +154,12 @@ export interface Line {
114
154
  readonly firstLine: boolean;
115
155
  readonly resolved: ResolvedParagraphProperties;
116
156
  isLastInParagraph: boolean;
157
+ /**
158
+ * ECMA-376 §17.15.1.35 — the line ends at a soft line break in a document
159
+ * that asked for `w:doNotExpandShiftReturn`, so justification leaves it at
160
+ * its natural width (as the paragraph's own last line is left).
161
+ */
162
+ readonly noJustify?: boolean;
117
163
  /**
118
164
  * Max ascent/descent contributed by math tokens (0 when none) — they straddle
119
165
  * the baseline, so the line height/descent must grow to fit them.
@@ -147,6 +193,11 @@ export interface ImageResource {
147
193
  * numbers — they are not page-frame coordinates.
148
194
  */
149
195
  export interface PageItemBase {
196
+ /**
197
+ * §20.4.2.3 — the float's `relativeHeight`. Items with one are sorted by it
198
+ * inside their layer before the page is written; the rest keep their order.
199
+ */
200
+ readonly z?: number;
150
201
  /**
151
202
  * Tagged PDF (§14.8): the logical structure node this item's content belongs
152
203
  * to. Set only on body content in tagged mode; undefined text in the line pass
@@ -167,6 +218,19 @@ export interface TextLineItem extends PageItemBase {
167
218
  readonly originX: Pt;
168
219
  /** Distance from the page TOP down to the text baseline. */
169
220
  readonly baselineY: Pt;
221
+ readonly clip?: {
222
+ readonly x: Pt;
223
+ readonly y: Pt;
224
+ readonly width: Pt;
225
+ readonly height: Pt;
226
+ };
227
+ /**
228
+ * Counter-clockwise rotation about `(originX, baselineY)`, in degrees. A
229
+ * value-axis title reads bottom-to-top in every reader (§21.2.2.216
230
+ * `c:title/c:tx/…/a:bodyPr@rot` = -5400000, i.e. 90°); drawn flat it sat over
231
+ * the plot's own tick labels. Absent ⇒ horizontal.
232
+ */
233
+ readonly rotationDeg?: number;
170
234
  }
171
235
  /** One edge of a table-cell frame; `(x, y)` is the cell box's top-left corner. */
172
236
  export interface BorderItem extends PageItemBase {
@@ -178,6 +242,12 @@ export interface BorderItem extends PageItemBase {
178
242
  readonly height: Pt;
179
243
  readonly borderSizePt: number;
180
244
  readonly borderColorHex: string;
245
+ /**
246
+ * §18.18.3 `ST_BorderStyle` — the rule's PATTERN, when it is not solid.
247
+ * `dashed`/`dotted` are line patterns, not weights, and dropping them here
248
+ * painted 57423.xlsx's dashed band as twelve continuous rules.
249
+ */
250
+ readonly borderStyle?: BorderStyle;
181
251
  }
182
252
  /** A filled rectangle (cell shading); `(x, y)` is its top-left corner. */
183
253
  export interface FillItem extends PageItemBase {
@@ -199,6 +269,22 @@ export interface ImageItem extends PageItemBase {
199
269
  readonly width: Pt;
200
270
  readonly height: Pt;
201
271
  readonly imageResourceName: string;
272
+ /** §20.1.8.55 `a:srcRect` — the part of the source the frame shows. */
273
+ readonly crop?: ImageCrop;
274
+ /** §20.1.7.6 — degrees clockwise about the box's centre. */
275
+ readonly rotationDeg?: number;
276
+ /** §20.1.7.6 — the picture drawn mirrored in its box. */
277
+ readonly flipH?: boolean;
278
+ readonly flipV?: boolean;
279
+ /**
280
+ * §20.1.8.14 — a picture FILL is the shape's outline painted with a picture,
281
+ * so it is clipped to that outline: the paths in the shape's local frame and
282
+ * the matrix that maps them onto the page.
283
+ */
284
+ readonly clip?: {
285
+ readonly paths: ReadonlyArray<VectorPath>;
286
+ readonly transform: readonly [number, number, number, number, number, number];
287
+ };
202
288
  }
203
289
  /**
204
290
  * DrawingML vector geometry. `shape.transform` maps the shape's local y-up frame