ooxml.js 4.6.0 → 4.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/typed/xlsx/drawings.cjs +118 -23
- package/dist/typed/xlsx/drawings.js +118 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -299,7 +299,7 @@ The package layers a lossless core outward to lossy convenience views:
|
|
|
299
299
|
- **A construct marker brackets whole blocks, never a sub-sequence of runs.** A construct covering a sub-sequence of one paragraph's runs lands on that paragraph's `constructs` field as a run range (see the fidelity-constructs section above) — bookmarks, fields, internal links, comment extents, note references, and `w:ffData` form fields alike. An inline SDT or a few inserted words inside an otherwise untouched paragraph are still read exactly as before — the text survives, the construct does not — as is a bookmark whose two halves sit in different paragraphs. So does a block extent that crosses another, or that straddles a section break or table-cell boundary: neither is expressible as balanced brackets (nor as a tree group, which is what the marker pair promotes to), and both are dropped — a drop `document-schema.js`'s extent-scope note ratifies — rather than emitted at a position that would decode to a different nesting.
|
|
300
300
|
- **The docx pair round-trips `sections`, not a whole `DocxDocument`.** Numbering definitions, cell border styling/shading, section break kinds (`w:sectPr/w:type` onto `ContentSection.breakType`, both directions), and `w:themeColor` (without `themeShade`/`themeTint`) are read; images read into `ContentImageBlock` (floating `wp:anchor` position not recorded); `PAGE`/`NUMPAGES` fields resolve to Word's cached text. Headers and footers are read both as the flat per-part text arrays the reader always produced and structurally — each referenced part as block flow (`headerFooterParts`) plus per-section default/first/even references (`sectionHeaderFooters`); collapsing the flat arrays into that model wants a breaking change to a published shape and is tracked rather than taken. An inline `w:object`/`o:OLEObject` whose payload part is itself a ZIP archive — a modern producer's embedded xlsx/docx/pptx, detected by magic bytes through `archive-codec` — or a classic OLE compound-file `.bin` whose root storage carries the embedded file as an OLE-packaged `Package` stream, read through `archive-codec`'s bounded CFB reader, is decoded into a nested content document and emitted as a `ContentEmbeddedObjectBlock` beside its containing paragraph's own block, sized from `w:dxaOrig`/`w:dyaOrig`; the object's VML preview picture (`v:imagedata`) and a `w:object` inside a footnote (notes ride as text, with no block flow to lift an object into — a header/footer's own objects DO recover, those parts being walked as block flow) are not read, a compound file holding native legacy streams (BIFF and friends — no `Package` stream, or a packaged file that is not a ZIP) stays opaque, and a payload that does not decode as one of the three OOXML flavours (a plain archive, corrupt zip or compound-file data, a bodyless docx) degrades to no embedded block rather than failing the host read. The writer emits such a block back out as the inverse `w:object`/`o:OLEObject`: the nested document is re-serialised through its own format's builder into a fresh `word/embeddings/oleObject<N>.<docx|xlsx|pptx>` ZIP part carrying its relationship and content-type override, and `w:dxaOrig`/`w:dyaOrig` are derived from the block's frame (twips). An embedded presentation document serialises through an injected port — `BuildDocxContentOptions.serialiseEmbeddedPresentation`, a presentation `ContentDocument` → pptx-bytes function this package accepts because it has no PresentationML writer of its own, and the ecosystem's one pptx writer lives one layer up in documents.js (which exports `embeddedPresentationSerialiser`, wired from its own pptx builder, for exactly this call); with no serialiser injected, a `ContentDocument` carrying one is refused with a thrown error rather than a silent drop, and no VML preview picture is regenerated (the reader never read one into the model, and real previews are WMF/EMF this ecosystem has no writer for; Word shows a blank until activated). The writer emits no `styles.xml`, `numbering.xml`, comments, footnotes, endnotes, or headers/footers, so the `DocxDocument` fields outside `sections` do not come back — a paragraph's `styleId` is still written as a `w:pStyle` reference, resolving to nothing, since every property the style would have contributed is already spelled as direct formatting by then.
|
|
301
301
|
- **pptx is read-only.** Connector shapes (`p:cxnSp`) are skipped; shape rotation composes through groups; a dynamic field (`a:fld`, e.g. slidenum/datetime) reads as an ordinary run plus a `field` run construct carrying `@type` as the instruction and the cached `a:t` as the result; an internal slide-jump link (`a:hlinkClick` resolving to a slide relationship, no `TargetMode`) records a `link` run construct with an internal target naming the destination slide's package part path (e.g. `ppt/slides/slide2.xml` — PresentationML addresses slides by part relationship, never by name; the flat run's `hyperlink` field stays reserved for external URIs, and an action-only `ppaction://hlinkshowjump` names no target part and records nothing); a chart graphic frame reads its chart part's cached series/category model into a table block (header row = series names, one row per category index); a SmartArt graphic frame reads its diagram data model's node text as paragraphs in diagram order (depth-first over `parOf` connections, siblings by `srcOrd`); an OLE graphic frame reads the fallback picture its `mc:Fallback` carries (or, with none reachable, a paragraph naming the `p:oleObj`'s `progId`), and when the payload part is itself a ZIP archive — a modern producer's embedded xlsx/docx/pptx, detected by magic bytes through `archive-codec` — or a classic OLE compound-file `.bin` whose root storage carries the embedded file as an OLE-packaged `Package` stream, read through `archive-codec`'s bounded CFB reader, also decodes it into a nested content document and emits it as an `embeddedObject` block beside the picture, sized to the frame's own geometry; a compound file holding native legacy streams (no `Package` stream, or a packaged file that is not a ZIP) stays opaque external-application data, and a payload that does not decode as one of the three OOXML flavours degrades to no embedded block rather than failing the slide read.
|
|
302
|
-
- **xlsx has no native percentage/currency/date/time cell type.** Both directions are closed via the number-format engine: reading classifies style → format code → kind; writing emits interned `numFmt` codes, fed back through the classifier in tests. `displayText` is the typed-value spelling, not the producer's rendered string. A chart graphic frame reads as an embedded `chart` object (`embeddedObjects`, one row per series over the shared category axis, values verbatim `c:v` text, frame resolved through the sheet's own column widths and row heights), and a drawing picture (`xdr:pic`) as a `ContentSheetImage` (`images`, media bytes sniffed through the drawing part's relationships, frame resolved the same way) — one-way rows, since the writer emits no drawing part. A workbook's general defined names and table/List objects ride the tree reader's root `definitions` table (`readXlsx`), the landing the schema's own verdict gives a named range; the flat reader and the write pair carry neither. `dataValidation` and `conditionalFormatting` rules quarantine verbatim on their range's anchor cell through the residue channel, pending the corpus-gated vocabulary the construct inventory defers.
|
|
302
|
+
- **xlsx has no native percentage/currency/date/time cell type.** Both directions are closed via the number-format engine: reading classifies style → format code → kind; writing emits interned `numFmt` codes, fed back through the classifier in tests. `displayText` is the typed-value spelling, not the producer's rendered string. A chart graphic frame reads as an embedded `chart` object (`embeddedObjects`, one row per series over the shared category axis, values verbatim `c:v` text, frame resolved through the sheet's own column widths and row heights), and a drawing picture (`xdr:pic`) as a `ContentSheetImage` (`images`, media bytes sniffed through the drawing part's relationships, frame resolved the same way) — both rows under any of the drawing's three anchor spellings (`twoCellAnchor` marker pairs, `oneCellAnchor` sized by its own `xdr:ext`, and `absoluteAnchor`, whose page-absolute `xdr:pos` is re-based into the cell anchor vocabulary through that same grid geometry) — one-way rows, since the writer emits no drawing part. A workbook's general defined names and table/List objects ride the tree reader's root `definitions` table (`readXlsx`), the landing the schema's own verdict gives a named range; the flat reader and the write pair carry neither. `dataValidation` and `conditionalFormatting` rules quarantine verbatim on their range's anchor cell through the residue channel, pending the corpus-gated vocabulary the construct inventory defers.
|
|
303
303
|
- **`test:smoke` depends on a fresh build.** It runs `tsdown && vitest run --project smoke`, always rebuilding `dist/` first. A bare `vitest` runs both projects; `smoke` fails loudly (`Cannot find module '../dist/index.js'`) if `dist/` is unbuilt.
|
|
304
304
|
- **Binary-vs-XML part classification is a byte sniff, not an extension check.** `looksLikeXml` looks for a leading `<` after skipping a UTF-8 BOM and whitespace; any future binary format starting with `<` would misclassify.
|
|
305
305
|
- **`Array.isArray` narrows `unknown` to `any[]`, not `unknown[]`.** Indexing the result reintroduces `any` and trips `no-unsafe-assignment`. `compact.ts` and `xml/parse.ts` each define a local `isUnknownArray` guard (`value is unknown[]`) — use it wherever the narrowed element is read.
|
|
@@ -55,6 +55,34 @@ var SheetGridGeometry = class {
|
|
|
55
55
|
for (let index = 0; index < row; index++) yPt += this.rowHeightPt(index);
|
|
56
56
|
return yPt;
|
|
57
57
|
}
|
|
58
|
+
locateColumn(xPt) {
|
|
59
|
+
let index = 0;
|
|
60
|
+
let boundaryPt = 0;
|
|
61
|
+
let widthPt = this.columnWidthPt(index);
|
|
62
|
+
while (boundaryPt + widthPt <= xPt) {
|
|
63
|
+
boundaryPt += widthPt;
|
|
64
|
+
index += 1;
|
|
65
|
+
widthPt = this.columnWidthPt(index);
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
index,
|
|
69
|
+
offsetPt: xPt - boundaryPt
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
locateRow(yPt) {
|
|
73
|
+
let index = 0;
|
|
74
|
+
let boundaryPt = 0;
|
|
75
|
+
let heightPt = this.rowHeightPt(index);
|
|
76
|
+
while (boundaryPt + heightPt <= yPt) {
|
|
77
|
+
boundaryPt += heightPt;
|
|
78
|
+
index += 1;
|
|
79
|
+
heightPt = this.rowHeightPt(index);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
index,
|
|
83
|
+
offsetPt: yPt - boundaryPt
|
|
84
|
+
};
|
|
85
|
+
}
|
|
58
86
|
};
|
|
59
87
|
function readAnchorChild(marker, tag) {
|
|
60
88
|
const child = require_typed_util.childrenWithTag(marker, tag)[0];
|
|
@@ -62,6 +90,11 @@ function readAnchorChild(marker, tag) {
|
|
|
62
90
|
const parsed = text === void 0 || text === "" ? NaN : Number(text);
|
|
63
91
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
64
92
|
}
|
|
93
|
+
function numericAttr(element, name) {
|
|
94
|
+
const raw = require_typed_util.attr(element, name);
|
|
95
|
+
const parsed = raw === void 0 ? NaN : Number(raw);
|
|
96
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
97
|
+
}
|
|
65
98
|
function readAnchorMarker(parent, tag) {
|
|
66
99
|
const marker = require_typed_util.childrenWithTag(parent, tag)[0];
|
|
67
100
|
if (marker === void 0) return;
|
|
@@ -72,6 +105,65 @@ function readAnchorMarker(parent, tag) {
|
|
|
72
105
|
rowOffEmu: readAnchorChild(marker, "xdr:rowOff")
|
|
73
106
|
};
|
|
74
107
|
}
|
|
108
|
+
function readAnchorExtEmu(anchor) {
|
|
109
|
+
const ext = require_typed_util.childrenWithTag(anchor, "xdr:ext")[0];
|
|
110
|
+
if (ext === void 0) return;
|
|
111
|
+
return {
|
|
112
|
+
cxEmu: numericAttr(ext, "cx"),
|
|
113
|
+
cyEmu: numericAttr(ext, "cy")
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function readAnchorPlacement(anchor, geometry) {
|
|
117
|
+
if (anchor.tag === "xdr:twoCellAnchor") {
|
|
118
|
+
const from = readAnchorMarker(anchor, "xdr:from");
|
|
119
|
+
const to = readAnchorMarker(anchor, "xdr:to");
|
|
120
|
+
if (from === void 0 || to === void 0) return;
|
|
121
|
+
const xPt = geometry.xPt(from.column, from.colOffEmu);
|
|
122
|
+
const yPt = geometry.yPt(from.row, from.rowOffEmu);
|
|
123
|
+
return {
|
|
124
|
+
xPt,
|
|
125
|
+
yPt,
|
|
126
|
+
widthPt: geometry.xPt(to.column, to.colOffEmu) - xPt,
|
|
127
|
+
heightPt: geometry.yPt(to.row, to.rowOffEmu) - yPt,
|
|
128
|
+
anchorRow: from.row,
|
|
129
|
+
anchorColumn: from.column,
|
|
130
|
+
offsetXPt: require_typed_shared_units.emuToPt(from.colOffEmu),
|
|
131
|
+
offsetYPt: require_typed_shared_units.emuToPt(from.rowOffEmu)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (anchor.tag === "xdr:oneCellAnchor") {
|
|
135
|
+
const from = readAnchorMarker(anchor, "xdr:from");
|
|
136
|
+
const ext = readAnchorExtEmu(anchor);
|
|
137
|
+
if (from === void 0 || ext === void 0) return;
|
|
138
|
+
return {
|
|
139
|
+
xPt: geometry.xPt(from.column, from.colOffEmu),
|
|
140
|
+
yPt: geometry.yPt(from.row, from.rowOffEmu),
|
|
141
|
+
widthPt: require_typed_shared_units.emuToPt(ext.cxEmu),
|
|
142
|
+
heightPt: require_typed_shared_units.emuToPt(ext.cyEmu),
|
|
143
|
+
anchorRow: from.row,
|
|
144
|
+
anchorColumn: from.column,
|
|
145
|
+
offsetXPt: require_typed_shared_units.emuToPt(from.colOffEmu),
|
|
146
|
+
offsetYPt: require_typed_shared_units.emuToPt(from.rowOffEmu)
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const pos = require_typed_util.childrenWithTag(anchor, "xdr:pos")[0];
|
|
150
|
+
const ext = readAnchorExtEmu(anchor);
|
|
151
|
+
if (pos === void 0 || ext === void 0) return;
|
|
152
|
+
const xPt = require_typed_shared_units.emuToPt(numericAttr(pos, "x"));
|
|
153
|
+
const yPt = require_typed_shared_units.emuToPt(numericAttr(pos, "y"));
|
|
154
|
+
const column = geometry.locateColumn(xPt);
|
|
155
|
+
const row = geometry.locateRow(yPt);
|
|
156
|
+
return {
|
|
157
|
+
xPt,
|
|
158
|
+
yPt,
|
|
159
|
+
widthPt: require_typed_shared_units.emuToPt(ext.cxEmu),
|
|
160
|
+
heightPt: require_typed_shared_units.emuToPt(ext.cyEmu),
|
|
161
|
+
anchorRow: row.index,
|
|
162
|
+
anchorColumn: column.index,
|
|
163
|
+
offsetXPt: column.offsetPt,
|
|
164
|
+
offsetYPt: row.offsetPt
|
|
165
|
+
};
|
|
166
|
+
}
|
|
75
167
|
function emptyWorksheet() {
|
|
76
168
|
return {
|
|
77
169
|
type: "element",
|
|
@@ -100,6 +192,11 @@ function chartCells(chartRoot, frame) {
|
|
|
100
192
|
});
|
|
101
193
|
return cells;
|
|
102
194
|
}
|
|
195
|
+
const ANCHOR_TAGS = [
|
|
196
|
+
"xdr:twoCellAnchor",
|
|
197
|
+
"xdr:oneCellAnchor",
|
|
198
|
+
"xdr:absoluteAnchor"
|
|
199
|
+
];
|
|
103
200
|
function readSheetDrawing(pkg, worksheetPath, worksheet) {
|
|
104
201
|
let drawingPath;
|
|
105
202
|
for (const rel of require_typed_util.resolveRelationships(pkg, worksheetPath).values()) if (rel.type.endsWith(DRAWING_REL_SUFFIX)) {
|
|
@@ -119,45 +216,43 @@ function readSheetDrawing(pkg, worksheetPath, worksheet) {
|
|
|
119
216
|
const geometry = new SheetGridGeometry(worksheet);
|
|
120
217
|
const objects = [];
|
|
121
218
|
const images = [];
|
|
122
|
-
for (const
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
const xPt = geometry.xPt(from.column, from.colOffEmu);
|
|
127
|
-
const yPt = geometry.yPt(from.row, from.rowOffEmu);
|
|
219
|
+
for (const node of drawingRoot.children) {
|
|
220
|
+
if (node.type !== "element" || !ANCHOR_TAGS.includes(node.tag)) continue;
|
|
221
|
+
const placement = readAnchorPlacement(node, geometry);
|
|
222
|
+
if (placement === void 0) continue;
|
|
128
223
|
const frameBox = {
|
|
129
|
-
xPt,
|
|
130
|
-
yPt,
|
|
131
|
-
widthPt:
|
|
132
|
-
heightPt:
|
|
224
|
+
xPt: placement.xPt,
|
|
225
|
+
yPt: placement.yPt,
|
|
226
|
+
widthPt: placement.widthPt,
|
|
227
|
+
heightPt: placement.heightPt
|
|
133
228
|
};
|
|
134
|
-
for (const frame of require_typed_util.elementsWithTag([
|
|
229
|
+
for (const frame of require_typed_util.elementsWithTag([node], "xdr:graphicFrame")) {
|
|
135
230
|
const chart = readChartFrame(pkg, frame, drawingRels);
|
|
136
231
|
if (chart === void 0) continue;
|
|
137
232
|
objects.push({
|
|
138
233
|
objectKind: "chart",
|
|
139
234
|
document: chartDocument(pkg, chart.root, frameBox, chart.name),
|
|
140
235
|
frame: frameBox,
|
|
141
|
-
anchorRow:
|
|
142
|
-
anchorColumn:
|
|
143
|
-
offsetXPt:
|
|
144
|
-
offsetYPt:
|
|
236
|
+
anchorRow: placement.anchorRow,
|
|
237
|
+
anchorColumn: placement.anchorColumn,
|
|
238
|
+
offsetXPt: placement.offsetXPt,
|
|
239
|
+
offsetYPt: placement.offsetYPt
|
|
145
240
|
});
|
|
146
241
|
}
|
|
147
|
-
for (const pic of require_typed_util.elementsWithTag([
|
|
242
|
+
for (const pic of require_typed_util.elementsWithTag([node], "xdr:pic")) {
|
|
148
243
|
const media = readPictureMedia(pkg, pic, drawingRels);
|
|
149
244
|
if (media === void 0) continue;
|
|
150
|
-
if (
|
|
245
|
+
if (placement.widthPt <= 0 || placement.heightPt <= 0) continue;
|
|
151
246
|
images.push({
|
|
152
247
|
kind: "image",
|
|
153
248
|
format: media.format,
|
|
154
249
|
base64: media.base64,
|
|
155
|
-
widthPt:
|
|
156
|
-
heightPt:
|
|
157
|
-
anchorRow:
|
|
158
|
-
anchorColumn:
|
|
159
|
-
offsetXPt:
|
|
160
|
-
offsetYPt:
|
|
250
|
+
widthPt: placement.widthPt,
|
|
251
|
+
heightPt: placement.heightPt,
|
|
252
|
+
anchorRow: placement.anchorRow,
|
|
253
|
+
anchorColumn: placement.anchorColumn,
|
|
254
|
+
offsetXPt: placement.offsetXPt,
|
|
255
|
+
offsetYPt: placement.offsetYPt
|
|
161
256
|
});
|
|
162
257
|
}
|
|
163
258
|
}
|
|
@@ -54,6 +54,34 @@ var SheetGridGeometry = class {
|
|
|
54
54
|
for (let index = 0; index < row; index++) yPt += this.rowHeightPt(index);
|
|
55
55
|
return yPt;
|
|
56
56
|
}
|
|
57
|
+
locateColumn(xPt) {
|
|
58
|
+
let index = 0;
|
|
59
|
+
let boundaryPt = 0;
|
|
60
|
+
let widthPt = this.columnWidthPt(index);
|
|
61
|
+
while (boundaryPt + widthPt <= xPt) {
|
|
62
|
+
boundaryPt += widthPt;
|
|
63
|
+
index += 1;
|
|
64
|
+
widthPt = this.columnWidthPt(index);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
index,
|
|
68
|
+
offsetPt: xPt - boundaryPt
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
locateRow(yPt) {
|
|
72
|
+
let index = 0;
|
|
73
|
+
let boundaryPt = 0;
|
|
74
|
+
let heightPt = this.rowHeightPt(index);
|
|
75
|
+
while (boundaryPt + heightPt <= yPt) {
|
|
76
|
+
boundaryPt += heightPt;
|
|
77
|
+
index += 1;
|
|
78
|
+
heightPt = this.rowHeightPt(index);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
index,
|
|
82
|
+
offsetPt: yPt - boundaryPt
|
|
83
|
+
};
|
|
84
|
+
}
|
|
57
85
|
};
|
|
58
86
|
function readAnchorChild(marker, tag) {
|
|
59
87
|
const child = childrenWithTag(marker, tag)[0];
|
|
@@ -61,6 +89,11 @@ function readAnchorChild(marker, tag) {
|
|
|
61
89
|
const parsed = text === void 0 || text === "" ? NaN : Number(text);
|
|
62
90
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
63
91
|
}
|
|
92
|
+
function numericAttr(element, name) {
|
|
93
|
+
const raw = attr(element, name);
|
|
94
|
+
const parsed = raw === void 0 ? NaN : Number(raw);
|
|
95
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
96
|
+
}
|
|
64
97
|
function readAnchorMarker(parent, tag) {
|
|
65
98
|
const marker = childrenWithTag(parent, tag)[0];
|
|
66
99
|
if (marker === void 0) return;
|
|
@@ -71,6 +104,65 @@ function readAnchorMarker(parent, tag) {
|
|
|
71
104
|
rowOffEmu: readAnchorChild(marker, "xdr:rowOff")
|
|
72
105
|
};
|
|
73
106
|
}
|
|
107
|
+
function readAnchorExtEmu(anchor) {
|
|
108
|
+
const ext = childrenWithTag(anchor, "xdr:ext")[0];
|
|
109
|
+
if (ext === void 0) return;
|
|
110
|
+
return {
|
|
111
|
+
cxEmu: numericAttr(ext, "cx"),
|
|
112
|
+
cyEmu: numericAttr(ext, "cy")
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function readAnchorPlacement(anchor, geometry) {
|
|
116
|
+
if (anchor.tag === "xdr:twoCellAnchor") {
|
|
117
|
+
const from = readAnchorMarker(anchor, "xdr:from");
|
|
118
|
+
const to = readAnchorMarker(anchor, "xdr:to");
|
|
119
|
+
if (from === void 0 || to === void 0) return;
|
|
120
|
+
const xPt = geometry.xPt(from.column, from.colOffEmu);
|
|
121
|
+
const yPt = geometry.yPt(from.row, from.rowOffEmu);
|
|
122
|
+
return {
|
|
123
|
+
xPt,
|
|
124
|
+
yPt,
|
|
125
|
+
widthPt: geometry.xPt(to.column, to.colOffEmu) - xPt,
|
|
126
|
+
heightPt: geometry.yPt(to.row, to.rowOffEmu) - yPt,
|
|
127
|
+
anchorRow: from.row,
|
|
128
|
+
anchorColumn: from.column,
|
|
129
|
+
offsetXPt: emuToPt(from.colOffEmu),
|
|
130
|
+
offsetYPt: emuToPt(from.rowOffEmu)
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (anchor.tag === "xdr:oneCellAnchor") {
|
|
134
|
+
const from = readAnchorMarker(anchor, "xdr:from");
|
|
135
|
+
const ext = readAnchorExtEmu(anchor);
|
|
136
|
+
if (from === void 0 || ext === void 0) return;
|
|
137
|
+
return {
|
|
138
|
+
xPt: geometry.xPt(from.column, from.colOffEmu),
|
|
139
|
+
yPt: geometry.yPt(from.row, from.rowOffEmu),
|
|
140
|
+
widthPt: emuToPt(ext.cxEmu),
|
|
141
|
+
heightPt: emuToPt(ext.cyEmu),
|
|
142
|
+
anchorRow: from.row,
|
|
143
|
+
anchorColumn: from.column,
|
|
144
|
+
offsetXPt: emuToPt(from.colOffEmu),
|
|
145
|
+
offsetYPt: emuToPt(from.rowOffEmu)
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const pos = childrenWithTag(anchor, "xdr:pos")[0];
|
|
149
|
+
const ext = readAnchorExtEmu(anchor);
|
|
150
|
+
if (pos === void 0 || ext === void 0) return;
|
|
151
|
+
const xPt = emuToPt(numericAttr(pos, "x"));
|
|
152
|
+
const yPt = emuToPt(numericAttr(pos, "y"));
|
|
153
|
+
const column = geometry.locateColumn(xPt);
|
|
154
|
+
const row = geometry.locateRow(yPt);
|
|
155
|
+
return {
|
|
156
|
+
xPt,
|
|
157
|
+
yPt,
|
|
158
|
+
widthPt: emuToPt(ext.cxEmu),
|
|
159
|
+
heightPt: emuToPt(ext.cyEmu),
|
|
160
|
+
anchorRow: row.index,
|
|
161
|
+
anchorColumn: column.index,
|
|
162
|
+
offsetXPt: column.offsetPt,
|
|
163
|
+
offsetYPt: row.offsetPt
|
|
164
|
+
};
|
|
165
|
+
}
|
|
74
166
|
function emptyWorksheet() {
|
|
75
167
|
return {
|
|
76
168
|
type: "element",
|
|
@@ -99,6 +191,11 @@ function chartCells(chartRoot, frame) {
|
|
|
99
191
|
});
|
|
100
192
|
return cells;
|
|
101
193
|
}
|
|
194
|
+
const ANCHOR_TAGS = [
|
|
195
|
+
"xdr:twoCellAnchor",
|
|
196
|
+
"xdr:oneCellAnchor",
|
|
197
|
+
"xdr:absoluteAnchor"
|
|
198
|
+
];
|
|
102
199
|
function readSheetDrawing(pkg, worksheetPath, worksheet) {
|
|
103
200
|
let drawingPath;
|
|
104
201
|
for (const rel of resolveRelationships(pkg, worksheetPath).values()) if (rel.type.endsWith(DRAWING_REL_SUFFIX)) {
|
|
@@ -118,45 +215,43 @@ function readSheetDrawing(pkg, worksheetPath, worksheet) {
|
|
|
118
215
|
const geometry = new SheetGridGeometry(worksheet);
|
|
119
216
|
const objects = [];
|
|
120
217
|
const images = [];
|
|
121
|
-
for (const
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
if (
|
|
125
|
-
const xPt = geometry.xPt(from.column, from.colOffEmu);
|
|
126
|
-
const yPt = geometry.yPt(from.row, from.rowOffEmu);
|
|
218
|
+
for (const node of drawingRoot.children) {
|
|
219
|
+
if (node.type !== "element" || !ANCHOR_TAGS.includes(node.tag)) continue;
|
|
220
|
+
const placement = readAnchorPlacement(node, geometry);
|
|
221
|
+
if (placement === void 0) continue;
|
|
127
222
|
const frameBox = {
|
|
128
|
-
xPt,
|
|
129
|
-
yPt,
|
|
130
|
-
widthPt:
|
|
131
|
-
heightPt:
|
|
223
|
+
xPt: placement.xPt,
|
|
224
|
+
yPt: placement.yPt,
|
|
225
|
+
widthPt: placement.widthPt,
|
|
226
|
+
heightPt: placement.heightPt
|
|
132
227
|
};
|
|
133
|
-
for (const frame of elementsWithTag([
|
|
228
|
+
for (const frame of elementsWithTag([node], "xdr:graphicFrame")) {
|
|
134
229
|
const chart = readChartFrame(pkg, frame, drawingRels);
|
|
135
230
|
if (chart === void 0) continue;
|
|
136
231
|
objects.push({
|
|
137
232
|
objectKind: "chart",
|
|
138
233
|
document: chartDocument(pkg, chart.root, frameBox, chart.name),
|
|
139
234
|
frame: frameBox,
|
|
140
|
-
anchorRow:
|
|
141
|
-
anchorColumn:
|
|
142
|
-
offsetXPt:
|
|
143
|
-
offsetYPt:
|
|
235
|
+
anchorRow: placement.anchorRow,
|
|
236
|
+
anchorColumn: placement.anchorColumn,
|
|
237
|
+
offsetXPt: placement.offsetXPt,
|
|
238
|
+
offsetYPt: placement.offsetYPt
|
|
144
239
|
});
|
|
145
240
|
}
|
|
146
|
-
for (const pic of elementsWithTag([
|
|
241
|
+
for (const pic of elementsWithTag([node], "xdr:pic")) {
|
|
147
242
|
const media = readPictureMedia(pkg, pic, drawingRels);
|
|
148
243
|
if (media === void 0) continue;
|
|
149
|
-
if (
|
|
244
|
+
if (placement.widthPt <= 0 || placement.heightPt <= 0) continue;
|
|
150
245
|
images.push({
|
|
151
246
|
kind: "image",
|
|
152
247
|
format: media.format,
|
|
153
248
|
base64: media.base64,
|
|
154
|
-
widthPt:
|
|
155
|
-
heightPt:
|
|
156
|
-
anchorRow:
|
|
157
|
-
anchorColumn:
|
|
158
|
-
offsetXPt:
|
|
159
|
-
offsetYPt:
|
|
249
|
+
widthPt: placement.widthPt,
|
|
250
|
+
heightPt: placement.heightPt,
|
|
251
|
+
anchorRow: placement.anchorRow,
|
|
252
|
+
anchorColumn: placement.anchorColumn,
|
|
253
|
+
offsetXPt: placement.offsetXPt,
|
|
254
|
+
offsetYPt: placement.offsetYPt
|
|
160
255
|
});
|
|
161
256
|
}
|
|
162
257
|
}
|
package/package.json
CHANGED