@cj-tech-master/excelts 9.6.1 → 10.0.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 +18 -3
- package/README_zh.md +18 -3
- package/dist/browser/modules/excel/cell.d.ts +4 -0
- package/dist/browser/modules/excel/note.js +5 -1
- package/dist/browser/modules/excel/row.js +35 -2
- package/dist/browser/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
- package/dist/browser/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/browser/modules/excel/types.d.ts +81 -0
- package/dist/browser/modules/excel/utils/drawing-utils.d.ts +8 -0
- package/dist/browser/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/browser/modules/excel/workbook.browser.d.ts +16 -0
- package/dist/browser/modules/excel/workbook.browser.js +32 -2
- package/dist/browser/modules/excel/worksheet.d.ts +31 -1
- package/dist/browser/modules/excel/worksheet.js +83 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/browser/modules/pdf/builder/document-builder.js +22 -49
- package/dist/browser/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/browser/modules/pdf/core/pdf-stream.d.ts +28 -1
- package/dist/browser/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/browser/modules/pdf/font/font-manager.d.ts +26 -0
- package/dist/browser/modules/pdf/font/font-manager.js +35 -18
- package/dist/browser/modules/pdf/render/page-renderer.d.ts +51 -3
- package/dist/browser/modules/pdf/render/page-renderer.js +111 -18
- package/dist/browser/modules/word/advanced/field-engine.js +45 -20
- package/dist/browser/modules/word/advanced/glossary.d.ts +10 -36
- package/dist/browser/modules/word/advanced/glossary.js +8 -9
- package/dist/browser/modules/word/advanced/math-convert.js +94 -12
- package/dist/browser/modules/word/advanced/ole-objects.d.ts +28 -0
- package/dist/browser/modules/word/advanced/ole-objects.js +122 -19
- package/dist/browser/modules/word/advanced/style-map.js +31 -10
- package/dist/browser/modules/word/builder/run-builders.d.ts +7 -1
- package/dist/browser/modules/word/builder/run-builders.js +7 -1
- package/dist/browser/modules/word/constants.d.ts +4 -0
- package/dist/browser/modules/word/constants.js +5 -1
- package/dist/browser/modules/word/convert/docx-to-semantic.d.ts +2 -1
- package/dist/browser/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/browser/modules/word/convert/html/html-import.d.ts +32 -1
- package/dist/browser/modules/word/convert/html/html-import.js +167 -14
- package/dist/browser/modules/word/convert/html/html.d.ts +2 -2
- package/dist/browser/modules/word/convert/html/html.js +1 -1
- package/dist/browser/modules/word/convert/markdown/markdown-import.d.ts +48 -18
- package/dist/browser/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/browser/modules/word/convert/markdown/markdown.d.ts +1 -1
- package/dist/browser/modules/word/convert/odt/odt.js +407 -56
- package/dist/browser/modules/word/html.d.ts +2 -2
- package/dist/browser/modules/word/html.js +1 -1
- package/dist/browser/modules/word/index.base.d.ts +3 -3
- package/dist/browser/modules/word/index.base.js +1 -1
- package/dist/browser/modules/word/layout/layout-full.js +326 -19
- package/dist/browser/modules/word/layout/render-page.js +35 -8
- package/dist/browser/modules/word/markdown.d.ts +1 -1
- package/dist/browser/modules/word/query/compat.d.ts +10 -2
- package/dist/browser/modules/word/query/compat.js +29 -21
- package/dist/browser/modules/word/reader/docx-reader.js +105 -2
- package/dist/browser/modules/word/reader/math-parser.js +8 -2
- package/dist/browser/modules/word/security/cfb-reader.js +5 -5
- package/dist/browser/modules/word/types.d.ts +96 -1
- package/dist/browser/modules/word/writer/docx-packager.js +108 -2
- package/dist/browser/modules/word/writer/glossary-writer.d.ts +28 -0
- package/dist/browser/modules/word/writer/glossary-writer.js +121 -0
- package/dist/browser/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/browser/modules/word/writer/math-writer.js +7 -2
- package/dist/browser/utils/font-metrics.d.ts +8 -0
- package/dist/browser/utils/font-metrics.js +43 -0
- package/dist/browser/utils/theme-colors.js +4 -1
- package/dist/cjs/modules/excel/note.js +5 -1
- package/dist/cjs/modules/excel/row.js +35 -2
- package/dist/cjs/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/cjs/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/cjs/modules/excel/workbook.browser.js +31 -1
- package/dist/cjs/modules/excel/worksheet.js +83 -0
- package/dist/cjs/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/shape-xform.js +112 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/cjs/modules/pdf/builder/document-builder.js +21 -48
- package/dist/cjs/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/cjs/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/cjs/modules/pdf/font/font-manager.js +35 -18
- package/dist/cjs/modules/pdf/render/page-renderer.js +112 -18
- package/dist/cjs/modules/word/advanced/field-engine.js +45 -20
- package/dist/cjs/modules/word/advanced/glossary.js +8 -9
- package/dist/cjs/modules/word/advanced/math-convert.js +94 -12
- package/dist/cjs/modules/word/advanced/ole-objects.js +123 -19
- package/dist/cjs/modules/word/advanced/style-map.js +31 -10
- package/dist/cjs/modules/word/builder/run-builders.js +7 -1
- package/dist/cjs/modules/word/constants.js +5 -1
- package/dist/cjs/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/cjs/modules/word/convert/html/html-import.js +168 -14
- package/dist/cjs/modules/word/convert/html/html.js +2 -1
- package/dist/cjs/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/cjs/modules/word/convert/odt/odt.js +407 -56
- package/dist/cjs/modules/word/html.js +2 -1
- package/dist/cjs/modules/word/index.base.js +4 -3
- package/dist/cjs/modules/word/layout/layout-full.js +325 -18
- package/dist/cjs/modules/word/layout/render-page.js +35 -8
- package/dist/cjs/modules/word/query/compat.js +29 -21
- package/dist/cjs/modules/word/reader/docx-reader.js +104 -1
- package/dist/cjs/modules/word/reader/math-parser.js +8 -2
- package/dist/cjs/modules/word/security/cfb-reader.js +5 -5
- package/dist/cjs/modules/word/writer/docx-packager.js +108 -2
- package/dist/cjs/modules/word/writer/glossary-writer.js +124 -0
- package/dist/cjs/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/cjs/modules/word/writer/math-writer.js +7 -2
- package/dist/cjs/utils/font-metrics.js +44 -0
- package/dist/cjs/utils/theme-colors.js +4 -1
- package/dist/esm/modules/excel/note.js +5 -1
- package/dist/esm/modules/excel/row.js +35 -2
- package/dist/esm/modules/excel/stream/workbook-writer.browser.js +22 -2
- package/dist/esm/modules/excel/utils/drawing-utils.js +19 -2
- package/dist/esm/modules/excel/workbook.browser.js +32 -2
- package/dist/esm/modules/excel/worksheet.js +83 -0
- package/dist/esm/modules/excel/xlsx/xform/comment/vml-shape-xform.js +42 -8
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +3 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +5 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +18 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/blip-xform.js +38 -11
- package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +5 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/pic-xform.js +2 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/shape-xform.js +109 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +10 -1
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +64 -1
- package/dist/esm/modules/pdf/builder/document-builder.js +22 -49
- package/dist/esm/modules/pdf/builder/pdf-editor.js +1 -1
- package/dist/esm/modules/pdf/core/pdf-stream.js +38 -2
- package/dist/esm/modules/pdf/font/font-manager.js +35 -18
- package/dist/esm/modules/pdf/render/page-renderer.js +111 -18
- package/dist/esm/modules/word/advanced/field-engine.js +45 -20
- package/dist/esm/modules/word/advanced/glossary.js +8 -9
- package/dist/esm/modules/word/advanced/math-convert.js +94 -12
- package/dist/esm/modules/word/advanced/ole-objects.js +122 -19
- package/dist/esm/modules/word/advanced/style-map.js +31 -10
- package/dist/esm/modules/word/builder/run-builders.js +7 -1
- package/dist/esm/modules/word/constants.js +5 -1
- package/dist/esm/modules/word/convert/docx-to-semantic.js +135 -1
- package/dist/esm/modules/word/convert/html/html-import.js +167 -14
- package/dist/esm/modules/word/convert/html/html.js +1 -1
- package/dist/esm/modules/word/convert/markdown/markdown-import.js +279 -69
- package/dist/esm/modules/word/convert/odt/odt.js +407 -56
- package/dist/esm/modules/word/html.js +1 -1
- package/dist/esm/modules/word/index.base.js +1 -1
- package/dist/esm/modules/word/layout/layout-full.js +326 -19
- package/dist/esm/modules/word/layout/render-page.js +35 -8
- package/dist/esm/modules/word/query/compat.js +29 -21
- package/dist/esm/modules/word/reader/docx-reader.js +105 -2
- package/dist/esm/modules/word/reader/math-parser.js +8 -2
- package/dist/esm/modules/word/security/cfb-reader.js +5 -5
- package/dist/esm/modules/word/writer/docx-packager.js +108 -2
- package/dist/esm/modules/word/writer/glossary-writer.js +121 -0
- package/dist/esm/modules/word/writer/header-footer-writer.js +105 -20
- package/dist/esm/modules/word/writer/math-writer.js +7 -2
- package/dist/esm/utils/font-metrics.js +43 -0
- package/dist/esm/utils/theme-colors.js +4 -1
- package/dist/iife/excelts.iife.js +496 -59
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +39 -39
- package/dist/types/modules/excel/cell.d.ts +4 -0
- package/dist/types/modules/excel/stream/workbook-writer.browser.d.ts +8 -1
- package/dist/types/modules/excel/types.d.ts +81 -0
- package/dist/types/modules/excel/utils/drawing-utils.d.ts +8 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +16 -0
- package/dist/types/modules/excel/worksheet.d.ts +31 -1
- package/dist/types/modules/excel/xlsx/xform/comment/vml-shape-xform.d.ts +7 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/blip-xform.d.ts +6 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/pic-xform.d.ts +2 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/shape-xform.d.ts +47 -0
- package/dist/types/modules/pdf/core/pdf-stream.d.ts +28 -1
- package/dist/types/modules/pdf/font/font-manager.d.ts +26 -0
- package/dist/types/modules/pdf/render/page-renderer.d.ts +51 -3
- package/dist/types/modules/word/advanced/glossary.d.ts +10 -36
- package/dist/types/modules/word/advanced/ole-objects.d.ts +28 -0
- package/dist/types/modules/word/builder/run-builders.d.ts +7 -1
- package/dist/types/modules/word/constants.d.ts +4 -0
- package/dist/types/modules/word/convert/docx-to-semantic.d.ts +2 -1
- package/dist/types/modules/word/convert/html/html-import.d.ts +32 -1
- package/dist/types/modules/word/convert/html/html.d.ts +2 -2
- package/dist/types/modules/word/convert/markdown/markdown-import.d.ts +48 -18
- package/dist/types/modules/word/convert/markdown/markdown.d.ts +1 -1
- package/dist/types/modules/word/html.d.ts +2 -2
- package/dist/types/modules/word/index.base.d.ts +3 -3
- package/dist/types/modules/word/markdown.d.ts +1 -1
- package/dist/types/modules/word/query/compat.d.ts +10 -2
- package/dist/types/modules/word/types.d.ts +96 -1
- package/dist/types/modules/word/writer/glossary-writer.d.ts +28 -0
- package/dist/types/utils/font-metrics.d.ts +8 -0
- package/package.json +3 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* @cj-tech-master/excelts
|
|
2
|
+
* @cj-tech-master/excelts v10.0.0
|
|
3
3
|
* Zero-dependency TypeScript toolkit — Excel (XLSX), PDF, CSV, Markdown, XML, ZIP/TAR, and streaming.
|
|
4
4
|
* (c) 2026 cjnoname
|
|
5
5
|
* Released under the MIT License
|
|
@@ -17695,7 +17695,8 @@ onmessage = async (ev) => {
|
|
|
17695
17695
|
set model(value) {
|
|
17696
17696
|
const { note } = value;
|
|
17697
17697
|
const { texts } = note;
|
|
17698
|
-
|
|
17698
|
+
const hasCustomSize = note.width !== void 0 || note.height !== void 0;
|
|
17699
|
+
if (texts && texts.length === 1 && Object.keys(texts[0]).length === 1 && !hasCustomSize) this.note = texts[0].text;
|
|
17699
17700
|
else this.note = note;
|
|
17700
17701
|
this.author = value.author;
|
|
17701
17702
|
}
|
|
@@ -19865,6 +19866,30 @@ onmessage = async (ev) => {
|
|
|
19865
19866
|
}));
|
|
19866
19867
|
//#endregion
|
|
19867
19868
|
//#region src/modules/excel/row.ts
|
|
19869
|
+
/**
|
|
19870
|
+
* Resolve a column key against a row object, supporting dotted nested paths.
|
|
19871
|
+
*
|
|
19872
|
+
* A key without a `.` takes the original fast path (`obj[key]`), preserving
|
|
19873
|
+
* exact backward compatibility — including keys that legitimately contain a
|
|
19874
|
+
* dot only as a flat property name, which still resolve via the fast path
|
|
19875
|
+
* first. A dotted key (e.g. `"address.city"`) is resolved by walking each
|
|
19876
|
+
* segment; if any segment is missing or not an object, the result is
|
|
19877
|
+
* `undefined` (the same signal the caller already uses to skip a cell).
|
|
19878
|
+
*
|
|
19879
|
+
* @param obj - The row object supplied to `row.values = {...}` / `addRow({...})`.
|
|
19880
|
+
* @param key - The column key, optionally a dotted path.
|
|
19881
|
+
* @returns The resolved value, or `undefined` when the path cannot be followed.
|
|
19882
|
+
*/
|
|
19883
|
+
function resolveColumnKeyValue(obj, key) {
|
|
19884
|
+
const direct = obj[key];
|
|
19885
|
+
if (direct !== void 0 || !key.includes(".")) return direct;
|
|
19886
|
+
let current = obj;
|
|
19887
|
+
for (const segment of key.split(".")) {
|
|
19888
|
+
if (current === null || typeof current !== "object") return;
|
|
19889
|
+
current = current[segment];
|
|
19890
|
+
}
|
|
19891
|
+
return current;
|
|
19892
|
+
}
|
|
19868
19893
|
var Row;
|
|
19869
19894
|
var init_row = __esmMin((() => {
|
|
19870
19895
|
init_cell();
|
|
@@ -20031,11 +20056,12 @@ onmessage = async (ev) => {
|
|
|
20031
20056
|
}).value = item;
|
|
20032
20057
|
});
|
|
20033
20058
|
} else this._worksheet.eachColumnKey((column, key) => {
|
|
20034
|
-
|
|
20059
|
+
const resolved = resolveColumnKeyValue(value, key);
|
|
20060
|
+
if (resolved !== void 0) this.getCellEx({
|
|
20035
20061
|
address: colCache.encodeAddress(this._number, column.number),
|
|
20036
20062
|
row: this._number,
|
|
20037
20063
|
col: column.number
|
|
20038
|
-
}).value =
|
|
20064
|
+
}).value = resolved;
|
|
20039
20065
|
});
|
|
20040
20066
|
}
|
|
20041
20067
|
/**
|
|
@@ -28148,11 +28174,13 @@ self.onmessage = async function(event) {
|
|
|
28148
28174
|
}));
|
|
28149
28175
|
//#endregion
|
|
28150
28176
|
//#region src/modules/excel/xlsx/xform/comment/vml-shape-xform.ts
|
|
28151
|
-
var VmlShapeXform;
|
|
28177
|
+
var DEFAULT_NOTE_WIDTH_PT, DEFAULT_NOTE_HEIGHT_PT, VmlShapeXform;
|
|
28152
28178
|
var init_vml_shape_xform = __esmMin((() => {
|
|
28153
28179
|
init_base_xform();
|
|
28154
28180
|
init_vml_client_data_xform();
|
|
28155
28181
|
init_vml_textbox_xform();
|
|
28182
|
+
DEFAULT_NOTE_WIDTH_PT = 97.8;
|
|
28183
|
+
DEFAULT_NOTE_HEIGHT_PT = 59.1;
|
|
28156
28184
|
VmlShapeXform = class VmlShapeXform extends BaseXform {
|
|
28157
28185
|
constructor() {
|
|
28158
28186
|
super();
|
|
@@ -28190,6 +28218,13 @@ self.onmessage = async function(event) {
|
|
|
28190
28218
|
editAs: "",
|
|
28191
28219
|
protection: {}
|
|
28192
28220
|
};
|
|
28221
|
+
{
|
|
28222
|
+
const style = node.attributes.style ?? "";
|
|
28223
|
+
const width = VmlShapeXform.parseStyleLength(style, "width");
|
|
28224
|
+
const height = VmlShapeXform.parseStyleLength(style, "height");
|
|
28225
|
+
if (width !== void 0 && width !== DEFAULT_NOTE_WIDTH_PT) this.model.width = width;
|
|
28226
|
+
if (height !== void 0 && height !== DEFAULT_NOTE_HEIGHT_PT) this.model.height = height;
|
|
28227
|
+
}
|
|
28193
28228
|
break;
|
|
28194
28229
|
default:
|
|
28195
28230
|
this.parser = this.map[node.name];
|
|
@@ -28220,15 +28255,29 @@ self.onmessage = async function(event) {
|
|
|
28220
28255
|
default: return true;
|
|
28221
28256
|
}
|
|
28222
28257
|
}
|
|
28258
|
+
/**
|
|
28259
|
+
* Extract a points-valued length (e.g. `width:120pt`) from a VML style
|
|
28260
|
+
* string. Returns `undefined` when the property is absent or not in `pt`.
|
|
28261
|
+
*/
|
|
28262
|
+
static parseStyleLength(style, prop) {
|
|
28263
|
+
const match = new RegExp(`(?:^|;)\\s*${prop}\\s*:\\s*([0-9.]+)pt`, "i").exec(style);
|
|
28264
|
+
if (!match) return;
|
|
28265
|
+
const value = parseFloat(match[1]);
|
|
28266
|
+
return Number.isFinite(value) ? value : void 0;
|
|
28267
|
+
}
|
|
28223
28268
|
static {
|
|
28224
|
-
this.V_SHAPE_ATTRIBUTES = (model, index) =>
|
|
28225
|
-
|
|
28226
|
-
|
|
28227
|
-
|
|
28228
|
-
|
|
28229
|
-
|
|
28230
|
-
|
|
28231
|
-
|
|
28269
|
+
this.V_SHAPE_ATTRIBUTES = (model, index) => {
|
|
28270
|
+
const width = model.note?.width ?? DEFAULT_NOTE_WIDTH_PT;
|
|
28271
|
+
const height = model.note?.height ?? DEFAULT_NOTE_HEIGHT_PT;
|
|
28272
|
+
return {
|
|
28273
|
+
id: `_x0000_s${1025 + index}`,
|
|
28274
|
+
type: "#_x0000_t202",
|
|
28275
|
+
style: `position:absolute; margin-left:105.3pt;margin-top:10.5pt;width:${width}pt;height:${height}pt;z-index:1;visibility:hidden`,
|
|
28276
|
+
fillcolor: "infoBackground [80]",
|
|
28277
|
+
strokecolor: "none [81]",
|
|
28278
|
+
"o:insetmode": model.note.margins && model.note.margins.insetmode
|
|
28279
|
+
};
|
|
28280
|
+
};
|
|
28232
28281
|
}
|
|
28233
28282
|
};
|
|
28234
28283
|
}));
|
|
@@ -28549,6 +28598,19 @@ self.onmessage = async function(event) {
|
|
|
28549
28598
|
},
|
|
28550
28599
|
range: medium.range
|
|
28551
28600
|
};
|
|
28601
|
+
if (bookImage.svgMediaId !== void 0) {
|
|
28602
|
+
const svgKey = `svg:${bookImage.svgMediaId}`;
|
|
28603
|
+
let rIdSvg = imageRIdMap[svgKey];
|
|
28604
|
+
if (!rIdSvg) {
|
|
28605
|
+
const svgImage = options.getBookImage(bookImage.svgMediaId);
|
|
28606
|
+
if (svgImage) {
|
|
28607
|
+
rIdSvg = options.nextRId(rels);
|
|
28608
|
+
imageRIdMap[svgKey] = rIdSvg;
|
|
28609
|
+
rels.push(buildImageRel(rIdSvg, svgImage));
|
|
28610
|
+
}
|
|
28611
|
+
}
|
|
28612
|
+
if (rIdSvg) anchor.picture.svgRId = rIdSvg;
|
|
28613
|
+
}
|
|
28552
28614
|
if (medium.opacity !== void 0) {
|
|
28553
28615
|
const clamped = Math.max(0, Math.min(1, medium.opacity));
|
|
28554
28616
|
anchor.picture.alphaModFix = Math.round(clamped * 1e5);
|
|
@@ -28584,7 +28646,7 @@ self.onmessage = async function(event) {
|
|
|
28584
28646
|
if (a == null) return false;
|
|
28585
28647
|
if (a.range?.pos !== void 0) return !!a.picture || !!a.graphicFrame || !!a.shape;
|
|
28586
28648
|
if (a.range?.br && a.shape) return true;
|
|
28587
|
-
if (!a.range?.br && !a.picture && !a.graphicFrame) return false;
|
|
28649
|
+
if (!a.range?.br && !a.picture && !a.graphicFrame && !a.shape) return false;
|
|
28588
28650
|
if (a.range?.br && !a.picture && !a.shape && !a.graphicFrame) return false;
|
|
28589
28651
|
return true;
|
|
28590
28652
|
});
|
|
@@ -33201,7 +33263,7 @@ self.onmessage = async function(event) {
|
|
|
33201
33263
|
mediaHash[imageType] = true;
|
|
33202
33264
|
xmlStream.leafNode("Default", {
|
|
33203
33265
|
Extension: imageType,
|
|
33204
|
-
ContentType: `image/${imageType}`
|
|
33266
|
+
ContentType: imageType === "svg" ? "image/svg+xml" : `image/${imageType}`
|
|
33205
33267
|
});
|
|
33206
33268
|
}
|
|
33207
33269
|
}
|
|
@@ -33634,7 +33696,16 @@ self.onmessage = async function(event) {
|
|
|
33634
33696
|
const name = match[1];
|
|
33635
33697
|
const mediaId = options.mediaIndex[name];
|
|
33636
33698
|
const medium = options.media[mediaId];
|
|
33637
|
-
if (medium
|
|
33699
|
+
if (!medium) return;
|
|
33700
|
+
if (model.svgRId) {
|
|
33701
|
+
const svgRel = options.rels[model.svgRId];
|
|
33702
|
+
const svgMatch = svgRel && svgRel.Target.match(/.*\/media\/(.+[.][a-zA-Z]{3,4})/);
|
|
33703
|
+
if (svgMatch) {
|
|
33704
|
+
const svgMediaId = options.mediaIndex[svgMatch[1]];
|
|
33705
|
+
if (svgMediaId !== void 0) medium.svgMediaId = svgMediaId;
|
|
33706
|
+
}
|
|
33707
|
+
}
|
|
33708
|
+
if (model.alphaModFix !== void 0) return {
|
|
33638
33709
|
...medium,
|
|
33639
33710
|
alphaModFix: model.alphaModFix
|
|
33640
33711
|
};
|
|
@@ -33873,9 +33944,12 @@ self.onmessage = async function(event) {
|
|
|
33873
33944
|
}));
|
|
33874
33945
|
//#endregion
|
|
33875
33946
|
//#region src/modules/excel/xlsx/xform/drawing/blip-xform.ts
|
|
33876
|
-
var BlipXform;
|
|
33947
|
+
var SVG_BLIP_EXT_URI, SVG_BLIP_NS, REL_NS, BlipXform;
|
|
33877
33948
|
var init_blip_xform = __esmMin((() => {
|
|
33878
33949
|
init_base_xform();
|
|
33950
|
+
SVG_BLIP_EXT_URI = "{96DAC541-7B7A-43D3-8B79-37D633B846F1}";
|
|
33951
|
+
SVG_BLIP_NS = "http://schemas.microsoft.com/office/drawing/2016/SVG/main";
|
|
33952
|
+
REL_NS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
33879
33953
|
BlipXform = class extends BaseXform {
|
|
33880
33954
|
constructor() {
|
|
33881
33955
|
super();
|
|
@@ -33886,19 +33960,33 @@ self.onmessage = async function(event) {
|
|
|
33886
33960
|
}
|
|
33887
33961
|
render(xmlStream, model) {
|
|
33888
33962
|
const relAttr = model.external ? "r:link" : "r:embed";
|
|
33889
|
-
|
|
33890
|
-
|
|
33891
|
-
|
|
33963
|
+
const hasAlpha = model.alphaModFix !== void 0 && model.alphaModFix < 1e5;
|
|
33964
|
+
const hasSvg = model.svgRId !== void 0;
|
|
33965
|
+
if (!hasAlpha && !hasSvg) {
|
|
33966
|
+
xmlStream.leafNode(this.tag, {
|
|
33967
|
+
"xmlns:r": REL_NS,
|
|
33892
33968
|
[relAttr]: model.rId,
|
|
33893
33969
|
cstate: "print"
|
|
33894
33970
|
});
|
|
33895
|
-
|
|
33896
|
-
|
|
33897
|
-
|
|
33898
|
-
"xmlns:r":
|
|
33971
|
+
return;
|
|
33972
|
+
}
|
|
33973
|
+
xmlStream.openNode(this.tag, {
|
|
33974
|
+
"xmlns:r": REL_NS,
|
|
33899
33975
|
[relAttr]: model.rId,
|
|
33900
33976
|
cstate: "print"
|
|
33901
33977
|
});
|
|
33978
|
+
if (hasAlpha) xmlStream.leafNode("a:alphaModFix", { amt: String(model.alphaModFix) });
|
|
33979
|
+
if (hasSvg) {
|
|
33980
|
+
xmlStream.openNode("a:extLst");
|
|
33981
|
+
xmlStream.openNode("a:ext", { uri: SVG_BLIP_EXT_URI });
|
|
33982
|
+
xmlStream.leafNode("asvg:svgBlip", {
|
|
33983
|
+
"xmlns:asvg": SVG_BLIP_NS,
|
|
33984
|
+
"r:embed": model.svgRId
|
|
33985
|
+
});
|
|
33986
|
+
xmlStream.closeNode();
|
|
33987
|
+
xmlStream.closeNode();
|
|
33988
|
+
}
|
|
33989
|
+
xmlStream.closeNode();
|
|
33902
33990
|
}
|
|
33903
33991
|
parseOpen(node) {
|
|
33904
33992
|
switch (node.name) {
|
|
@@ -33914,6 +34002,11 @@ self.onmessage = async function(event) {
|
|
|
33914
34002
|
case "a:alphaModFix":
|
|
33915
34003
|
if (node.attributes.amt) this.model.alphaModFix = parseInt(node.attributes.amt, 10);
|
|
33916
34004
|
return true;
|
|
34005
|
+
case "asvg:svgBlip": {
|
|
34006
|
+
const embed = node.attributes["r:embed"];
|
|
34007
|
+
if (embed !== void 0 && this.model) this.model.svgRId = embed;
|
|
34008
|
+
return true;
|
|
34009
|
+
}
|
|
33917
34010
|
default: return true;
|
|
33918
34011
|
}
|
|
33919
34012
|
}
|
|
@@ -34251,7 +34344,8 @@ self.onmessage = async function(event) {
|
|
|
34251
34344
|
this.map["xdr:blipFill"].render(xmlStream, {
|
|
34252
34345
|
rId: model.rId,
|
|
34253
34346
|
alphaModFix: model.alphaModFix,
|
|
34254
|
-
external: model.external
|
|
34347
|
+
external: model.external,
|
|
34348
|
+
svgRId: model.svgRId
|
|
34255
34349
|
});
|
|
34256
34350
|
this.map["xdr:spPr"].render(xmlStream, model);
|
|
34257
34351
|
xmlStream.closeNode();
|
|
@@ -34289,6 +34383,105 @@ self.onmessage = async function(event) {
|
|
|
34289
34383
|
};
|
|
34290
34384
|
}));
|
|
34291
34385
|
//#endregion
|
|
34386
|
+
//#region src/modules/excel/xlsx/xform/drawing/shape-xform.ts
|
|
34387
|
+
/**
|
|
34388
|
+
* Normalize a user-supplied colour to the bare 6-digit RGB hex that OOXML's
|
|
34389
|
+
* `<a:srgbClr val="...">` requires:
|
|
34390
|
+
* - strips a leading `#`
|
|
34391
|
+
* - accepts 8-digit ARGB (the form excelts uses for cell fills) and drops the
|
|
34392
|
+
* leading alpha byte, since `srgbClr` carries no alpha channel
|
|
34393
|
+
* - upper-cases
|
|
34394
|
+
*
|
|
34395
|
+
* Anything that isn't a 6- or 8-digit hex string is passed through unchanged so
|
|
34396
|
+
* a caller using a less common form is not silently broken.
|
|
34397
|
+
*/
|
|
34398
|
+
function normalizeColor(color) {
|
|
34399
|
+
const hex = color.startsWith("#") ? color.slice(1) : color;
|
|
34400
|
+
if (/^[0-9a-fA-F]{8}$/.test(hex)) return hex.slice(2).toUpperCase();
|
|
34401
|
+
if (/^[0-9a-fA-F]{6}$/.test(hex)) return hex.toUpperCase();
|
|
34402
|
+
return hex;
|
|
34403
|
+
}
|
|
34404
|
+
var EMU_PER_POINT$1, ShapeXform;
|
|
34405
|
+
var init_shape_xform = __esmMin((() => {
|
|
34406
|
+
init_base_xform();
|
|
34407
|
+
EMU_PER_POINT$1 = 12700;
|
|
34408
|
+
ShapeXform = class extends BaseXform {
|
|
34409
|
+
get tag() {
|
|
34410
|
+
return "xdr:sp";
|
|
34411
|
+
}
|
|
34412
|
+
render(xmlStream, model) {
|
|
34413
|
+
xmlStream.openNode("xdr:sp", {
|
|
34414
|
+
macro: "",
|
|
34415
|
+
textlink: ""
|
|
34416
|
+
});
|
|
34417
|
+
xmlStream.openNode("xdr:nvSpPr");
|
|
34418
|
+
xmlStream.leafNode("xdr:cNvPr", {
|
|
34419
|
+
id: model.cNvPrId,
|
|
34420
|
+
name: model.name
|
|
34421
|
+
});
|
|
34422
|
+
xmlStream.leafNode("xdr:cNvSpPr", {});
|
|
34423
|
+
xmlStream.closeNode();
|
|
34424
|
+
xmlStream.openNode("xdr:spPr");
|
|
34425
|
+
xmlStream.openNode("a:xfrm");
|
|
34426
|
+
xmlStream.leafNode("a:off", {
|
|
34427
|
+
x: 0,
|
|
34428
|
+
y: 0
|
|
34429
|
+
});
|
|
34430
|
+
xmlStream.leafNode("a:ext", {
|
|
34431
|
+
cx: 0,
|
|
34432
|
+
cy: 0
|
|
34433
|
+
});
|
|
34434
|
+
xmlStream.closeNode();
|
|
34435
|
+
xmlStream.openNode("a:prstGeom", { prst: model.shapeType });
|
|
34436
|
+
xmlStream.leafNode("a:avLst");
|
|
34437
|
+
xmlStream.closeNode();
|
|
34438
|
+
if (model.fill && model.fill.color) {
|
|
34439
|
+
xmlStream.openNode("a:solidFill");
|
|
34440
|
+
xmlStream.leafNode("a:srgbClr", { val: normalizeColor(model.fill.color) });
|
|
34441
|
+
xmlStream.closeNode();
|
|
34442
|
+
} else xmlStream.leafNode("a:noFill");
|
|
34443
|
+
if (model.line && (model.line.color || model.line.width !== void 0)) {
|
|
34444
|
+
const lnAttrs = {};
|
|
34445
|
+
if (model.line.width !== void 0) lnAttrs.w = Math.round(model.line.width * EMU_PER_POINT$1);
|
|
34446
|
+
xmlStream.openNode("a:ln", lnAttrs);
|
|
34447
|
+
if (model.line.color) {
|
|
34448
|
+
xmlStream.openNode("a:solidFill");
|
|
34449
|
+
xmlStream.leafNode("a:srgbClr", { val: normalizeColor(model.line.color) });
|
|
34450
|
+
xmlStream.closeNode();
|
|
34451
|
+
}
|
|
34452
|
+
xmlStream.closeNode();
|
|
34453
|
+
} else {
|
|
34454
|
+
xmlStream.openNode("a:ln");
|
|
34455
|
+
xmlStream.leafNode("a:noFill");
|
|
34456
|
+
xmlStream.closeNode();
|
|
34457
|
+
}
|
|
34458
|
+
xmlStream.closeNode();
|
|
34459
|
+
xmlStream.openNode("xdr:txBody");
|
|
34460
|
+
xmlStream.leafNode("a:bodyPr", {
|
|
34461
|
+
vertOverflow: "clip",
|
|
34462
|
+
wrap: "square",
|
|
34463
|
+
anchor: "ctr"
|
|
34464
|
+
});
|
|
34465
|
+
xmlStream.leafNode("a:lstStyle");
|
|
34466
|
+
xmlStream.openNode("a:p");
|
|
34467
|
+
xmlStream.openNode("a:pPr", { algn: "ctr" });
|
|
34468
|
+
xmlStream.closeNode();
|
|
34469
|
+
if (model.text) {
|
|
34470
|
+
xmlStream.openNode("a:r");
|
|
34471
|
+
xmlStream.openNode("a:rPr", { lang: "en-US" });
|
|
34472
|
+
xmlStream.closeNode();
|
|
34473
|
+
xmlStream.openNode("a:t");
|
|
34474
|
+
xmlStream.writeText(model.text);
|
|
34475
|
+
xmlStream.closeNode();
|
|
34476
|
+
xmlStream.closeNode();
|
|
34477
|
+
} else xmlStream.leafNode("a:endParaRPr", { lang: "en-US" });
|
|
34478
|
+
xmlStream.closeNode();
|
|
34479
|
+
xmlStream.closeNode();
|
|
34480
|
+
xmlStream.closeNode();
|
|
34481
|
+
}
|
|
34482
|
+
};
|
|
34483
|
+
}));
|
|
34484
|
+
//#endregion
|
|
34292
34485
|
//#region src/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.ts
|
|
34293
34486
|
var EMU_PER_PIXEL_AT_96_DPI, PosXform, AbsoluteAnchorXform;
|
|
34294
34487
|
var init_absolute_anchor_xform = __esmMin((() => {
|
|
@@ -34297,6 +34490,7 @@ self.onmessage = async function(event) {
|
|
|
34297
34490
|
init_ext_xform();
|
|
34298
34491
|
init_graphic_frame_xform();
|
|
34299
34492
|
init_pic_xform();
|
|
34493
|
+
init_shape_xform();
|
|
34300
34494
|
init_static_xform();
|
|
34301
34495
|
EMU_PER_PIXEL_AT_96_DPI = 9525;
|
|
34302
34496
|
PosXform = class extends BaseXform {
|
|
@@ -34340,6 +34534,7 @@ self.onmessage = async function(event) {
|
|
|
34340
34534
|
"xdr:ext": new ExtXform({ tag: "xdr:ext" }),
|
|
34341
34535
|
"xdr:pic": new PicXform(),
|
|
34342
34536
|
"xdr:graphicFrame": new GraphicFrameXform(),
|
|
34537
|
+
"xdr:userShape": new ShapeXform(),
|
|
34343
34538
|
"xdr:clientData": new StaticXform({ tag: "xdr:clientData" })
|
|
34344
34539
|
};
|
|
34345
34540
|
}
|
|
@@ -34359,6 +34554,7 @@ self.onmessage = async function(event) {
|
|
|
34359
34554
|
this.map["xdr:ext"].render(xmlStream, model.range.ext);
|
|
34360
34555
|
if (model.picture) this.map["xdr:pic"].render(xmlStream, model.picture);
|
|
34361
34556
|
else if (model.graphicFrame) this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
34557
|
+
else if (model.shape?.kind === "userShape") this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
34362
34558
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
34363
34559
|
xmlStream.closeNode();
|
|
34364
34560
|
}
|
|
@@ -34472,6 +34668,7 @@ self.onmessage = async function(event) {
|
|
|
34472
34668
|
init_ext_xform();
|
|
34473
34669
|
init_graphic_frame_xform();
|
|
34474
34670
|
init_pic_xform();
|
|
34671
|
+
init_shape_xform();
|
|
34475
34672
|
init_static_xform();
|
|
34476
34673
|
OneCellAnchorXform = class extends BaseCellAnchorXform {
|
|
34477
34674
|
constructor() {
|
|
@@ -34480,6 +34677,7 @@ self.onmessage = async function(event) {
|
|
|
34480
34677
|
"xdr:from": new CellPositionXform({ tag: "xdr:from" }),
|
|
34481
34678
|
"xdr:ext": new ExtXform({ tag: "xdr:ext" }),
|
|
34482
34679
|
"xdr:pic": new PicXform(),
|
|
34680
|
+
"xdr:userShape": new ShapeXform(),
|
|
34483
34681
|
"xdr:graphicFrame": new GraphicFrameXform(),
|
|
34484
34682
|
"xdr:clientData": new StaticXform({ tag: "xdr:clientData" })
|
|
34485
34683
|
};
|
|
@@ -34497,6 +34695,7 @@ self.onmessage = async function(event) {
|
|
|
34497
34695
|
this.map["xdr:ext"].render(xmlStream, model.range.ext);
|
|
34498
34696
|
if (model.picture) this.map["xdr:pic"].render(xmlStream, model.picture);
|
|
34499
34697
|
else if (model.graphicFrame) this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
34698
|
+
else if (model.shape?.kind === "userShape") this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
34500
34699
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
34501
34700
|
xmlStream.closeNode();
|
|
34502
34701
|
}
|
|
@@ -34659,6 +34858,7 @@ self.onmessage = async function(event) {
|
|
|
34659
34858
|
init_cell_position_xform();
|
|
34660
34859
|
init_graphic_frame_xform();
|
|
34661
34860
|
init_pic_xform();
|
|
34861
|
+
init_shape_xform();
|
|
34662
34862
|
init_sp_xform();
|
|
34663
34863
|
init_static_xform();
|
|
34664
34864
|
TwoCellAnchorXform = class extends BaseCellAnchorXform {
|
|
@@ -34673,6 +34873,7 @@ self.onmessage = async function(event) {
|
|
|
34673
34873
|
"xdr:to": new CellPositionXform({ tag: "xdr:to" }),
|
|
34674
34874
|
"xdr:pic": new PicXform(),
|
|
34675
34875
|
"xdr:sp": new SpXform(),
|
|
34876
|
+
"xdr:userShape": new ShapeXform(),
|
|
34676
34877
|
"xdr:graphicFrame": new GraphicFrameXform(),
|
|
34677
34878
|
"xdr:clientData": new StaticXform({ tag: "xdr:clientData" })
|
|
34678
34879
|
};
|
|
@@ -34703,7 +34904,8 @@ self.onmessage = async function(event) {
|
|
|
34703
34904
|
if (isChartEx) this.renderChartExAlternateContent(xmlStream, model);
|
|
34704
34905
|
else if (model.picture) this.map["xdr:pic"].render(xmlStream, model.picture);
|
|
34705
34906
|
else if (model.graphicFrame) this.map["xdr:graphicFrame"].render(xmlStream, model.graphicFrame);
|
|
34706
|
-
else if (model.shape) this.map["xdr:
|
|
34907
|
+
else if (model.shape) if (model.shape.kind === "userShape") this.map["xdr:userShape"].render(xmlStream, model.shape);
|
|
34908
|
+
else this.map["xdr:sp"].render(xmlStream, model.shape);
|
|
34707
34909
|
this.map["xdr:clientData"].render(xmlStream, {});
|
|
34708
34910
|
xmlStream.closeNode();
|
|
34709
34911
|
if (wrapAnchorInAc) {
|
|
@@ -35561,13 +35763,25 @@ self.onmessage = async function(event) {
|
|
|
35561
35763
|
* ```
|
|
35562
35764
|
*/
|
|
35563
35765
|
addImage(image) {
|
|
35766
|
+
const { svg, ...raster } = image;
|
|
35767
|
+
if (svg && raster.link && raster.buffer == null && raster.base64 == null && raster.filename == null) throw new ImageError("An SVG image requires an embedded raster fallback (buffer/base64/filename); it cannot be combined with an external link.");
|
|
35564
35768
|
const id = this.media.length;
|
|
35565
35769
|
const medium = {
|
|
35566
|
-
...
|
|
35770
|
+
...raster,
|
|
35567
35771
|
type: "image",
|
|
35568
|
-
name: `image${id}.${
|
|
35772
|
+
name: `image${id}.${raster.extension}`
|
|
35569
35773
|
};
|
|
35570
35774
|
this.media.push(medium);
|
|
35775
|
+
if (svg) {
|
|
35776
|
+
const svgId = this.media.length;
|
|
35777
|
+
this.media.push({
|
|
35778
|
+
...svg,
|
|
35779
|
+
type: "image",
|
|
35780
|
+
extension: "svg",
|
|
35781
|
+
name: `image${svgId}.svg`
|
|
35782
|
+
});
|
|
35783
|
+
medium.svgMediaId = svgId;
|
|
35784
|
+
}
|
|
35571
35785
|
return id;
|
|
35572
35786
|
}
|
|
35573
35787
|
getImage(id) {
|
|
@@ -41539,6 +41753,7 @@ self.onmessage = async function(event) {
|
|
|
41539
41753
|
this.views = options.views ?? [];
|
|
41540
41754
|
this.autoFilter = options.autoFilter ?? null;
|
|
41541
41755
|
this._media = [];
|
|
41756
|
+
this._shapes = [];
|
|
41542
41757
|
this._charts = [];
|
|
41543
41758
|
this._sparklineGroups = [];
|
|
41544
41759
|
this.sheetProtection = null;
|
|
@@ -42139,6 +42354,74 @@ self.onmessage = async function(event) {
|
|
|
42139
42354
|
};
|
|
42140
42355
|
this._media.push(new Image(this, model));
|
|
42141
42356
|
}
|
|
42357
|
+
/**
|
|
42358
|
+
* Add a free-form drawing shape (rectangle, ellipse, line, text box, …) to
|
|
42359
|
+
* the worksheet, anchored to a cell range.
|
|
42360
|
+
*
|
|
42361
|
+
* Unlike images, shapes need no media file — the geometry, fill, outline and
|
|
42362
|
+
* optional text label are written directly into the drawing part.
|
|
42363
|
+
*
|
|
42364
|
+
* @example
|
|
42365
|
+
* ```typescript
|
|
42366
|
+
* worksheet.addShape({
|
|
42367
|
+
* type: "rect",
|
|
42368
|
+
* range: "B2:D5",
|
|
42369
|
+
* fillColor: "FFD966",
|
|
42370
|
+
* lineColor: "000000",
|
|
42371
|
+
* lineWidth: 1,
|
|
42372
|
+
* text: "Important"
|
|
42373
|
+
* });
|
|
42374
|
+
* ```
|
|
42375
|
+
*/
|
|
42376
|
+
addShape(options) {
|
|
42377
|
+
const range = options.range;
|
|
42378
|
+
if (!(typeof range === "string" && range.includes(":") || typeof range === "object" && range !== null && ("br" in range || "ext" in range || "pos" in range))) throw new ImageError("addShape requires a range covering an area: a cell range like \"B2:D5\", or an object with `br`, `ext`, or `pos`.");
|
|
42379
|
+
this._shapes.push({
|
|
42380
|
+
type: "shape",
|
|
42381
|
+
shapeType: options.type ?? "rect",
|
|
42382
|
+
range,
|
|
42383
|
+
fillColor: options.fillColor,
|
|
42384
|
+
lineColor: options.lineColor,
|
|
42385
|
+
lineWidth: options.lineWidth,
|
|
42386
|
+
text: options.text,
|
|
42387
|
+
name: options.name
|
|
42388
|
+
});
|
|
42389
|
+
}
|
|
42390
|
+
/** All shapes added to this worksheet. */
|
|
42391
|
+
getShapes() {
|
|
42392
|
+
return this._shapes.slice();
|
|
42393
|
+
}
|
|
42394
|
+
/**
|
|
42395
|
+
* Resolve a shape's `range` into concrete two-cell anchor coordinates,
|
|
42396
|
+
* reusing the `Image` range parser so cell-address/anchor handling stays in
|
|
42397
|
+
* one place. Returns a serializable ShapeModel for the worksheet xform.
|
|
42398
|
+
*/
|
|
42399
|
+
_resolveShapeModel(shape) {
|
|
42400
|
+
let range;
|
|
42401
|
+
try {
|
|
42402
|
+
range = new Image(this, {
|
|
42403
|
+
type: "image",
|
|
42404
|
+
imageId: "",
|
|
42405
|
+
range: shape.range
|
|
42406
|
+
}).model.range;
|
|
42407
|
+
} catch {
|
|
42408
|
+
range = void 0;
|
|
42409
|
+
}
|
|
42410
|
+
if (!range) return {
|
|
42411
|
+
...shape,
|
|
42412
|
+
anchorRange: void 0
|
|
42413
|
+
};
|
|
42414
|
+
return {
|
|
42415
|
+
...shape,
|
|
42416
|
+
anchorRange: {
|
|
42417
|
+
tl: range.tl,
|
|
42418
|
+
br: range.br,
|
|
42419
|
+
ext: range.ext,
|
|
42420
|
+
pos: range.pos,
|
|
42421
|
+
editAs: range.editAs
|
|
42422
|
+
}
|
|
42423
|
+
};
|
|
42424
|
+
}
|
|
42142
42425
|
getImages() {
|
|
42143
42426
|
return this._media.filter((m) => m.type === "image");
|
|
42144
42427
|
}
|
|
@@ -42787,6 +43070,7 @@ self.onmessage = async function(event) {
|
|
|
42787
43070
|
views: this.views,
|
|
42788
43071
|
autoFilter: this.autoFilter,
|
|
42789
43072
|
media: this._media.map((medium) => medium.model),
|
|
43073
|
+
shapes: this._shapes.map((shape) => this._resolveShapeModel(shape)),
|
|
42790
43074
|
sheetProtection: this.sheetProtection,
|
|
42791
43075
|
tables: Object.values(this.tables).map((table) => table.model),
|
|
42792
43076
|
pivotTables: this.pivotTables,
|
|
@@ -42840,6 +43124,7 @@ self.onmessage = async function(event) {
|
|
|
42840
43124
|
this.views = value.views;
|
|
42841
43125
|
this.autoFilter = value.autoFilter;
|
|
42842
43126
|
this._media = value.media.map((medium) => new Image(this, medium));
|
|
43127
|
+
this._shapes = value.shapes ? value.shapes.slice() : [];
|
|
42843
43128
|
this._watermark = value.watermark ?? null;
|
|
42844
43129
|
if (!this._watermark) {
|
|
42845
43130
|
for (const medium of this._media) if (medium.type === "watermark") {
|
|
@@ -51335,6 +51620,60 @@ self.onmessage = async function(event) {
|
|
|
51335
51620
|
});
|
|
51336
51621
|
}
|
|
51337
51622
|
}
|
|
51623
|
+
const shapes = model.shapes ?? [];
|
|
51624
|
+
if (shapes.length > 0) {
|
|
51625
|
+
let { drawing } = model;
|
|
51626
|
+
if (!drawing) {
|
|
51627
|
+
drawing = model.drawing = {
|
|
51628
|
+
rId: nextRid(rels),
|
|
51629
|
+
name: `drawing${++options.drawingsCount}`,
|
|
51630
|
+
anchors: [],
|
|
51631
|
+
rels: []
|
|
51632
|
+
};
|
|
51633
|
+
options.drawings.push(drawing);
|
|
51634
|
+
rels.push({
|
|
51635
|
+
Id: drawing.rId,
|
|
51636
|
+
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
|
|
51637
|
+
Target: drawingRelTargetFromWorksheet(drawing.name)
|
|
51638
|
+
});
|
|
51639
|
+
}
|
|
51640
|
+
for (const shape of shapes) {
|
|
51641
|
+
const anchorRange = shape.anchorRange;
|
|
51642
|
+
if (!anchorRange) continue;
|
|
51643
|
+
let range;
|
|
51644
|
+
if (anchorRange.pos) range = {
|
|
51645
|
+
pos: anchorRange.pos,
|
|
51646
|
+
ext: anchorRange.ext,
|
|
51647
|
+
editAs: "absolute"
|
|
51648
|
+
};
|
|
51649
|
+
else if (anchorRange.br) range = {
|
|
51650
|
+
tl: anchorRange.tl,
|
|
51651
|
+
br: anchorRange.br,
|
|
51652
|
+
editAs: anchorRange.editAs ?? "oneCell"
|
|
51653
|
+
};
|
|
51654
|
+
else range = {
|
|
51655
|
+
tl: anchorRange.tl,
|
|
51656
|
+
ext: anchorRange.ext,
|
|
51657
|
+
editAs: anchorRange.editAs ?? "oneCell"
|
|
51658
|
+
};
|
|
51659
|
+
const cNvPrId = drawing.anchors.length + 1;
|
|
51660
|
+
drawing.anchors.push({
|
|
51661
|
+
range,
|
|
51662
|
+
shape: {
|
|
51663
|
+
kind: "userShape",
|
|
51664
|
+
cNvPrId,
|
|
51665
|
+
name: shape.name ?? `Shape ${cNvPrId}`,
|
|
51666
|
+
shapeType: shape.shapeType,
|
|
51667
|
+
fill: shape.fillColor ? { color: shape.fillColor } : void 0,
|
|
51668
|
+
line: shape.lineColor !== void 0 || shape.lineWidth !== void 0 ? {
|
|
51669
|
+
color: shape.lineColor,
|
|
51670
|
+
width: shape.lineWidth
|
|
51671
|
+
} : void 0,
|
|
51672
|
+
text: shape.text
|
|
51673
|
+
}
|
|
51674
|
+
});
|
|
51675
|
+
}
|
|
51676
|
+
}
|
|
51338
51677
|
if (headerImageMedia.length > 0) {
|
|
51339
51678
|
const medium = headerImageMedia[0];
|
|
51340
51679
|
const bookImage = options.media[medium.imageId];
|
|
@@ -58425,13 +58764,35 @@ self.onmessage = async function(event) {
|
|
|
58425
58764
|
* const id = workbook.addImage({ extension: "png", link: "https://example.com/logo.png" });
|
|
58426
58765
|
* worksheet.addImage(id, "B2:D6");
|
|
58427
58766
|
* ```
|
|
58767
|
+
*
|
|
58768
|
+
* @example SVG with raster fallback — crisp in modern Excel, safe everywhere
|
|
58769
|
+
* ```typescript
|
|
58770
|
+
* const id = workbook.addImage({
|
|
58771
|
+
* buffer: pngFallbackBytes, // shown by older Excel / non-SVG consumers
|
|
58772
|
+
* extension: "png",
|
|
58773
|
+
* svg: { buffer: svgBytes } // shown by Excel 2016+
|
|
58774
|
+
* });
|
|
58775
|
+
* worksheet.addImage(id, "B2:D6");
|
|
58776
|
+
* ```
|
|
58428
58777
|
*/
|
|
58429
58778
|
addImage(image) {
|
|
58779
|
+
const { svg, ...raster } = image;
|
|
58780
|
+
if (svg && raster.link && raster.buffer == null && raster.base64 == null && raster.filename == null) throw new ImageError("An SVG image requires an embedded raster fallback (buffer/base64/filename); it cannot be combined with an external link.");
|
|
58430
58781
|
const id = this.media.length;
|
|
58431
|
-
|
|
58432
|
-
...
|
|
58782
|
+
const rasterMedia = {
|
|
58783
|
+
...raster,
|
|
58433
58784
|
type: "image"
|
|
58434
|
-
}
|
|
58785
|
+
};
|
|
58786
|
+
this.media.push(rasterMedia);
|
|
58787
|
+
if (svg) {
|
|
58788
|
+
const svgId = this.media.length;
|
|
58789
|
+
this.media.push({
|
|
58790
|
+
...svg,
|
|
58791
|
+
type: "image",
|
|
58792
|
+
extension: "svg"
|
|
58793
|
+
});
|
|
58794
|
+
rasterMedia.svgMediaId = svgId;
|
|
58795
|
+
}
|
|
58435
58796
|
return id;
|
|
58436
58797
|
}
|
|
58437
58798
|
getImage(id) {
|
|
@@ -60675,6 +61036,17 @@ self.onmessage = async function(event) {
|
|
|
60675
61036
|
return this;
|
|
60676
61037
|
}
|
|
60677
61038
|
/**
|
|
61039
|
+
* Append a deferred fragment whose body is evaluated only at serialization
|
|
61040
|
+
* time. Used by text drawing so the final byte encoding can be chosen after
|
|
61041
|
+
* the document's fonts are resolved at build time. The fragment occupies its
|
|
61042
|
+
* draw-order slot immediately, so z-order relative to other operators is
|
|
61043
|
+
* preserved.
|
|
61044
|
+
*/
|
|
61045
|
+
deferred(produce) {
|
|
61046
|
+
this.parts.push(produce);
|
|
61047
|
+
return this;
|
|
61048
|
+
}
|
|
61049
|
+
/**
|
|
60678
61050
|
* Save the current graphics state (push onto state stack).
|
|
60679
61051
|
* Must be balanced with a corresponding restore().
|
|
60680
61052
|
*/
|
|
@@ -61033,10 +61405,23 @@ self.onmessage = async function(event) {
|
|
|
61033
61405
|
return this;
|
|
61034
61406
|
}
|
|
61035
61407
|
/**
|
|
61036
|
-
*
|
|
61408
|
+
* Whether any fragment has been appended. Unlike `toString().length > 0`,
|
|
61409
|
+
* this does NOT evaluate deferred fragments, so it is safe to call before
|
|
61410
|
+
* fonts are resolved (e.g. when probing for overlay content during an
|
|
61411
|
+
* editor save, prior to `writeFontResources`). A deferred text fragment
|
|
61412
|
+
* counts as content even though its bytes are not produced yet.
|
|
61413
|
+
*/
|
|
61414
|
+
hasContent() {
|
|
61415
|
+
return this.parts.length > 0;
|
|
61416
|
+
}
|
|
61417
|
+
/**
|
|
61418
|
+
* Get the content stream as a string. Deferred fragments (see `deferred`)
|
|
61419
|
+
* are evaluated here, after font resolution has completed at build time.
|
|
61037
61420
|
*/
|
|
61038
61421
|
toString() {
|
|
61039
|
-
|
|
61422
|
+
const out = [];
|
|
61423
|
+
for (const part of this.parts) out.push(typeof part === "function" ? part() : part);
|
|
61424
|
+
return out.join("\n");
|
|
61040
61425
|
}
|
|
61041
61426
|
/**
|
|
61042
61427
|
* Get the content stream as a Uint8Array (UTF-8 encoded).
|
|
@@ -87314,18 +87699,42 @@ self.onmessage = async function(event) {
|
|
|
87314
87699
|
return this.embeddedResourceName;
|
|
87315
87700
|
}
|
|
87316
87701
|
/**
|
|
87702
|
+
* Resolve the resource name a draw-time-resolved Type1 resource should
|
|
87703
|
+
* actually render (and be measured) with, given the font manager's
|
|
87704
|
+
* *current* state. If an embedded font exists (possibly auto-discovered
|
|
87705
|
+
* at build time, after the text was drawn against a Type1 resource), the
|
|
87706
|
+
* embedded resource name is returned so both measurement and encoding go
|
|
87707
|
+
* through the CIDFont. Otherwise the original Type1 resource name is kept;
|
|
87708
|
+
* `measureText` handles Type3-fallback widths internally from that name.
|
|
87709
|
+
*
|
|
87710
|
+
* Centralises the routing rule shared by the deferred text renderer and
|
|
87711
|
+
* any deferred measurement (anchor alignment, word wrapping) so the two
|
|
87712
|
+
* never disagree.
|
|
87713
|
+
*/
|
|
87714
|
+
resolveRenderResourceName(type1ResourceName) {
|
|
87715
|
+
return this.embeddedFont ? this.embeddedResourceName : type1ResourceName;
|
|
87716
|
+
}
|
|
87717
|
+
/**
|
|
87317
87718
|
* Record that a text string will be rendered, tracking its code points.
|
|
87318
87719
|
* Must be called for every text string before writing the PDF.
|
|
87720
|
+
*
|
|
87721
|
+
* Two sets are maintained because font selection may be decided *after*
|
|
87722
|
+
* drawing (e.g. `PdfDocumentBuilder.build()` auto-discovers and embeds a
|
|
87723
|
+
* system font once it sees the accumulated non-WinAnsi code points):
|
|
87724
|
+
*
|
|
87725
|
+
* - `usedCodePoints` — every code point seen, always. If an embedded
|
|
87726
|
+
* font ends up being used (whether registered up front or
|
|
87727
|
+
* auto-discovered at build time), the subset must cover all of these,
|
|
87728
|
+
* including plain ASCII, so the CIDFont can encode the full run.
|
|
87729
|
+
* - `type3CodePoints` — non-WinAnsi code points only. Drives the
|
|
87730
|
+
* build-time decision to auto-embed a system font, and the Type3
|
|
87731
|
+
* fallback when none is available.
|
|
87319
87732
|
*/
|
|
87320
87733
|
trackText(text) {
|
|
87321
|
-
|
|
87322
|
-
const cp = text.codePointAt(i);
|
|
87323
|
-
this.usedCodePoints.add(cp);
|
|
87324
|
-
if (cp > 65535) i++;
|
|
87325
|
-
}
|
|
87326
|
-
else for (let i = 0; i < text.length; i++) {
|
|
87734
|
+
for (let i = 0; i < text.length; i++) {
|
|
87327
87735
|
const cp = text.codePointAt(i);
|
|
87328
87736
|
if (cp > 65535) i++;
|
|
87737
|
+
this.usedCodePoints.add(cp);
|
|
87329
87738
|
if (!isWinAnsiCodePoint(cp)) this.type3CodePoints.add(cp);
|
|
87330
87739
|
}
|
|
87331
87740
|
}
|
|
@@ -88540,7 +88949,7 @@ self.onmessage = async function(event) {
|
|
|
88540
88949
|
emitTextWithMatrix(stream, line, cos, sin, -sin, cos, tx, ty, resourceName, fontSize, fontManager, useType3);
|
|
88541
88950
|
}
|
|
88542
88951
|
}
|
|
88543
|
-
/** Emit a text string with hex encoding if available. */
|
|
88952
|
+
/** Emit a text string with hex encoding if available, onto a sink stream. */
|
|
88544
88953
|
function emitText(stream, fontManager, text, resourceName) {
|
|
88545
88954
|
const hex = fontManager.encodeText(text, resourceName);
|
|
88546
88955
|
if (hex) stream.showTextHex(hex);
|
|
@@ -88551,37 +88960,65 @@ self.onmessage = async function(event) {
|
|
|
88551
88960
|
* when needed. For each sub-run the matrix origin is advanced along the
|
|
88552
88961
|
* text direction (cos, sin) by the rendered width.
|
|
88553
88962
|
*
|
|
88554
|
-
*
|
|
88555
|
-
*
|
|
88556
|
-
|
|
88557
|
-
|
|
88558
|
-
|
|
88559
|
-
|
|
88560
|
-
|
|
88561
|
-
|
|
88562
|
-
|
|
88563
|
-
|
|
88564
|
-
|
|
88963
|
+
* The emitted operators are written as a *deferred* fragment (see
|
|
88964
|
+
* `PdfContentStream.deferred`). The fragment is only evaluated at
|
|
88965
|
+
* serialization time, by which point `PdfDocumentBuilder.build()` has
|
|
88966
|
+
* finalised the document's fonts (auto-discovered embedded CIDFont,
|
|
88967
|
+
* Type3 fallback, or plain Type1). This is essential: at draw time the
|
|
88968
|
+
* font manager has not yet decided whether a non-WinAnsi code point (e.g.
|
|
88969
|
+
* U+2192 →) will be served by an embedded font or a Type3 glyph, so eager
|
|
88970
|
+
* encoding would irreversibly degrade those characters to spaces via the
|
|
88971
|
+
* WinAnsi fallback. Deferring the encode keeps the fragment at its exact
|
|
88972
|
+
* draw-order slot (preserving z-order) while choosing the correct bytes
|
|
88973
|
+
* once fonts are known.
|
|
88974
|
+
*
|
|
88975
|
+
* The `useType3` argument is the caller's *draw-time* guess and is ignored;
|
|
88976
|
+
* the deferred body recomputes the routing from the now-settled font
|
|
88977
|
+
* manager state.
|
|
88978
|
+
*/
|
|
88979
|
+
function emitTextWithMatrix(stream, text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager, _useType3) {
|
|
88980
|
+
stream.deferred(() => renderTextBlock(text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager));
|
|
88981
|
+
}
|
|
88982
|
+
/**
|
|
88983
|
+
* Produce the PDF operator string for a positioned text run, choosing the
|
|
88984
|
+
* encoding from the font manager's *current* (build-time) state:
|
|
88985
|
+
* - embedded font → single BT/ET with CIDFont hex encoding
|
|
88986
|
+
* - Type3 fallback → split into WinAnsi (Type1) and per-glyph Type3 runs
|
|
88987
|
+
* - neither → single BT/ET with Type1/WinAnsi encoding
|
|
88988
|
+
*
|
|
88989
|
+
* Must only be called after font resolution (i.e. from a deferred fragment).
|
|
88990
|
+
*/
|
|
88991
|
+
function renderTextBlock(text, a, b, c, d, tx, ty, type1ResourceName, fontSize, fontManager) {
|
|
88992
|
+
const sink = new PdfContentStream();
|
|
88993
|
+
if (!(fontManager.hasType3Fonts() && !fontManager.hasEmbeddedFont())) {
|
|
88994
|
+
const resourceName = fontManager.resolveRenderResourceName(type1ResourceName);
|
|
88995
|
+
sink.beginText();
|
|
88996
|
+
sink.setFont(resourceName, fontSize);
|
|
88997
|
+
sink.setTextMatrix(a, b, c, d, tx, ty);
|
|
88998
|
+
emitText(sink, fontManager, text, resourceName);
|
|
88999
|
+
sink.endText();
|
|
89000
|
+
return sink.toString();
|
|
88565
89001
|
}
|
|
88566
89002
|
const runs = splitTextRuns(text, fontManager);
|
|
88567
89003
|
let curTx = tx;
|
|
88568
89004
|
let curTy = ty;
|
|
88569
89005
|
for (const run of runs) {
|
|
88570
|
-
|
|
89006
|
+
sink.beginText();
|
|
88571
89007
|
if (run.type3) {
|
|
88572
|
-
|
|
88573
|
-
|
|
88574
|
-
|
|
89008
|
+
sink.setFont(run.type3.resourceName, fontSize);
|
|
89009
|
+
sink.setTextMatrix(a, b, c, d, curTx, curTy);
|
|
89010
|
+
sink.showTextHex(run.type3.hex);
|
|
88575
89011
|
} else {
|
|
88576
|
-
|
|
88577
|
-
|
|
88578
|
-
emitText(
|
|
89012
|
+
sink.setFont(type1ResourceName, fontSize);
|
|
89013
|
+
sink.setTextMatrix(a, b, c, d, curTx, curTy);
|
|
89014
|
+
emitText(sink, fontManager, run.text, type1ResourceName);
|
|
88579
89015
|
}
|
|
88580
|
-
|
|
89016
|
+
sink.endText();
|
|
88581
89017
|
const w = fontManager.measureText(run.text, run.type3?.resourceName ?? type1ResourceName, fontSize);
|
|
88582
89018
|
curTx += a * w;
|
|
88583
89019
|
curTy += b * w;
|
|
88584
89020
|
}
|
|
89021
|
+
return sink.toString();
|
|
88585
89022
|
}
|
|
88586
89023
|
/**
|
|
88587
89024
|
* Split a line of text into runs of consecutive WinAnsi and non-WinAnsi
|