@lotics/cli 0.96.1 → 0.96.2
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/render_page.js +6999 -6909
- package/dist/src/cli.js +189 -31
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -79374,8 +79374,9 @@ function parseImages(rels, zipEntries) {
|
|
|
79374
79374
|
const drawingRelsPath = drawingPath.replace(/([^/]+)$/, "_rels/$1.rels");
|
|
79375
79375
|
const drawingRelsEntry = findZipEntry(zipEntries, drawingRelsPath);
|
|
79376
79376
|
const drawingRels = drawingRelsEntry ? parseDrawingRels(decodeUtf8(drawingRelsEntry)) : /* @__PURE__ */ new Map();
|
|
79377
|
-
const
|
|
79378
|
-
|
|
79377
|
+
for (const key of ["xdr:twoCellAnchor", "xdr:oneCellAnchor", "xdr:absoluteAnchor"]) {
|
|
79378
|
+
const anchors = wsDr[key];
|
|
79379
|
+
if (!anchors) continue;
|
|
79379
79380
|
for (const anchor of anchors) {
|
|
79380
79381
|
if (images.length >= MAX_IMAGES) break;
|
|
79381
79382
|
const image = extractImageFromAnchor(anchor, drawingRels, zipEntries, drawingPath);
|
|
@@ -79401,18 +79402,42 @@ function parseDrawingRels(relsXml2) {
|
|
|
79401
79402
|
}
|
|
79402
79403
|
return map3;
|
|
79403
79404
|
}
|
|
79405
|
+
var MEDIA_MIME_TYPES = {
|
|
79406
|
+
png: "image/png",
|
|
79407
|
+
jpg: "image/jpeg",
|
|
79408
|
+
jpeg: "image/jpeg",
|
|
79409
|
+
gif: "image/gif",
|
|
79410
|
+
bmp: "image/bmp",
|
|
79411
|
+
tiff: "image/tiff",
|
|
79412
|
+
tif: "image/tiff",
|
|
79413
|
+
svg: "image/svg+xml",
|
|
79414
|
+
emf: "image/x-emf",
|
|
79415
|
+
wmf: "image/x-wmf"
|
|
79416
|
+
};
|
|
79417
|
+
function isSupportedMediaMime(mime) {
|
|
79418
|
+
return Object.values(MEDIA_MIME_TYPES).includes(mime);
|
|
79419
|
+
}
|
|
79404
79420
|
function extractImageFromAnchor(anchor, drawingRels, zipEntries, drawingPath) {
|
|
79405
|
-
const from = anchor["xdr:from"];
|
|
79421
|
+
const from = anchor["xdr:from"] ?? { "xdr:row": "0", "xdr:col": "0" };
|
|
79406
79422
|
const to = anchor["xdr:to"];
|
|
79407
|
-
|
|
79423
|
+
const posEl = anchor["xdr:pos"];
|
|
79424
|
+
if (!anchor["xdr:from"] && !posEl) return void 0;
|
|
79425
|
+
const extEl = anchor["xdr:ext"];
|
|
79426
|
+
const extent = extEl ? { cx: parseInt(extEl["@_cx"] ?? "0", 10), cy: parseInt(extEl["@_cy"] ?? "0", 10) } : void 0;
|
|
79427
|
+
const pos = posEl ? { x: parseInt(posEl["@_x"] ?? "0", 10), y: parseInt(posEl["@_y"] ?? "0", 10) } : void 0;
|
|
79428
|
+
const anchorKind = to ? "twoCell" : posEl ? "absolute" : "oneCell";
|
|
79408
79429
|
const tl = {
|
|
79409
79430
|
row: parseInt(from["xdr:row"] ?? "0", 10),
|
|
79410
|
-
col: parseInt(from["xdr:col"] ?? "0", 10)
|
|
79431
|
+
col: parseInt(from["xdr:col"] ?? "0", 10),
|
|
79432
|
+
rowOff: parseInt(from["xdr:rowOff"] ?? "0", 10),
|
|
79433
|
+
colOff: parseInt(from["xdr:colOff"] ?? "0", 10)
|
|
79411
79434
|
};
|
|
79412
|
-
const br = {
|
|
79435
|
+
const br = to ? {
|
|
79413
79436
|
row: parseInt(to["xdr:row"] ?? "0", 10) + 1,
|
|
79414
|
-
col: parseInt(to["xdr:col"] ?? "0", 10) + 1
|
|
79415
|
-
|
|
79437
|
+
col: parseInt(to["xdr:col"] ?? "0", 10) + 1,
|
|
79438
|
+
rowOff: parseInt(to["xdr:rowOff"] ?? "0", 10),
|
|
79439
|
+
colOff: parseInt(to["xdr:colOff"] ?? "0", 10)
|
|
79440
|
+
} : { row: tl.row + 1, col: tl.col + 1, rowOff: 0, colOff: 0 };
|
|
79416
79441
|
const pic = anchor["xdr:pic"];
|
|
79417
79442
|
if (!pic) return void 0;
|
|
79418
79443
|
const blipFill = pic["xdr:blipFill"];
|
|
@@ -79428,10 +79453,10 @@ function extractImageFromAnchor(anchor, drawingRels, zipEntries, drawingPath) {
|
|
|
79428
79453
|
const imageEntry = findZipEntry(zipEntries, imagePath);
|
|
79429
79454
|
if (!imageEntry) return void 0;
|
|
79430
79455
|
const ext = imagePath.split(".").pop()?.toLowerCase() ?? "png";
|
|
79431
|
-
const mimeType = ext
|
|
79456
|
+
const mimeType = MEDIA_MIME_TYPES[ext] ?? "application/octet-stream";
|
|
79432
79457
|
const base643 = uint8ToBase64(imageEntry);
|
|
79433
79458
|
const dataUrl = `data:${mimeType};base64,${base643}`;
|
|
79434
|
-
return { dataUrl, tl, br };
|
|
79459
|
+
return { dataUrl, tl, br, ext, anchorKind, extent, pos };
|
|
79435
79460
|
}
|
|
79436
79461
|
function parseConditionalFormats(worksheet, theme, indexedColors) {
|
|
79437
79462
|
const cfArr = worksheet["conditionalFormatting"];
|
|
@@ -81897,7 +81922,7 @@ function readWorkbookRels(originalZip) {
|
|
|
81897
81922
|
const bytes = originalZip["xl/_rels/workbook.xml.rels"];
|
|
81898
81923
|
if (!bytes) return out;
|
|
81899
81924
|
const xml = decode3(bytes);
|
|
81900
|
-
const re2 = /<Relationship\b([
|
|
81925
|
+
const re2 = /<Relationship\b([^>]*?)\/>/g;
|
|
81901
81926
|
let m;
|
|
81902
81927
|
while ((m = re2.exec(xml)) !== null) {
|
|
81903
81928
|
const attrs = m[1];
|
|
@@ -81931,7 +81956,7 @@ function readSheetPivotPaths(originalZip, sheetTarget) {
|
|
|
81931
81956
|
const bytes = originalZip[relsPath];
|
|
81932
81957
|
if (!bytes) return [];
|
|
81933
81958
|
const xml = decode3(bytes);
|
|
81934
|
-
const re2 = /<Relationship\b([
|
|
81959
|
+
const re2 = /<Relationship\b([^>]*?)\/>/g;
|
|
81935
81960
|
const out = [];
|
|
81936
81961
|
let m;
|
|
81937
81962
|
while ((m = re2.exec(xml)) !== null) {
|
|
@@ -81943,6 +81968,32 @@ function readSheetPivotPaths(originalZip, sheetTarget) {
|
|
|
81943
81968
|
}
|
|
81944
81969
|
return out;
|
|
81945
81970
|
}
|
|
81971
|
+
function extractLegacyHeaderFooterArt(originalZip, sheetTarget) {
|
|
81972
|
+
if (!originalZip || !sheetTarget) return null;
|
|
81973
|
+
const sheetPath = `xl/${sheetTarget}`;
|
|
81974
|
+
const sheetBytes = originalZip[sheetPath];
|
|
81975
|
+
if (!sheetBytes || !/<legacyDrawingHF\b/.test(decode3(sheetBytes))) return null;
|
|
81976
|
+
const relsPath = sheetPath.replace(/([^/]+)$/, "_rels/$1.rels");
|
|
81977
|
+
const relsBytes = originalZip[relsPath];
|
|
81978
|
+
if (!relsBytes) return null;
|
|
81979
|
+
const relsXml2 = decode3(relsBytes);
|
|
81980
|
+
const hfRel = [...relsXml2.matchAll(/<Relationship\b([^>]*?)\/>/g)].map((m) => m[1]).find((attrs) => (/\bType="([^"]+)"/.exec(attrs)?.[1] ?? "").includes("/vmlDrawing"));
|
|
81981
|
+
const target = hfRel ? /\bTarget="([^"]+)"/.exec(hfRel)?.[1] : void 0;
|
|
81982
|
+
if (!target) return null;
|
|
81983
|
+
const vmlPath = `xl/${target.replace(/^\.\.\//, "")}`;
|
|
81984
|
+
if (!originalZip[vmlPath]) return null;
|
|
81985
|
+
const parts = [vmlPath];
|
|
81986
|
+
const vmlRelsPath = vmlPath.replace(/([^/]+)$/, "_rels/$1.rels");
|
|
81987
|
+
const vmlRels = originalZip[vmlRelsPath];
|
|
81988
|
+
if (vmlRels) {
|
|
81989
|
+
parts.push(vmlRelsPath);
|
|
81990
|
+
for (const m of decode3(vmlRels).matchAll(/\bTarget="([^"]+)"/g)) {
|
|
81991
|
+
const mediaPath = `xl/${m[1].replace(/^\.\.\//, "")}`;
|
|
81992
|
+
if (originalZip[mediaPath]) parts.push(mediaPath);
|
|
81993
|
+
}
|
|
81994
|
+
}
|
|
81995
|
+
return { target, parts };
|
|
81996
|
+
}
|
|
81946
81997
|
function extractPivotRoundTripInfo(originalZip) {
|
|
81947
81998
|
const empty = {
|
|
81948
81999
|
cachesByWorkbook: /* @__PURE__ */ new Map(),
|
|
@@ -82056,6 +82107,7 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
82056
82107
|
regeneratedPaths.add("_rels/.rels");
|
|
82057
82108
|
regeneratedPaths.add("docProps/core.xml");
|
|
82058
82109
|
regeneratedPaths.add("docProps/app.xml");
|
|
82110
|
+
regeneratedPaths.add("xl/calcChain.xml");
|
|
82059
82111
|
for (let i2 = 0; i2 < workbook.sheets.length + 10; i2++) {
|
|
82060
82112
|
regeneratedPaths.add(`xl/worksheets/sheet${i2 + 1}.xml`);
|
|
82061
82113
|
regeneratedPaths.add(`xl/worksheets/_rels/sheet${i2 + 1}.xml.rels`);
|
|
@@ -82066,7 +82118,10 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
82066
82118
|
}
|
|
82067
82119
|
}
|
|
82068
82120
|
for (const [path8, data] of Object.entries(originalZip)) {
|
|
82069
|
-
if (
|
|
82121
|
+
if (regeneratedPaths.has(path8)) continue;
|
|
82122
|
+
const ext = path8.slice(path8.lastIndexOf(".") + 1).toLowerCase();
|
|
82123
|
+
if (!DECLARED_EXTENSIONS.includes(ext)) continue;
|
|
82124
|
+
entries2[path8] = data;
|
|
82070
82125
|
}
|
|
82071
82126
|
}
|
|
82072
82127
|
const sharedStrings = buildSharedStrings(workbook);
|
|
@@ -82074,6 +82129,7 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
82074
82129
|
const stylesResult = stylesPassthrough ? { xml: "", xfMap: /* @__PURE__ */ new Map(), numFmtMap: /* @__PURE__ */ new Map(), dxfMap: /* @__PURE__ */ new Map() } : buildStylesXml(workbook);
|
|
82075
82130
|
if (!stylesPassthrough) entries2["xl/styles.xml"] = strToU8(stylesResult.xml);
|
|
82076
82131
|
const roundTripInfo = extractPivotRoundTripInfo(originalZip);
|
|
82132
|
+
const sheetTargets = originalZip ? readWorkbookSheetOrder(originalZip).map((rid) => readWorkbookRels(originalZip).get(rid)?.target) : [];
|
|
82077
82133
|
const authoredStartIndex = roundTripInfo.pivotXmlPaths.filter((p) => p.startsWith("xl/pivotTables/")).length + 1;
|
|
82078
82134
|
const pivotInfo = mergePivotInfo(roundTripInfo, emitAuthoredPivots(workbook, entries2, authoredStartIndex));
|
|
82079
82135
|
entries2["xl/workbook.xml"] = strToU8(buildWorkbookXml(workbook, pivotInfo));
|
|
@@ -82106,6 +82162,15 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
82106
82162
|
sheetRels.push(`<Relationship Id="${rId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink" Target="${escapeXml(url2)}" TargetMode="External"/>`);
|
|
82107
82163
|
}
|
|
82108
82164
|
}
|
|
82165
|
+
let legacyHFRId = "";
|
|
82166
|
+
if (originalZip) {
|
|
82167
|
+
const hf = extractLegacyHeaderFooterArt(originalZip, sheetTargets[i2]);
|
|
82168
|
+
if (hf) {
|
|
82169
|
+
legacyHFRId = `rId${nextRId++}`;
|
|
82170
|
+
sheetRels.push(`<Relationship Id="${legacyHFRId}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing" Target="${escapeXml(hf.target)}"/>`);
|
|
82171
|
+
for (const part of hf.parts) entries2[part] = originalZip[part];
|
|
82172
|
+
}
|
|
82173
|
+
}
|
|
82109
82174
|
let drawingRId = "";
|
|
82110
82175
|
if (needsDrawing) {
|
|
82111
82176
|
drawingRId = `rId${nextRId++}`;
|
|
@@ -82124,7 +82189,8 @@ function exportWorkbook(workbook, originalZip) {
|
|
|
82124
82189
|
}
|
|
82125
82190
|
for (const image of sheet.images) {
|
|
82126
82191
|
const imgRId = `rId${drawingRelId++}`;
|
|
82127
|
-
const ext = getImageExtension(image.dataUrl);
|
|
82192
|
+
const ext = getImageExtension(image.dataUrl, image.ext);
|
|
82193
|
+
while (entries2[`xl/media/image${globalImageIndex}.${ext}`]) globalImageIndex++;
|
|
82128
82194
|
const imgPath = `xl/media/image${globalImageIndex}.${ext}`;
|
|
82129
82195
|
const imgBytes = dataUrlToBytes(image.dataUrl);
|
|
82130
82196
|
if (imgBytes) {
|
|
@@ -82183,7 +82249,7 @@ ${sheetRels.join("\n")}
|
|
|
82183
82249
|
);
|
|
82184
82250
|
}
|
|
82185
82251
|
entries2[`xl/worksheets/sheet${i2 + 1}.xml`] = strToU8(
|
|
82186
|
-
buildSheetXml(sheet, workbook.styles, sharedStrings.index, i2 === workbook.activeSheetIndex, stylesResult.xfMap, stylesResult.numFmtMap, stylesResult.dxfMap, drawingRId, tableRIds, hyperlinkRIds)
|
|
82252
|
+
buildSheetXml(sheet, workbook.styles, sharedStrings.index, i2 === workbook.activeSheetIndex, stylesResult.xfMap, stylesResult.numFmtMap, stylesResult.dxfMap, drawingRId, tableRIds, hyperlinkRIds, legacyHFRId)
|
|
82187
82253
|
);
|
|
82188
82254
|
}
|
|
82189
82255
|
entries2["docProps/core.xml"] = strToU8(buildCoreProps());
|
|
@@ -82518,7 +82584,7 @@ function extractFillColors(css) {
|
|
|
82518
82584
|
}
|
|
82519
82585
|
return { fg: void 0, bg: void 0 };
|
|
82520
82586
|
}
|
|
82521
|
-
function buildSheetXml(sheet, styles, ssIndex, isActive, xfMap, numFmtMap, dxfMap, drawingRId, tableRIds, hyperlinkRIds) {
|
|
82587
|
+
function buildSheetXml(sheet, styles, ssIndex, isActive, xfMap, numFmtMap, dxfMap, drawingRId, tableRIds, hyperlinkRIds, legacyHFRId) {
|
|
82522
82588
|
const rows = [];
|
|
82523
82589
|
const rowMap = /* @__PURE__ */ new Map();
|
|
82524
82590
|
for (const [ref, cell] of sheet.cells) {
|
|
@@ -82568,10 +82634,22 @@ function buildSheetXml(sheet, styles, ssIndex, isActive, xfMap, numFmtMap, dxfMa
|
|
|
82568
82634
|
}
|
|
82569
82635
|
const cols = [];
|
|
82570
82636
|
const allCols = /* @__PURE__ */ new Set([...sheet.colWidths.keys(), ...sheet.hiddenCols]);
|
|
82571
|
-
|
|
82637
|
+
const sortedCols = Array.from(allCols).sort((a, b) => a - b);
|
|
82638
|
+
const colDef = (c) => {
|
|
82572
82639
|
const w = sheet.colWidths.get(c) ?? sheet.defaultColWidth;
|
|
82573
82640
|
const hidden = sheet.hiddenCols.has(c) ? ' hidden="1"' : "";
|
|
82574
|
-
|
|
82641
|
+
return `width="${w}" customWidth="1"${hidden}`;
|
|
82642
|
+
};
|
|
82643
|
+
for (let i2 = 0; i2 < sortedCols.length; ) {
|
|
82644
|
+
const start = sortedCols[i2];
|
|
82645
|
+
const def = colDef(start);
|
|
82646
|
+
let end = start;
|
|
82647
|
+
while (i2 + 1 < sortedCols.length && sortedCols[i2 + 1] === end + 1 && colDef(sortedCols[i2 + 1]) === def) {
|
|
82648
|
+
end = sortedCols[i2 + 1];
|
|
82649
|
+
i2++;
|
|
82650
|
+
}
|
|
82651
|
+
cols.push(`<col min="${start}" max="${end}" ${def}/>`);
|
|
82652
|
+
i2++;
|
|
82575
82653
|
}
|
|
82576
82654
|
let mergeXml = "";
|
|
82577
82655
|
if (sheet.mergedCells.length > 0) {
|
|
@@ -82627,6 +82705,7 @@ function buildSheetXml(sheet, styles, ssIndex, isActive, xfMap, numFmtMap, dxfMa
|
|
|
82627
82705
|
hyperlinksXml = `<hyperlinks>${hlEntries}</hyperlinks>`;
|
|
82628
82706
|
}
|
|
82629
82707
|
const drawingXml = drawingRId ? `<drawing r:id="${drawingRId}"/>` : "";
|
|
82708
|
+
const legacyHFXml = legacyHFRId ? `<legacyDrawingHF r:id="${legacyHFRId}"/>` : "";
|
|
82630
82709
|
let tablePartsXml = "";
|
|
82631
82710
|
if (tableRIds && tableRIds.length > 0) {
|
|
82632
82711
|
const parts = tableRIds.map((rId) => `<tablePart r:id="${rId}"/>`).join("");
|
|
@@ -82697,7 +82776,7 @@ ${cols.length > 0 ? `<cols>${cols.join("")}</cols>` : ""}
|
|
|
82697
82776
|
<sheetData>
|
|
82698
82777
|
${rows.join("\n")}
|
|
82699
82778
|
</sheetData>
|
|
82700
|
-
${autoFilterXml}${mergeXml}${cfXml}${dvXml}${hyperlinksXml}${marginsXml}${pageSetupXml}${headerFooterXml}${drawingXml}${tablePartsXml}
|
|
82779
|
+
${autoFilterXml}${mergeXml}${cfXml}${dvXml}${hyperlinksXml}${marginsXml}${pageSetupXml}${headerFooterXml}${drawingXml}${legacyHFXml}${tablePartsXml}
|
|
82701
82780
|
</worksheet>`;
|
|
82702
82781
|
}
|
|
82703
82782
|
function getCellType(cell, ssIndex) {
|
|
@@ -82794,19 +82873,30 @@ function buildWorkbookRels(workbook, pivotInfo) {
|
|
|
82794
82873
|
${rels.join("\n")}
|
|
82795
82874
|
</Relationships>`;
|
|
82796
82875
|
}
|
|
82876
|
+
var DECLARED_EXTENSIONS = ["rels", "xml", "png", "jpeg", "jpg", "gif", "vml", "emf", "wmf", "bmp", "tiff", "tif", "svg"];
|
|
82797
82877
|
function buildContentTypes(sheetCount, extraTypes = []) {
|
|
82878
|
+
const DEFAULT_CONTENT_TYPES = [
|
|
82879
|
+
`<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>`,
|
|
82880
|
+
`<Default Extension="xml" ContentType="application/xml"/>`,
|
|
82881
|
+
`<Default Extension="png" ContentType="image/png"/>`,
|
|
82882
|
+
`<Default Extension="jpeg" ContentType="image/jpeg"/>`,
|
|
82883
|
+
`<Default Extension="jpg" ContentType="image/jpeg"/>`,
|
|
82884
|
+
`<Default Extension="gif" ContentType="image/gif"/>`,
|
|
82885
|
+
`<Default Extension="vml" ContentType="application/vnd.openxmlformats-officedocument.vmlDrawing"/>`,
|
|
82886
|
+
`<Default Extension="emf" ContentType="image/x-emf"/>`,
|
|
82887
|
+
`<Default Extension="wmf" ContentType="image/x-wmf"/>`,
|
|
82888
|
+
`<Default Extension="bmp" ContentType="image/bmp"/>`,
|
|
82889
|
+
`<Default Extension="tiff" ContentType="image/tiff"/>`,
|
|
82890
|
+
`<Default Extension="tif" ContentType="image/tiff"/>`,
|
|
82891
|
+
`<Default Extension="svg" ContentType="image/svg+xml"/>`
|
|
82892
|
+
].join("\n");
|
|
82798
82893
|
const sheetTypes = Array.from(
|
|
82799
82894
|
{ length: sheetCount },
|
|
82800
82895
|
(_, i2) => `<Override PartName="/xl/worksheets/sheet${i2 + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`
|
|
82801
82896
|
).join("\n");
|
|
82802
82897
|
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
82803
82898
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
82804
|
-
|
|
82805
|
-
<Default Extension="xml" ContentType="application/xml"/>
|
|
82806
|
-
<Default Extension="png" ContentType="image/png"/>
|
|
82807
|
-
<Default Extension="jpeg" ContentType="image/jpeg"/>
|
|
82808
|
-
<Default Extension="jpg" ContentType="image/jpeg"/>
|
|
82809
|
-
<Default Extension="gif" ContentType="image/gif"/>
|
|
82899
|
+
${DEFAULT_CONTENT_TYPES}
|
|
82810
82900
|
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
|
|
82811
82901
|
${sheetTypes}
|
|
82812
82902
|
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
|
|
@@ -82981,15 +83071,37 @@ function buildChartAnchorXml(chart, rId) {
|
|
|
82981
83071
|
</xdr:twoCellAnchor>`;
|
|
82982
83072
|
}
|
|
82983
83073
|
function buildImageAnchorXml(image, rId) {
|
|
82984
|
-
|
|
82985
|
-
<xdr:from>${buildAnchorPosition(image.tl)}</xdr:from>
|
|
82986
|
-
<xdr:to>${buildAnchorPosition(image.br)}</xdr:to>
|
|
82987
|
-
<xdr:pic>
|
|
83074
|
+
const pic = `<xdr:pic>
|
|
82988
83075
|
<xdr:nvPicPr><xdr:cNvPr id="0" name="Image"/><xdr:cNvPicPr/></xdr:nvPicPr>
|
|
82989
83076
|
<xdr:blipFill><a:blip xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" r:embed="${rId}"/><a:stretch><a:fillRect/></a:stretch></xdr:blipFill>
|
|
82990
83077
|
<xdr:spPr><a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr>
|
|
82991
83078
|
</xdr:pic>
|
|
82992
|
-
<xdr:clientData
|
|
83079
|
+
<xdr:clientData/>`;
|
|
83080
|
+
const from = `<xdr:from>${buildAnchorPosition({ row: image.tl.row, col: image.tl.col, rowOffset: image.tl.rowOff, colOffset: image.tl.colOff })}</xdr:from>`;
|
|
83081
|
+
if (image.anchorKind === "oneCell" && image.extent) {
|
|
83082
|
+
return `<xdr:oneCellAnchor>
|
|
83083
|
+
${from}
|
|
83084
|
+
<xdr:ext cx="${image.extent.cx}" cy="${image.extent.cy}"/>
|
|
83085
|
+
${pic}
|
|
83086
|
+
</xdr:oneCellAnchor>`;
|
|
83087
|
+
}
|
|
83088
|
+
if (image.anchorKind === "absolute" && image.extent && image.pos) {
|
|
83089
|
+
return `<xdr:absoluteAnchor>
|
|
83090
|
+
<xdr:pos x="${image.pos.x}" y="${image.pos.y}"/>
|
|
83091
|
+
<xdr:ext cx="${image.extent.cx}" cy="${image.extent.cy}"/>
|
|
83092
|
+
${pic}
|
|
83093
|
+
</xdr:absoluteAnchor>`;
|
|
83094
|
+
}
|
|
83095
|
+
const to = {
|
|
83096
|
+
row: Math.max(image.tl.row, image.br.row - 1),
|
|
83097
|
+
col: Math.max(image.tl.col, image.br.col - 1),
|
|
83098
|
+
rowOffset: image.br.rowOff,
|
|
83099
|
+
colOffset: image.br.colOff
|
|
83100
|
+
};
|
|
83101
|
+
return `<xdr:twoCellAnchor editAs="oneCell">
|
|
83102
|
+
${from}
|
|
83103
|
+
<xdr:to>${buildAnchorPosition(to)}</xdr:to>
|
|
83104
|
+
${pic}
|
|
82993
83105
|
</xdr:twoCellAnchor>`;
|
|
82994
83106
|
}
|
|
82995
83107
|
function buildShapeAnchorXml(drawing) {
|
|
@@ -83088,10 +83200,16 @@ function buildDxfXml(style) {
|
|
|
83088
83200
|
}
|
|
83089
83201
|
return `<dxf>${inner}</dxf>`;
|
|
83090
83202
|
}
|
|
83091
|
-
function getImageExtension(dataUrl) {
|
|
83203
|
+
function getImageExtension(dataUrl, sourceExt) {
|
|
83204
|
+
if (sourceExt) return sourceExt.toLowerCase();
|
|
83092
83205
|
if (dataUrl.startsWith("data:image/png")) return "png";
|
|
83093
83206
|
if (dataUrl.startsWith("data:image/jpeg") || dataUrl.startsWith("data:image/jpg")) return "jpeg";
|
|
83094
83207
|
if (dataUrl.startsWith("data:image/gif")) return "gif";
|
|
83208
|
+
if (dataUrl.startsWith("data:image/x-emf")) return "emf";
|
|
83209
|
+
if (dataUrl.startsWith("data:image/x-wmf")) return "wmf";
|
|
83210
|
+
if (dataUrl.startsWith("data:image/bmp")) return "bmp";
|
|
83211
|
+
if (dataUrl.startsWith("data:image/tiff")) return "tiff";
|
|
83212
|
+
if (dataUrl.startsWith("data:image/svg+xml")) return "svg";
|
|
83095
83213
|
return "png";
|
|
83096
83214
|
}
|
|
83097
83215
|
function dataUrlToBytes(dataUrl) {
|
|
@@ -83306,6 +83424,46 @@ var SheetModel = class {
|
|
|
83306
83424
|
if (!rc) throw new Error(`Invalid cell reference: ${topLeftRef}`);
|
|
83307
83425
|
this.freeze = { row: rc.row - 1, col: rc.col - 1 };
|
|
83308
83426
|
}
|
|
83427
|
+
/**
|
|
83428
|
+
* Place a picture on the sheet, anchored to a cell range.
|
|
83429
|
+
*
|
|
83430
|
+
* The authoring counterpart to the parser: without it, adding an image meant
|
|
83431
|
+
* hand-constructing a ParsedImage (0-based anchors, an EXCLUSIVE `br`, a
|
|
83432
|
+
* dataUrl, an anchor kind) — enough hidden convention that every caller would
|
|
83433
|
+
* get one of them wrong. It lives on the model rather than in a tool so that
|
|
83434
|
+
* every surface reaches it: a sandbox code run, a workflow tool, the editor.
|
|
83435
|
+
*
|
|
83436
|
+
* `range` is an ordinary A1 range ("B3:F11"); a single ref ("B3") anchors a
|
|
83437
|
+
* one-cell box. The picture resizes with its cells (twoCell), which is what a
|
|
83438
|
+
* logo in a letterhead should do.
|
|
83439
|
+
*
|
|
83440
|
+
* @param dataUrl `data:image/png;base64,…` — the bytes to embed.
|
|
83441
|
+
* @param range Where it sits, e.g. "B3:F11".
|
|
83442
|
+
*/
|
|
83443
|
+
addImage(dataUrl, range2) {
|
|
83444
|
+
const mime = /^data:([^;,]+)[;,]/.exec(dataUrl)?.[1];
|
|
83445
|
+
if (!mime) throw new Error("addImage expects a data: URL, e.g. data:image/png;base64,\u2026");
|
|
83446
|
+
if (!isSupportedMediaMime(mime)) {
|
|
83447
|
+
throw new Error(`addImage cannot embed ${mime} \u2014 xl/media holds png, jpeg, gif, bmp, tiff, svg, emf or wmf`);
|
|
83448
|
+
}
|
|
83449
|
+
const [startRef, endRef] = range2.split(":");
|
|
83450
|
+
const start = refToRowCol(startRef ?? "");
|
|
83451
|
+
const end = endRef ? refToRowCol(endRef) : start;
|
|
83452
|
+
if (!start || !end) throw new Error(`Invalid cell range: ${range2}`);
|
|
83453
|
+
const image = {
|
|
83454
|
+
dataUrl,
|
|
83455
|
+
// refToRowCol is 1-based; anchors are 0-based, and `br` is EXCLUSIVE — one
|
|
83456
|
+
// past the last covered cell — so the end ref converts straight across
|
|
83457
|
+
// while the start ref loses one.
|
|
83458
|
+
// rowOff/colOff are pinned to 0 (not left undefined) so an authored image
|
|
83459
|
+
// is structurally identical to a parsed one — every reader handles one shape.
|
|
83460
|
+
tl: { row: Math.min(start.row, end.row) - 1, col: Math.min(start.col, end.col) - 1, rowOff: 0, colOff: 0 },
|
|
83461
|
+
br: { row: Math.max(start.row, end.row), col: Math.max(start.col, end.col), rowOff: 0, colOff: 0 },
|
|
83462
|
+
anchorKind: "twoCell"
|
|
83463
|
+
};
|
|
83464
|
+
this.images.push(image);
|
|
83465
|
+
return image;
|
|
83466
|
+
}
|
|
83309
83467
|
/** Get cell, returning undefined for empty cells. */
|
|
83310
83468
|
getCell(ref) {
|
|
83311
83469
|
return this.cells.get(ref);
|