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.
- package/dist/esm/core/bidi/segments.js +1 -2
- package/dist/esm/core/converter/facade.d.ts +5 -0
- package/dist/esm/core/converter/project.js +5 -1
- package/dist/esm/core/converter/ream.d.ts +6 -0
- package/dist/esm/core/converter/ream.js +34 -8
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +659 -7
- package/dist/esm/core/drawingml/chart-geometry.d.ts +34 -10
- package/dist/esm/core/drawingml/chart-geometry.js +424 -92
- package/dist/esm/core/drawingml/chart-parser.js +301 -11
- package/dist/esm/core/drawingml/colors.d.ts +7 -7
- package/dist/esm/core/drawingml/colors.js +84 -18
- package/dist/esm/core/drawingml/preset-geometry.js +240 -6
- package/dist/esm/core/drawingml/shape-render.d.ts +12 -0
- package/dist/esm/core/drawingml/shape-render.js +116 -3
- package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
- package/dist/esm/core/drawingml/theme-parser.d.ts +51 -0
- package/dist/esm/core/drawingml/theme-parser.js +92 -1
- package/dist/esm/core/font/measure.d.ts +5 -0
- package/dist/esm/core/font/measure.js +21 -1
- package/dist/esm/core/font/ttf-subset.js +26 -1
- package/dist/esm/core/images.d.ts +2 -2
- package/dist/esm/core/images.js +353 -43
- package/dist/esm/core/indexed-colors.d.ts +11 -0
- package/dist/esm/core/indexed-colors.js +81 -0
- package/dist/esm/core/ir/flow.d.ts +23 -1
- package/dist/esm/core/ir/sheet.d.ts +61 -0
- package/dist/esm/{excel → core}/number-format.d.ts +37 -0
- package/dist/esm/core/number-format.js +800 -0
- package/dist/esm/core/numbering/apply.d.ts +5 -3
- package/dist/esm/core/numbering/apply.js +42 -11
- package/dist/esm/core/numbering/index.js +2 -0
- package/dist/esm/core/numbering/state.d.ts +13 -1
- package/dist/esm/core/numbering/state.js +256 -15
- package/dist/esm/core/opc/alternate-content.d.ts +13 -0
- package/dist/esm/core/opc/alternate-content.js +72 -0
- package/dist/esm/core/opc/core-properties.js +1 -0
- package/dist/esm/core/opc/package.d.ts +14 -1
- package/dist/esm/core/opc/package.js +43 -4
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/opc/xml-entities.d.ts +12 -0
- package/dist/esm/core/opc/xml-entities.js +91 -0
- package/dist/esm/core/po-helpers.js +16 -1
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
- package/dist/esm/core/style-cascade/resolver.js +66 -11
- package/dist/esm/core/style-cascade/table.js +35 -11
- package/dist/esm/core/style-cascade/types.d.ts +42 -1
- package/dist/esm/core/style-cascade/types.js +4 -0
- package/dist/esm/core/vector.d.ts +30 -0
- package/dist/esm/excel/activex-parser.js +1 -0
- package/dist/esm/excel/column-bands.d.ts +26 -1
- package/dist/esm/excel/column-bands.js +156 -20
- package/dist/esm/excel/comments-parser.js +5 -3
- package/dist/esm/excel/conditional-format.d.ts +25 -2
- package/dist/esm/excel/conditional-format.js +63 -19
- package/dist/esm/excel/escaped-text.d.ts +9 -0
- package/dist/esm/excel/escaped-text.js +20 -0
- package/dist/esm/excel/form-control-parser.js +1 -0
- package/dist/esm/excel/formula/dates.js +1 -1
- package/dist/esm/excel/header-footer.d.ts +9 -1
- package/dist/esm/excel/header-footer.js +162 -14
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/index.js +2 -2
- package/dist/esm/excel/pivot-table-parser.js +1 -0
- package/dist/esm/excel/print-model.d.ts +75 -0
- package/dist/esm/excel/print-model.js +899 -77
- package/dist/esm/excel/printer-settings.d.ts +16 -0
- package/dist/esm/excel/printer-settings.js +36 -0
- package/dist/esm/excel/rich-value.d.ts +13 -0
- package/dist/esm/excel/rich-value.js +120 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -7
- package/dist/esm/excel/sheet-drawing.d.ts +11 -0
- package/dist/esm/excel/sheet-drawing.js +26 -3
- package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
- package/dist/esm/excel/sheet-shape-parser.js +461 -32
- package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
- package/dist/esm/excel/sheet-to-flow.js +553 -36
- package/dist/esm/excel/slicer-parser.js +1 -0
- package/dist/esm/excel/styles-parser.d.ts +30 -2
- package/dist/esm/excel/styles-parser.js +177 -40
- package/dist/esm/excel/table-parser.js +1 -0
- package/dist/esm/excel/vml-drawing.d.ts +68 -0
- package/dist/esm/excel/vml-drawing.js +158 -0
- package/dist/esm/excel/workbook-parser.d.ts +5 -0
- package/dist/esm/excel/workbook-parser.js +5 -1
- package/dist/esm/excel/worksheet-parser.d.ts +2 -1
- package/dist/esm/excel/worksheet-parser.js +150 -61
- package/dist/esm/excel/xlsx-reader.js +242 -11
- package/dist/esm/excel/xlsx-to-pdf.js +12 -1
- package/dist/esm/html/html-writer.js +29 -6
- package/dist/esm/layout/page-doc.d.ts +87 -1
- package/dist/esm/layout/styled-layout.d.ts +46 -2
- package/dist/esm/layout/styled-layout.js +2345 -274
- package/dist/esm/pdf/cid-font.js +20 -9
- package/dist/esm/pdf/objects.d.ts +13 -0
- package/dist/esm/pdf/objects.js +18 -1
- package/dist/esm/pdf/shading.js +76 -6
- package/dist/esm/pdf/styled-page-emitter.js +355 -49
- package/dist/esm/pdf/text-page-renderer.js +1 -0
- package/dist/esm/pdf/vector-graphics.d.ts +31 -2
- package/dist/esm/pdf/vector-graphics.js +103 -3
- package/dist/esm/pptx/pptx-reader.js +2 -0
- package/dist/esm/pptx/slide-parser.d.ts +21 -4
- package/dist/esm/pptx/slide-parser.js +98 -24
- package/dist/esm/svg/svg-writer.js +23 -4
- package/dist/esm/word/document-parser.d.ts +96 -7
- package/dist/esm/word/document-parser.js +538 -116
- package/dist/esm/word/docx-reader.js +135 -43
- package/dist/esm/word/docx-writer.js +6 -1
- package/dist/esm/word/drawing-parser.d.ts +86 -5
- package/dist/esm/word/drawing-parser.js +1590 -54
- package/dist/esm/word/index.d.ts +4 -4
- package/dist/esm/word/numbering-parser.d.ts +2 -1
- package/dist/esm/word/numbering-parser.js +108 -21
- package/dist/esm/word/paragraph-properties.d.ts +11 -1
- package/dist/esm/word/paragraph-properties.js +219 -10
- package/dist/esm/word/run-properties.js +45 -1
- package/dist/esm/word/settings-parser.d.ts +24 -0
- package/dist/esm/word/settings-parser.js +32 -5
- package/dist/esm/word/shading.d.ts +11 -0
- package/dist/esm/word/shading.js +64 -0
- package/dist/esm/word/styles-parser.js +9 -2
- package/dist/esm/word/table-parser.d.ts +9 -1
- package/dist/esm/word/table-parser.js +182 -30
- package/package.json +7 -3
- 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
|
-
|
|
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 {
|
|
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"
|
|
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"
|
|
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
|
-
|
|
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
|