@rowsncolumns/toolkit 24.4.1
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/LICENSE.md +100 -0
- package/Readme.md +27 -0
- package/dist/cjs/autofilter-condition.d.ts +43 -0
- package/dist/cjs/autofilter-condition.d.ts.map +1 -0
- package/dist/cjs/autofilter-condition.js +155 -0
- package/dist/cjs/csv-export.d.ts +49 -0
- package/dist/cjs/csv-export.d.ts.map +1 -0
- package/dist/cjs/csv-export.js +142 -0
- package/dist/cjs/csv-import-worker.d.ts +16 -0
- package/dist/cjs/csv-import-worker.d.ts.map +1 -0
- package/dist/cjs/csv-import-worker.js +60 -0
- package/dist/cjs/csv-import.d.ts +38 -0
- package/dist/cjs/csv-import.d.ts.map +1 -0
- package/dist/cjs/csv-import.js +166 -0
- package/dist/cjs/csv-parser/helpers.d.ts +14 -0
- package/dist/cjs/csv-parser/helpers.d.ts.map +1 -0
- package/dist/cjs/csv-parser/helpers.js +145 -0
- package/dist/cjs/csv-parser/types.d.ts +66 -0
- package/dist/cjs/csv-parser/types.d.ts.map +1 -0
- package/dist/cjs/csv-parser/types.js +14 -0
- package/dist/cjs/csv-parser/worker.d.ts +2 -0
- package/dist/cjs/csv-parser/worker.d.ts.map +1 -0
- package/dist/cjs/csv-parser/worker.js +200 -0
- package/dist/cjs/excel-export.d.ts +11 -0
- package/dist/cjs/excel-export.d.ts.map +1 -0
- package/dist/cjs/excel-export.js +22 -0
- package/dist/cjs/excel-import-session.d.ts +51 -0
- package/dist/cjs/excel-import-session.d.ts.map +1 -0
- package/dist/cjs/excel-import-session.js +307 -0
- package/dist/cjs/excel-import-worker.d.ts +7 -0
- package/dist/cjs/excel-import-worker.d.ts.map +1 -0
- package/dist/cjs/excel-import-worker.js +119 -0
- package/dist/cjs/excel-parser/builtin-numfmts.d.ts +24 -0
- package/dist/cjs/excel-parser/builtin-numfmts.d.ts.map +1 -0
- package/dist/cjs/excel-parser/builtin-numfmts.js +63 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts +53 -0
- package/dist/cjs/excel-parser/cfb-decryptor.d.ts.map +1 -0
- package/dist/cjs/excel-parser/cfb-decryptor.js +553 -0
- package/dist/cjs/excel-parser/cfb-encryptor.d.ts +23 -0
- package/dist/cjs/excel-parser/cfb-encryptor.d.ts.map +1 -0
- package/dist/cjs/excel-parser/cfb-encryptor.js +200 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.d.ts +29 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.d.ts.map +1 -0
- package/dist/cjs/excel-parser/dv-cell-stamp.js +239 -0
- package/dist/cjs/excel-parser/helpers.d.ts +28 -0
- package/dist/cjs/excel-parser/helpers.d.ts.map +1 -0
- package/dist/cjs/excel-parser/helpers.js +188 -0
- package/dist/cjs/excel-parser/interface.d.ts +179 -0
- package/dist/cjs/excel-parser/interface.d.ts.map +1 -0
- package/dist/cjs/excel-parser/interface.js +1 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts +31 -0
- package/dist/cjs/excel-parser/plugins/base/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/base/index.js +101 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/conditional-formatting.js +488 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts +15 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/data-validations.js +353 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.d.ts +8 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/formula.js +82 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts +122 -0
- package/dist/cjs/excel-parser/plugins/ods/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/index.js +3642 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts +25 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/sparklines.js +221 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts +60 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/styles.js +808 -0
- package/dist/cjs/excel-parser/plugins/ods/types.d.ts +7 -0
- package/dist/cjs/excel-parser/plugins/ods/types.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/ods/types.js +1 -0
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts +5 -0
- package/dist/cjs/excel-parser/plugins/xls/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xls/index.js +19 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/biff-record-reader.js +49 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts +117 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/index.js +2972 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsb/rgce-parser.js +527 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts +5 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsm/index.js +10 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts +60 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/charts.js +2178 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/conditional-formatting.js +620 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/data-validations.js +515 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/drawing.js +941 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts +320 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/index.js +6056 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/numfmt.js +3 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/pivots.js +342 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/relationships.js +26 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/sheet-views.js +59 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts +44 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/styles.js +1377 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts +50 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/theme.js +150 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/threaded-comments.js +141 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
- package/dist/cjs/excel-parser/plugins/xlsx/value-type-detection.js +407 -0
- package/dist/cjs/excel-parser/registry.d.ts +5 -0
- package/dist/cjs/excel-parser/registry.d.ts.map +1 -0
- package/dist/cjs/excel-parser/registry.js +21 -0
- package/dist/cjs/excel-parser/style-registry.d.ts +51 -0
- package/dist/cjs/excel-parser/style-registry.d.ts.map +1 -0
- package/dist/cjs/excel-parser/style-registry.js +175 -0
- package/dist/cjs/excel-parser/theme-default.d.ts +3 -0
- package/dist/cjs/excel-parser/theme-default.d.ts.map +1 -0
- package/dist/cjs/excel-parser/theme-default.js +19 -0
- package/dist/cjs/excel-parser/types.d.ts +365 -0
- package/dist/cjs/excel-parser/types.d.ts.map +1 -0
- package/dist/cjs/excel-parser/types.js +59 -0
- package/dist/cjs/excel-parser/utils.d.ts +6 -0
- package/dist/cjs/excel-parser/utils.d.ts.map +1 -0
- package/dist/cjs/excel-parser/utils.js +30 -0
- package/dist/cjs/excel-parser/workbook.d.ts +51 -0
- package/dist/cjs/excel-parser/workbook.d.ts.map +1 -0
- package/dist/cjs/excel-parser/workbook.js +317 -0
- package/dist/cjs/excel-parser/worker.d.ts +2 -0
- package/dist/cjs/excel-parser/worker.d.ts.map +1 -0
- package/dist/cjs/excel-parser/worker.js +1149 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.d.ts +13 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.d.ts.map +1 -0
- package/dist/cjs/excel-parser/zip-parser-streaming.js +200 -0
- package/dist/cjs/excel-parser/zip-parser.d.ts +11 -0
- package/dist/cjs/excel-parser/zip-parser.d.ts.map +1 -0
- package/dist/cjs/excel-parser/zip-parser.js +49 -0
- package/dist/cjs/exporter/invalid-data-validation.d.ts +19 -0
- package/dist/cjs/exporter/invalid-data-validation.d.ts.map +1 -0
- package/dist/cjs/exporter/invalid-data-validation.js +39 -0
- package/dist/cjs/exporter/ods/ods-export.d.ts +26 -0
- package/dist/cjs/exporter/ods/ods-export.d.ts.map +1 -0
- package/dist/cjs/exporter/ods/ods-export.js +3714 -0
- package/dist/cjs/exporter/ods/sparkline-builder.d.ts +33 -0
- package/dist/cjs/exporter/ods/sparkline-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/ods/sparkline-builder.js +221 -0
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts +3 -0
- package/dist/cjs/exporter/xlsx/chart-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chart-builder.js +1901 -0
- package/dist/cjs/exporter/xlsx/chart-templates.d.ts +1781 -0
- package/dist/cjs/exporter/xlsx/chart-templates.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/chart-templates.js +1798 -0
- package/dist/cjs/exporter/xlsx/future-functions.d.ts +10 -0
- package/dist/cjs/exporter/xlsx/future-functions.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/future-functions.js +264 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts +58 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/pivot-builder.js +277 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.d.ts +26 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/power-query-builder.js +306 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.d.ts +11 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/slicer-builder.js +87 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts +61 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/sparkline-builder.js +489 -0
- package/dist/cjs/exporter/xlsx/style-builder.d.ts +93 -0
- package/dist/cjs/exporter/xlsx/style-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/style-builder.js +813 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/threaded-comments-builder.js +189 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts +121 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.d.ts.map +1 -0
- package/dist/cjs/exporter/xlsx/xlsx-export.js +4596 -0
- package/dist/cjs/helpers/theme-xml-generator.d.ts +8 -0
- package/dist/cjs/helpers/theme-xml-generator.d.ts.map +1 -0
- package/dist/cjs/helpers/theme-xml-generator.js +33 -0
- package/dist/cjs/helpers.d.ts +34 -0
- package/dist/cjs/helpers.d.ts.map +1 -0
- package/dist/cjs/helpers.js +189 -0
- package/dist/cjs/index.d.ts +16 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +15 -0
- package/dist/cjs/indexed-colors.d.ts +2 -0
- package/dist/cjs/indexed-colors.d.ts.map +1 -0
- package/dist/cjs/indexed-colors.js +75 -0
- package/dist/cjs/ods-export.d.ts +24 -0
- package/dist/cjs/ods-export.d.ts.map +1 -0
- package/dist/cjs/ods-export.js +23 -0
- package/dist/cjs/parse.d.ts +24 -0
- package/dist/cjs/parse.d.ts.map +1 -0
- package/dist/cjs/parse.js +68 -0
- package/dist/cjs/power-query.d.ts +41 -0
- package/dist/cjs/power-query.d.ts.map +1 -0
- package/dist/cjs/power-query.js +22 -0
- package/dist/cjs/server.d.ts +9 -0
- package/dist/cjs/server.d.ts.map +1 -0
- package/dist/cjs/server.js +8 -0
- package/dist/cjs/theme1.d.ts +3 -0
- package/dist/cjs/theme1.d.ts.map +1 -0
- package/dist/cjs/theme1.js +2 -0
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -0
- package/dist/cjs/types.d.ts +14 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +14 -0
- package/dist/cjs/vitest.config.d.ts +3 -0
- package/dist/cjs/vitest.config.d.ts.map +1 -0
- package/dist/cjs/vitest.config.js +16 -0
- package/dist/esm/autofilter-condition.d.ts +43 -0
- package/dist/esm/autofilter-condition.d.ts.map +1 -0
- package/dist/esm/autofilter-condition.js +145 -0
- package/dist/esm/csv-export.d.ts +49 -0
- package/dist/esm/csv-export.d.ts.map +1 -0
- package/dist/esm/csv-export.js +126 -0
- package/dist/esm/csv-import-worker.d.ts +16 -0
- package/dist/esm/csv-import-worker.d.ts.map +1 -0
- package/dist/esm/csv-import-worker.js +60 -0
- package/dist/esm/csv-import.d.ts +38 -0
- package/dist/esm/csv-import.d.ts.map +1 -0
- package/dist/esm/csv-import.js +132 -0
- package/dist/esm/csv-parser/helpers.d.ts +14 -0
- package/dist/esm/csv-parser/helpers.d.ts.map +1 -0
- package/dist/esm/csv-parser/helpers.js +0 -0
- package/dist/esm/csv-parser/types.d.ts +66 -0
- package/dist/esm/csv-parser/types.d.ts.map +1 -0
- package/dist/esm/csv-parser/types.js +14 -0
- package/dist/esm/csv-parser/worker.d.ts +2 -0
- package/dist/esm/csv-parser/worker.d.ts.map +1 -0
- package/dist/esm/csv-parser/worker.js +154 -0
- package/dist/esm/excel-export.d.ts +11 -0
- package/dist/esm/excel-export.d.ts.map +1 -0
- package/dist/esm/excel-export.js +13 -0
- package/dist/esm/excel-import-session.d.ts +51 -0
- package/dist/esm/excel-import-session.d.ts.map +1 -0
- package/dist/esm/excel-import-session.js +255 -0
- package/dist/esm/excel-import-worker.d.ts +7 -0
- package/dist/esm/excel-import-worker.d.ts.map +1 -0
- package/dist/esm/excel-import-worker.js +116 -0
- package/dist/esm/excel-parser/builtin-numfmts.d.ts +24 -0
- package/dist/esm/excel-parser/builtin-numfmts.d.ts.map +1 -0
- package/dist/esm/excel-parser/builtin-numfmts.js +59 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts +53 -0
- package/dist/esm/excel-parser/cfb-decryptor.d.ts.map +1 -0
- package/dist/esm/excel-parser/cfb-decryptor.js +493 -0
- package/dist/esm/excel-parser/cfb-encryptor.d.ts +23 -0
- package/dist/esm/excel-parser/cfb-encryptor.d.ts.map +1 -0
- package/dist/esm/excel-parser/cfb-encryptor.js +181 -0
- package/dist/esm/excel-parser/dv-cell-stamp.d.ts +29 -0
- package/dist/esm/excel-parser/dv-cell-stamp.d.ts.map +1 -0
- package/dist/esm/excel-parser/dv-cell-stamp.js +155 -0
- package/dist/esm/excel-parser/helpers.d.ts +28 -0
- package/dist/esm/excel-parser/helpers.d.ts.map +1 -0
- package/dist/esm/excel-parser/helpers.js +160 -0
- package/dist/esm/excel-parser/interface.d.ts +179 -0
- package/dist/esm/excel-parser/interface.d.ts.map +1 -0
- package/dist/esm/excel-parser/interface.js +1 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts +31 -0
- package/dist/esm/excel-parser/plugins/base/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/base/index.js +64 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts +16 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/conditional-formatting.js +405 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts +15 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/data-validations.js +331 -0
- package/dist/esm/excel-parser/plugins/ods/formula.d.ts +8 -0
- package/dist/esm/excel-parser/plugins/ods/formula.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/formula.js +82 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts +122 -0
- package/dist/esm/excel-parser/plugins/ods/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/index.js +2896 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts +25 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/sparklines.js +188 -0
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts +60 -0
- package/dist/esm/excel-parser/plugins/ods/styles.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/styles.js +732 -0
- package/dist/esm/excel-parser/plugins/ods/types.d.ts +7 -0
- package/dist/esm/excel-parser/plugins/ods/types.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/ods/types.js +1 -0
- package/dist/esm/excel-parser/plugins/xls/index.d.ts +5 -0
- package/dist/esm/excel-parser/plugins/xls/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xls/index.js +7 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts +13 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/biff-record-reader.js +48 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts +117 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/index.js +2339 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts +18 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsb/rgce-parser.js +522 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.d.ts +5 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsm/index.js +6 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts +60 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/charts.js +2036 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts +18 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/conditional-formatting.js +621 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts +4 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/data-validations.js +493 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts +39 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/drawing.js +905 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts +320 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/index.js +4654 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts +2 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/numfmt.js +3 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts +40 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/pivots.js +254 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts +8 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/relationships.js +13 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts +26 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/sheet-views.js +64 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts +44 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/styles.js +1365 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts +50 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/theme.js +127 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts +47 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/threaded-comments.js +103 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts +44 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.d.ts.map +1 -0
- package/dist/esm/excel-parser/plugins/xlsx/value-type-detection.js +399 -0
- package/dist/esm/excel-parser/registry.d.ts +5 -0
- package/dist/esm/excel-parser/registry.d.ts.map +1 -0
- package/dist/esm/excel-parser/registry.js +20 -0
- package/dist/esm/excel-parser/style-registry.d.ts +51 -0
- package/dist/esm/excel-parser/style-registry.d.ts.map +1 -0
- package/dist/esm/excel-parser/style-registry.js +163 -0
- package/dist/esm/excel-parser/theme-default.d.ts +3 -0
- package/dist/esm/excel-parser/theme-default.d.ts.map +1 -0
- package/dist/esm/excel-parser/theme-default.js +19 -0
- package/dist/esm/excel-parser/types.d.ts +365 -0
- package/dist/esm/excel-parser/types.d.ts.map +1 -0
- package/dist/esm/excel-parser/types.js +59 -0
- package/dist/esm/excel-parser/utils.d.ts +6 -0
- package/dist/esm/excel-parser/utils.d.ts.map +1 -0
- package/dist/esm/excel-parser/utils.js +25 -0
- package/dist/esm/excel-parser/workbook.d.ts +51 -0
- package/dist/esm/excel-parser/workbook.d.ts.map +1 -0
- package/dist/esm/excel-parser/workbook.js +192 -0
- package/dist/esm/excel-parser/worker.d.ts +2 -0
- package/dist/esm/excel-parser/worker.d.ts.map +1 -0
- package/dist/esm/excel-parser/worker.js +862 -0
- package/dist/esm/excel-parser/zip-parser-streaming.d.ts +13 -0
- package/dist/esm/excel-parser/zip-parser-streaming.d.ts.map +1 -0
- package/dist/esm/excel-parser/zip-parser-streaming.js +119 -0
- package/dist/esm/excel-parser/zip-parser.d.ts +11 -0
- package/dist/esm/excel-parser/zip-parser.d.ts.map +1 -0
- package/dist/esm/excel-parser/zip-parser.js +43 -0
- package/dist/esm/exporter/invalid-data-validation.d.ts +19 -0
- package/dist/esm/exporter/invalid-data-validation.d.ts.map +1 -0
- package/dist/esm/exporter/invalid-data-validation.js +37 -0
- package/dist/esm/exporter/ods/ods-export.d.ts +26 -0
- package/dist/esm/exporter/ods/ods-export.d.ts.map +1 -0
- package/dist/esm/exporter/ods/ods-export.js +3238 -0
- package/dist/esm/exporter/ods/sparkline-builder.d.ts +33 -0
- package/dist/esm/exporter/ods/sparkline-builder.d.ts.map +1 -0
- package/dist/esm/exporter/ods/sparkline-builder.js +165 -0
- package/dist/esm/exporter/xlsx/chart-builder.d.ts +3 -0
- package/dist/esm/exporter/xlsx/chart-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chart-builder.js +1805 -0
- package/dist/esm/exporter/xlsx/chart-templates.d.ts +1781 -0
- package/dist/esm/exporter/xlsx/chart-templates.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/chart-templates.js +1798 -0
- package/dist/esm/exporter/xlsx/future-functions.d.ts +10 -0
- package/dist/esm/exporter/xlsx/future-functions.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/future-functions.js +264 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts +58 -0
- package/dist/esm/exporter/xlsx/pivot-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/pivot-builder.js +230 -0
- package/dist/esm/exporter/xlsx/power-query-builder.d.ts +26 -0
- package/dist/esm/exporter/xlsx/power-query-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/power-query-builder.js +257 -0
- package/dist/esm/exporter/xlsx/slicer-builder.d.ts +11 -0
- package/dist/esm/exporter/xlsx/slicer-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/slicer-builder.js +84 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.d.ts +61 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/sparkline-builder.js +437 -0
- package/dist/esm/exporter/xlsx/style-builder.d.ts +93 -0
- package/dist/esm/exporter/xlsx/style-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/style-builder.js +795 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts +58 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/threaded-comments-builder.js +175 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts +121 -0
- package/dist/esm/exporter/xlsx/xlsx-export.d.ts.map +1 -0
- package/dist/esm/exporter/xlsx/xlsx-export.js +4062 -0
- package/dist/esm/helpers/theme-xml-generator.d.ts +8 -0
- package/dist/esm/helpers/theme-xml-generator.d.ts.map +1 -0
- package/dist/esm/helpers/theme-xml-generator.js +33 -0
- package/dist/esm/helpers.d.ts +34 -0
- package/dist/esm/helpers.d.ts.map +1 -0
- package/dist/esm/helpers.js +182 -0
- package/dist/esm/index.d.ts +16 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/indexed-colors.d.ts +2 -0
- package/dist/esm/indexed-colors.d.ts.map +1 -0
- package/dist/esm/indexed-colors.js +75 -0
- package/dist/esm/ods-export.d.ts +24 -0
- package/dist/esm/ods-export.d.ts.map +1 -0
- package/dist/esm/ods-export.js +12 -0
- package/dist/esm/parse.d.ts +24 -0
- package/dist/esm/parse.d.ts.map +1 -0
- package/dist/esm/parse.js +55 -0
- package/dist/esm/power-query.d.ts +41 -0
- package/dist/esm/power-query.d.ts.map +1 -0
- package/dist/esm/power-query.js +19 -0
- package/dist/esm/server.d.ts +9 -0
- package/dist/esm/server.d.ts.map +1 -0
- package/dist/esm/server.js +8 -0
- package/dist/esm/theme1.d.ts +3 -0
- package/dist/esm/theme1.d.ts.map +1 -0
- package/dist/esm/theme1.js +2 -0
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -0
- package/dist/esm/types.d.ts +14 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +14 -0
- package/dist/esm/vitest.config.d.ts +3 -0
- package/dist/esm/vitest.config.d.ts.map +1 -0
- package/dist/esm/vitest.config.js +16 -0
- package/package.json +62 -0
- package/xlsx.d.ts +52 -0
|
@@ -0,0 +1,905 @@
|
|
|
1
|
+
import { uuid } from "@rowsncolumns/utils";
|
|
2
|
+
import { get } from "lodash-es";
|
|
3
|
+
/**
|
|
4
|
+
* Create a data URL from binary data and MIME type
|
|
5
|
+
* @param data Binary data of the image
|
|
6
|
+
* @param mimeType MIME type of the image
|
|
7
|
+
* @returns Data URL string
|
|
8
|
+
*/
|
|
9
|
+
function createDataUrl(data, mimeType) {
|
|
10
|
+
// Convert ArrayBuffer to Base64 string
|
|
11
|
+
const base64 = arrayBufferToBase64(data);
|
|
12
|
+
return `data:${mimeType};base64,${base64}`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Convert an ArrayBuffer to a Base64 string
|
|
16
|
+
* @param buffer ArrayBuffer to convert
|
|
17
|
+
* @returns Base64 string
|
|
18
|
+
*/
|
|
19
|
+
function arrayBufferToBase64(buffer) {
|
|
20
|
+
const bytes = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
|
|
21
|
+
// Use Buffer in Node.js, btoa in browser
|
|
22
|
+
if (typeof Buffer !== "undefined") {
|
|
23
|
+
return Buffer.from(bytes).toString("base64");
|
|
24
|
+
}
|
|
25
|
+
let binary = "";
|
|
26
|
+
const len = bytes.byteLength;
|
|
27
|
+
for (let i = 0; i < len; i++) {
|
|
28
|
+
binary += String.fromCharCode(bytes[i]);
|
|
29
|
+
}
|
|
30
|
+
return btoa(binary);
|
|
31
|
+
}
|
|
32
|
+
// Conversion constant: 1 pixel is approximately 9525 EMUs (at 96 DPI)
|
|
33
|
+
const EMU_PER_PIXEL = 9525;
|
|
34
|
+
const DEFAULT_CELL_IMAGE_MAX_SIZE_PX = 60;
|
|
35
|
+
const CELL_IMAGE_OFFSET_THRESHOLD_PX = 1;
|
|
36
|
+
/**
|
|
37
|
+
* Convert EMUs to pixels
|
|
38
|
+
* @param emuValue Value in English Metric Units
|
|
39
|
+
* @returns Value in pixels (at 96 DPI)
|
|
40
|
+
*/
|
|
41
|
+
function emuToPixels(emuValue) {
|
|
42
|
+
return Math.round(emuValue / EMU_PER_PIXEL);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Process different types of image anchors
|
|
46
|
+
* @param anchors The anchor elements from the drawing
|
|
47
|
+
* @param anchorType The type of anchor
|
|
48
|
+
* @param drawingPath The path to the drawing file
|
|
49
|
+
* @param sheetName The name of the worksheet
|
|
50
|
+
* @param zipParser The zip parser instance
|
|
51
|
+
* @param xmlParser The XML parser instance
|
|
52
|
+
* @returns An array of image objects with their properties and binary data
|
|
53
|
+
*/
|
|
54
|
+
export async function processAnchors(anchors, anchorType, drawingPath, sheetId, zipParser, xmlParser) {
|
|
55
|
+
const images = [];
|
|
56
|
+
if (!anchors)
|
|
57
|
+
return images;
|
|
58
|
+
// Normalize to array
|
|
59
|
+
const anchorArray = Array.isArray(anchors) ? anchors : [anchors];
|
|
60
|
+
for (const anchor of anchorArray) {
|
|
61
|
+
let isInsideCell = false;
|
|
62
|
+
// Get position information based on anchor type
|
|
63
|
+
let position = {
|
|
64
|
+
sheetId,
|
|
65
|
+
// sheet: sheetName,
|
|
66
|
+
// anchorType: anchorType, // Store the anchor type to differentiate positioning
|
|
67
|
+
};
|
|
68
|
+
if (anchorType === "twoCellAnchors") {
|
|
69
|
+
// Two cell anchor defines a rectangle with from and to cells
|
|
70
|
+
// Handle different namespace patterns
|
|
71
|
+
// Adjust row and column indices to start from 1 (Excel-like) instead of 0 (zero-based)
|
|
72
|
+
// Store both the original (0-based) and adjusted (1-based) indices
|
|
73
|
+
const fromColBase0 = parseInt(get(anchor, "xdr:from.xdr:col.t$") ||
|
|
74
|
+
get(anchor, "from.col.t$") ||
|
|
75
|
+
get(anchor, "xdr:from.xdr:col") ||
|
|
76
|
+
get(anchor, "from.col") ||
|
|
77
|
+
"0");
|
|
78
|
+
const fromRowBase0 = parseInt(get(anchor, "xdr:from.xdr:row.t$") ||
|
|
79
|
+
get(anchor, "from.row.t$") ||
|
|
80
|
+
get(anchor, "xdr:from.xdr:row") ||
|
|
81
|
+
get(anchor, "from.row") ||
|
|
82
|
+
"0");
|
|
83
|
+
const toColBase0 = parseInt(get(anchor, "xdr:to.xdr:col.t$") ||
|
|
84
|
+
get(anchor, "to.col.t$") ||
|
|
85
|
+
get(anchor, "xdr:to.xdr:col") ||
|
|
86
|
+
get(anchor, "to.col") ||
|
|
87
|
+
"0");
|
|
88
|
+
const toRowBase0 = parseInt(get(anchor, "xdr:to.xdr:row.t$") ||
|
|
89
|
+
get(anchor, "to.row.t$") ||
|
|
90
|
+
get(anchor, "xdr:to.xdr:row") ||
|
|
91
|
+
get(anchor, "to.row") ||
|
|
92
|
+
"0");
|
|
93
|
+
// Convert to 1-based indices (Excel-like)
|
|
94
|
+
const fromCol = fromColBase0 + 1;
|
|
95
|
+
const fromRow = fromRowBase0 + 1;
|
|
96
|
+
const toCol = toColBase0 + 1;
|
|
97
|
+
const toRow = toRowBase0 + 1;
|
|
98
|
+
// Get offset information if available (convert to pixels)
|
|
99
|
+
const fromColOffEmu = parseInt(get(anchor, "xdr:from.xdr:colOff.t$") ||
|
|
100
|
+
get(anchor, "from.colOff.t$") ||
|
|
101
|
+
get(anchor, "xdr:from.xdr:colOff") ||
|
|
102
|
+
get(anchor, "from.colOff") ||
|
|
103
|
+
"0");
|
|
104
|
+
const fromRowOffEmu = parseInt(get(anchor, "xdr:from.xdr:rowOff.t$") ||
|
|
105
|
+
get(anchor, "from.rowOff.t$") ||
|
|
106
|
+
get(anchor, "xdr:from.xdr:rowOff") ||
|
|
107
|
+
get(anchor, "from.rowOff") ||
|
|
108
|
+
"0");
|
|
109
|
+
const toColOffEmu = parseInt(get(anchor, "xdr:to.xdr:colOff.t$") ||
|
|
110
|
+
get(anchor, "to.colOff.t$") ||
|
|
111
|
+
get(anchor, "xdr:to.xdr:colOff") ||
|
|
112
|
+
get(anchor, "to.colOff") ||
|
|
113
|
+
"0");
|
|
114
|
+
const toRowOffEmu = parseInt(get(anchor, "xdr:to.xdr:rowOff.t$") ||
|
|
115
|
+
get(anchor, "to.rowOff.t$") ||
|
|
116
|
+
get(anchor, "xdr:to.xdr:rowOff") ||
|
|
117
|
+
get(anchor, "to.rowOff") ||
|
|
118
|
+
"0");
|
|
119
|
+
// Convert EMUs to pixels
|
|
120
|
+
const fromColOff = emuToPixels(fromColOffEmu);
|
|
121
|
+
const fromRowOff = emuToPixels(fromRowOffEmu);
|
|
122
|
+
const toColOff = emuToPixels(toColOffEmu);
|
|
123
|
+
const toRowOff = emuToPixels(toRowOffEmu);
|
|
124
|
+
// Get extent (size) information (in EMUs) from the correct path
|
|
125
|
+
const cxEmu = parseInt(get(anchor, "xdr:pic.xdr:spPr.a:xfrm.a:ext.a$.cx") ||
|
|
126
|
+
get(anchor, "pic.spPr.xfrm.ext.a$.cx") ||
|
|
127
|
+
"0");
|
|
128
|
+
const cyEmu = parseInt(get(anchor, "xdr:pic.xdr:spPr.a:xfrm.a:ext.a$.cy") ||
|
|
129
|
+
get(anchor, "pic.spPr.xfrm.ext.a$.cy") ||
|
|
130
|
+
"0");
|
|
131
|
+
// Convert EMUs to pixels
|
|
132
|
+
const width = emuToPixels(cxEmu);
|
|
133
|
+
const height = emuToPixels(cyEmu);
|
|
134
|
+
// Check for editAs attribute which indicates if image is locked to cells
|
|
135
|
+
const editAs = get(anchor, "a$.editAs") || "";
|
|
136
|
+
isInsideCell = determineIfTwoCellInsideCell(editAs, fromColBase0, fromRowBase0, toColBase0, toRowBase0);
|
|
137
|
+
position = {
|
|
138
|
+
...position,
|
|
139
|
+
overlayPosition: {
|
|
140
|
+
anchorCell: {
|
|
141
|
+
rowIndex: fromRow,
|
|
142
|
+
columnIndex: fromCol,
|
|
143
|
+
},
|
|
144
|
+
heightPixels: height,
|
|
145
|
+
widthPixels: width,
|
|
146
|
+
offsetXPixels: fromColOff,
|
|
147
|
+
offsetYPixels: fromRowOff,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
else if (anchorType === "oneCellAnchor") {
|
|
152
|
+
// One cell anchor defines a point with just from cell and extents
|
|
153
|
+
// Handle different namespace patterns
|
|
154
|
+
// Adjust row and column indices to start from 1 (Excel-like) instead of 0 (zero-based)
|
|
155
|
+
const fromColBase0 = parseInt(get(anchor, "xdr:from.xdr:col.t$") ||
|
|
156
|
+
get(anchor, "from.col.t$") ||
|
|
157
|
+
get(anchor, "xdr:from.xdr:col") ||
|
|
158
|
+
get(anchor, "from.col") ||
|
|
159
|
+
"0");
|
|
160
|
+
const fromRowBase0 = parseInt(get(anchor, "xdr:from.xdr:row.t$") ||
|
|
161
|
+
get(anchor, "from.row.t$") ||
|
|
162
|
+
get(anchor, "xdr:from.xdr:row") ||
|
|
163
|
+
get(anchor, "from.row") ||
|
|
164
|
+
"0");
|
|
165
|
+
// Convert to 1-based indices (Excel-like)
|
|
166
|
+
const fromCol = fromColBase0 + 1;
|
|
167
|
+
const fromRow = fromRowBase0 + 1;
|
|
168
|
+
// Get offset information (in EMUs)
|
|
169
|
+
const fromColOffEmu = parseInt(get(anchor, "xdr:from.xdr:colOff.t$") ||
|
|
170
|
+
get(anchor, "from.colOff.t$") ||
|
|
171
|
+
get(anchor, "xdr:from.xdr:colOff") ||
|
|
172
|
+
get(anchor, "from.colOff") ||
|
|
173
|
+
"0");
|
|
174
|
+
const fromRowOffEmu = parseInt(get(anchor, "xdr:from.xdr:rowOff.t$") ||
|
|
175
|
+
get(anchor, "from.rowOff.t$") ||
|
|
176
|
+
get(anchor, "xdr:from.xdr:rowOff") ||
|
|
177
|
+
get(anchor, "from.rowOff") ||
|
|
178
|
+
"0");
|
|
179
|
+
// Convert EMUs to pixels
|
|
180
|
+
const fromColOff = emuToPixels(fromColOffEmu);
|
|
181
|
+
const fromRowOff = emuToPixels(fromRowOffEmu);
|
|
182
|
+
// Get extent (size) information (in EMUs)
|
|
183
|
+
const cxEmu = parseInt(get(anchor, "xdr:ext.a$.cx") || get(anchor, "ext.a$.cx") || "0");
|
|
184
|
+
const cyEmu = parseInt(get(anchor, "xdr:ext.a$.cy") || get(anchor, "ext.a$.cy") || "0");
|
|
185
|
+
// Convert EMUs to pixels
|
|
186
|
+
const width = emuToPixels(cxEmu);
|
|
187
|
+
const height = emuToPixels(cyEmu);
|
|
188
|
+
// Add info about locking with sheet which helps determine positioning
|
|
189
|
+
const fLocksWithSheet = get(anchor, "xdr:clientData.a$.fLocksWithSheet") ||
|
|
190
|
+
get(anchor, "clientData.a$.fLocksWithSheet") ||
|
|
191
|
+
"0";
|
|
192
|
+
isInsideCell = determineIfOneCellInsideCell(fromColOffEmu, fromRowOffEmu, fLocksWithSheet, cxEmu, cyEmu);
|
|
193
|
+
position = {
|
|
194
|
+
...position,
|
|
195
|
+
overlayPosition: {
|
|
196
|
+
anchorCell: {
|
|
197
|
+
rowIndex: fromRow,
|
|
198
|
+
columnIndex: fromCol,
|
|
199
|
+
},
|
|
200
|
+
heightPixels: height,
|
|
201
|
+
widthPixels: width,
|
|
202
|
+
offsetXPixels: fromColOff,
|
|
203
|
+
offsetYPixels: fromRowOff,
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
// position = {
|
|
207
|
+
// ...position,
|
|
208
|
+
// fromCol,
|
|
209
|
+
// fromRow,
|
|
210
|
+
// fromColOff,
|
|
211
|
+
// fromRowOff,
|
|
212
|
+
// width,
|
|
213
|
+
// height,
|
|
214
|
+
// // Store original indices in case they're needed
|
|
215
|
+
// _fromColBase0: fromColBase0,
|
|
216
|
+
// _fromRowBase0: fromRowBase0,
|
|
217
|
+
// // Store original EMU values for reference if needed
|
|
218
|
+
// _fromColOffEmu: fromColOffEmu,
|
|
219
|
+
// _fromRowOffEmu: fromRowOffEmu,
|
|
220
|
+
// _widthEmu: cxEmu,
|
|
221
|
+
// _heightEmu: cyEmu,
|
|
222
|
+
// fLocksWithSheet: fLocksWithSheet === "1",
|
|
223
|
+
// // For oneCellAnchor, determine based on offsets and locking
|
|
224
|
+
// isInsideCell: determineIfOneCellInsideCell(
|
|
225
|
+
// fromColOffEmu,
|
|
226
|
+
// fromRowOffEmu,
|
|
227
|
+
// fLocksWithSheet,
|
|
228
|
+
// cxEmu,
|
|
229
|
+
// cyEmu
|
|
230
|
+
// ),
|
|
231
|
+
// };
|
|
232
|
+
}
|
|
233
|
+
else if (anchorType === "absoluteAnchors") {
|
|
234
|
+
// Absolute anchor doesn't have cell reference, only absolute position (in EMUs)
|
|
235
|
+
const posXEmu = parseInt(get(anchor, "xdr:pos.a$.x") || get(anchor, "pos.a$.x") || "0") || 0;
|
|
236
|
+
const posYEmu = parseInt(get(anchor, "xdr:pos.a$.y") || get(anchor, "pos.a$.y") || "0") || 0;
|
|
237
|
+
// Convert EMUs to pixels
|
|
238
|
+
const posX = emuToPixels(posXEmu);
|
|
239
|
+
const posY = emuToPixels(posYEmu);
|
|
240
|
+
// Get extent (size) information (in EMUs)
|
|
241
|
+
const cxEmu = parseInt(get(anchor, "xdr:ext.a$.cx") || get(anchor, "ext.a$.cx") || "0") || 0;
|
|
242
|
+
const cyEmu = parseInt(get(anchor, "xdr:ext.a$.cy") || get(anchor, "ext.a$.cy") || "0") || 0;
|
|
243
|
+
// Convert EMUs to pixels
|
|
244
|
+
const width = emuToPixels(cxEmu);
|
|
245
|
+
const height = emuToPixels(cyEmu);
|
|
246
|
+
position = {
|
|
247
|
+
...position,
|
|
248
|
+
overlayPosition: {
|
|
249
|
+
anchorCell: {
|
|
250
|
+
rowIndex: 1,
|
|
251
|
+
columnIndex: 1,
|
|
252
|
+
},
|
|
253
|
+
heightPixels: height,
|
|
254
|
+
widthPixels: width,
|
|
255
|
+
offsetXPixels: posX,
|
|
256
|
+
offsetYPixels: posY,
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
// Find the picture element with different possible namespaces
|
|
261
|
+
const picture = get(anchor, "xdr:pic") || get(anchor, "pic");
|
|
262
|
+
// Find shape (textbox or drawing shape) element
|
|
263
|
+
const shape = get(anchor, "xdr:sp") || get(anchor, "sp");
|
|
264
|
+
// Drawing shape (Insert → Shapes): parsed into an `EmbedShapeSpec` so the
|
|
265
|
+
// geometry/fill/outline render. A shape is only routed here when it is
|
|
266
|
+
// visibly a *shape* — a non-rect preset geometry, an explicit fill, or an
|
|
267
|
+
// `<xdr:style>` theme-style block. Plain text boxes (`txBox="1"`, or a bare
|
|
268
|
+
// unstyled rect) keep the textbox path below, so they don't inherit the
|
|
269
|
+
// shape renderer's default accent styling.
|
|
270
|
+
if (shape && isDrawingShape(shape)) {
|
|
271
|
+
const shapeSpec = parseShapeSpec(shape);
|
|
272
|
+
const cxEmu = parseInt(get(shape, "xdr:spPr.a:xfrm.a:ext.a$.cx") ||
|
|
273
|
+
get(shape, "spPr.xfrm.ext.a$.cx") ||
|
|
274
|
+
"0");
|
|
275
|
+
const cyEmu = parseInt(get(shape, "xdr:spPr.a:xfrm.a:ext.a$.cy") ||
|
|
276
|
+
get(shape, "spPr.xfrm.ext.a$.cy") ||
|
|
277
|
+
"0");
|
|
278
|
+
if (cxEmu > 0 && cyEmu > 0 && position.overlayPosition) {
|
|
279
|
+
position.overlayPosition.widthPixels = emuToPixels(cxEmu);
|
|
280
|
+
position.overlayPosition.heightPixels = emuToPixels(cyEmu);
|
|
281
|
+
}
|
|
282
|
+
// Shape rotation lives on the embed (like images), in degrees.
|
|
283
|
+
const rotUnits = parseInt(get(shape, "xdr:spPr.a:xfrm.a$.rot") ||
|
|
284
|
+
get(shape, "spPr.xfrm.a$.rot") ||
|
|
285
|
+
"0");
|
|
286
|
+
images.push({
|
|
287
|
+
isInsideCell,
|
|
288
|
+
embedId: uuid(),
|
|
289
|
+
spec: shapeSpec,
|
|
290
|
+
position,
|
|
291
|
+
rotation: rotUnits ? rotUnits / 60000 : undefined,
|
|
292
|
+
draggable: true,
|
|
293
|
+
});
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
// Process textbox if shape has text body
|
|
297
|
+
if (shape) {
|
|
298
|
+
const txBody = get(shape, "xdr:txBody") || get(shape, "txBody");
|
|
299
|
+
if (txBody) {
|
|
300
|
+
// Extract textbox properties
|
|
301
|
+
const textBoxName = get(shape, "xdr:nvSpPr.xdr:cNvPr.a$.name") ||
|
|
302
|
+
get(shape, "nvSpPr.cNvPr.a$.name") ||
|
|
303
|
+
"TextBox";
|
|
304
|
+
const textBoxId = get(shape, "xdr:nvSpPr.xdr:cNvPr.a$.id") ||
|
|
305
|
+
get(shape, "nvSpPr.cNvPr.a$.id") ||
|
|
306
|
+
"";
|
|
307
|
+
// Extract explicit width/height from shape properties (similar to images)
|
|
308
|
+
const cxEmu = parseInt(get(shape, "xdr:spPr.a:xfrm.a:ext.a$.cx") ||
|
|
309
|
+
get(shape, "spPr.xfrm.ext.a$.cx") ||
|
|
310
|
+
"0");
|
|
311
|
+
const cyEmu = parseInt(get(shape, "xdr:spPr.a:xfrm.a:ext.a$.cy") ||
|
|
312
|
+
get(shape, "spPr.xfrm.ext.a$.cy") ||
|
|
313
|
+
"0");
|
|
314
|
+
// Convert EMUs to pixels and override position dimensions if available
|
|
315
|
+
if (cxEmu > 0 && cyEmu > 0) {
|
|
316
|
+
const width = emuToPixels(cxEmu);
|
|
317
|
+
const height = emuToPixels(cyEmu);
|
|
318
|
+
if (position.overlayPosition) {
|
|
319
|
+
position.overlayPosition.widthPixels = width;
|
|
320
|
+
position.overlayPosition.heightPixels = height;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
// Parse text content and formatting
|
|
324
|
+
const textBoxSpec = parseTextBoxContent(txBody, shape);
|
|
325
|
+
images.push({
|
|
326
|
+
isInsideCell,
|
|
327
|
+
embedId: uuid(),
|
|
328
|
+
spec: textBoxSpec,
|
|
329
|
+
position,
|
|
330
|
+
draggable: true,
|
|
331
|
+
});
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (!picture)
|
|
336
|
+
continue;
|
|
337
|
+
// Get the embedded picture relationship ID with different possible paths
|
|
338
|
+
const blipRId = get(picture, "xdr:blipFill.a:blip.a$.embed") ||
|
|
339
|
+
get(picture, "xdr:blipFill.a:blip.a$.r:embed") ||
|
|
340
|
+
get(picture, "blipFill.a:blip.a$.embed") ||
|
|
341
|
+
get(picture, "blipFill.a:blip.a$.r:embed") ||
|
|
342
|
+
get(picture, "blipFill.blip.a$.embed") ||
|
|
343
|
+
get(picture, "blipFill.blip.a$.r:embed");
|
|
344
|
+
if (!blipRId)
|
|
345
|
+
continue;
|
|
346
|
+
// Get the name of the image if available - handle different path patterns
|
|
347
|
+
const imageName = get(picture, "xdr:nvPicPr.xdr:cNvPr.a$.name") ||
|
|
348
|
+
get(picture, "nvPicPr.cNvPr.a$.name") ||
|
|
349
|
+
"Image";
|
|
350
|
+
// Get the image ID - handle different path patterns
|
|
351
|
+
const imageId = get(picture, "xdr:nvPicPr.xdr:cNvPr.a$.id") ||
|
|
352
|
+
get(picture, "nvPicPr.cNvPr.a$.id") ||
|
|
353
|
+
"";
|
|
354
|
+
// Get title if available
|
|
355
|
+
const imageTitle = get(picture, "xdr:nvPicPr.xdr:cNvPr.a$.title") ||
|
|
356
|
+
get(picture, "nvPicPr.cNvPr.a$.title") ||
|
|
357
|
+
"";
|
|
358
|
+
// 3. Get the image file from the drawing relationships
|
|
359
|
+
const drawingDir = drawingPath.substring(0, drawingPath.lastIndexOf("/"));
|
|
360
|
+
const drawingFilename = drawingPath.split("/").pop();
|
|
361
|
+
const drawingRelsPath = `${drawingDir}/_rels/${drawingFilename}.rels`;
|
|
362
|
+
const drawingRelsContent = await zipParser.getText(drawingRelsPath);
|
|
363
|
+
if (!drawingRelsContent)
|
|
364
|
+
continue;
|
|
365
|
+
// Parse drawing relationships
|
|
366
|
+
const drawingRels = xmlParser.parse(drawingRelsContent);
|
|
367
|
+
const imageRelations = get(drawingRels, "Relationships.Relationship");
|
|
368
|
+
if (!imageRelations)
|
|
369
|
+
continue;
|
|
370
|
+
// Find the specific image relationship
|
|
371
|
+
const imageRel = Array.isArray(imageRelations)
|
|
372
|
+
? imageRelations.find((rel) => rel.a$.Id === blipRId)
|
|
373
|
+
: imageRelations.a$.Id === blipRId
|
|
374
|
+
? imageRelations
|
|
375
|
+
: null;
|
|
376
|
+
if (!imageRel)
|
|
377
|
+
continue;
|
|
378
|
+
// Get the target path of the image
|
|
379
|
+
const imageTarget = imageRel.a$.Target;
|
|
380
|
+
let imagePath;
|
|
381
|
+
// Handle different path formats
|
|
382
|
+
if (imageTarget.startsWith("/")) {
|
|
383
|
+
// Absolute path from the root of the zip
|
|
384
|
+
imagePath = imageTarget.substring(1);
|
|
385
|
+
}
|
|
386
|
+
else if (imageTarget.startsWith("../")) {
|
|
387
|
+
// Relative path going up directories
|
|
388
|
+
// Since drawingDir is something like 'xl/drawings',
|
|
389
|
+
// and '../media/image1.png' means 'xl/media/image1.png'
|
|
390
|
+
const baseDir = drawingDir.split("/").slice(0, -1).join("/");
|
|
391
|
+
imagePath = `${baseDir}/${imageTarget.replace("../", "")}`;
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
// Relative path in the same directory
|
|
395
|
+
imagePath = `${drawingDir}/${imageTarget}`;
|
|
396
|
+
}
|
|
397
|
+
// 4. Get the actual image data
|
|
398
|
+
const imageData = await zipParser.getBinary(imagePath);
|
|
399
|
+
if (!imageData)
|
|
400
|
+
continue;
|
|
401
|
+
// Determine image type from the path
|
|
402
|
+
const imageExt = imagePath.split(".").pop()?.toLowerCase() || "";
|
|
403
|
+
const imageType = `image/${imageExt === "jpg" ? "jpeg" : imageExt}`;
|
|
404
|
+
// Add the image to our collection
|
|
405
|
+
images.push({
|
|
406
|
+
isInsideCell,
|
|
407
|
+
embedId: uuid(),
|
|
408
|
+
spec: {
|
|
409
|
+
id: imageId,
|
|
410
|
+
imageUrl: createDataUrl(imageData, imageType),
|
|
411
|
+
type: "image",
|
|
412
|
+
description: imageName,
|
|
413
|
+
},
|
|
414
|
+
position,
|
|
415
|
+
draggable: true,
|
|
416
|
+
lockAspectRatio: true,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
return images;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Parse color from DrawingML color element
|
|
423
|
+
* Supports both RGB (srgbClr) and theme colors (schemeClr)
|
|
424
|
+
*/
|
|
425
|
+
function parseDrawingColor(colorElement) {
|
|
426
|
+
if (!colorElement)
|
|
427
|
+
return undefined;
|
|
428
|
+
// RGB color
|
|
429
|
+
const srgbClr = get(colorElement, "a:srgbClr.a$.val");
|
|
430
|
+
if (srgbClr) {
|
|
431
|
+
return `#${srgbClr}`;
|
|
432
|
+
}
|
|
433
|
+
// Theme color - map to approximate RGB values
|
|
434
|
+
const schemeClr = get(colorElement, "a:schemeClr.a$.val");
|
|
435
|
+
if (schemeClr) {
|
|
436
|
+
// Basic theme color mapping (Office theme defaults)
|
|
437
|
+
const themeColorMap = {
|
|
438
|
+
accent1: "#4472C4",
|
|
439
|
+
accent2: "#ED7D31",
|
|
440
|
+
accent3: "#A5A5A5",
|
|
441
|
+
accent4: "#FFC000",
|
|
442
|
+
accent5: "#5B9BD5",
|
|
443
|
+
accent6: "#70AD47",
|
|
444
|
+
dk1: "#000000",
|
|
445
|
+
lt1: "#FFFFFF",
|
|
446
|
+
dk2: "#44546A",
|
|
447
|
+
lt2: "#E7E6E6",
|
|
448
|
+
hlink: "#0563C1",
|
|
449
|
+
folHlink: "#954F72",
|
|
450
|
+
};
|
|
451
|
+
return themeColorMap[schemeClr] || "#000000";
|
|
452
|
+
}
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
const toArray = (value) => Array.isArray(value) ? value : value ? [value] : [];
|
|
456
|
+
/** DrawingML scheme-color names → the spreadsheet theme's ColorIndex slots. */
|
|
457
|
+
const SCHEME_TO_THEME_INDEX = {
|
|
458
|
+
bg1: 0,
|
|
459
|
+
lt1: 0,
|
|
460
|
+
tx1: 1,
|
|
461
|
+
dk1: 1,
|
|
462
|
+
bg2: 2,
|
|
463
|
+
lt2: 2,
|
|
464
|
+
tx2: 3,
|
|
465
|
+
dk2: 3,
|
|
466
|
+
accent1: 4,
|
|
467
|
+
accent2: 5,
|
|
468
|
+
accent3: 6,
|
|
469
|
+
accent4: 7,
|
|
470
|
+
accent5: 8,
|
|
471
|
+
accent6: 9,
|
|
472
|
+
hlink: 10,
|
|
473
|
+
};
|
|
474
|
+
/** OOXML preset names → the renderer's preset union where they differ. */
|
|
475
|
+
const PRESET_RENAMES = {
|
|
476
|
+
rtTriangle: "rightTriangle",
|
|
477
|
+
snip1Rect: "snipSingleCornerRect",
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* Parse a DrawingML color element into a `Color` — a live theme reference
|
|
481
|
+
* (`{ theme, tint }`) for `<a:schemeClr>` (so the shape follows document theme
|
|
482
|
+
* changes, unlike {@link parseDrawingColor}'s baked-in hex), or a hex string
|
|
483
|
+
* for `<a:srgbClr>`. Luminance/tint modifiers map onto the theme tint:
|
|
484
|
+
* `lumOff`/`tint` lighten (accent1 "lighter 40%" = lumMod 60000 + lumOff 40000
|
|
485
|
+
* → tint 0.4), `shade`/`lumMod`-only darken.
|
|
486
|
+
*/
|
|
487
|
+
function parseDrawingColorValue(colorElement) {
|
|
488
|
+
if (!colorElement)
|
|
489
|
+
return undefined;
|
|
490
|
+
const srgbClr = get(colorElement, "a:srgbClr.a$.val");
|
|
491
|
+
if (srgbClr)
|
|
492
|
+
return `#${srgbClr}`;
|
|
493
|
+
const schemeClr = get(colorElement, "a:schemeClr");
|
|
494
|
+
const schemeVal = get(schemeClr, "a$.val");
|
|
495
|
+
if (schemeVal) {
|
|
496
|
+
const theme = SCHEME_TO_THEME_INDEX[schemeVal];
|
|
497
|
+
if (theme === undefined) {
|
|
498
|
+
// Unmapped scheme name (e.g. folHlink): fall back to the baked hex.
|
|
499
|
+
return parseDrawingColor(colorElement);
|
|
500
|
+
}
|
|
501
|
+
const lumOff = parseInt(get(schemeClr, "a:lumOff.a$.val") || "0");
|
|
502
|
+
const tintVal = parseInt(get(schemeClr, "a:tint.a$.val") || "0");
|
|
503
|
+
const shade = parseInt(get(schemeClr, "a:shade.a$.val") || "0");
|
|
504
|
+
const lumMod = parseInt(get(schemeClr, "a:lumMod.a$.val") || "0");
|
|
505
|
+
let tint;
|
|
506
|
+
if (lumOff > 0)
|
|
507
|
+
tint = lumOff / 100000;
|
|
508
|
+
else if (tintVal > 0)
|
|
509
|
+
tint = tintVal / 100000;
|
|
510
|
+
else if (shade > 0)
|
|
511
|
+
tint = -(1 - shade / 100000);
|
|
512
|
+
else if (lumMod > 0 && lumMod < 100000)
|
|
513
|
+
tint = -(1 - lumMod / 100000);
|
|
514
|
+
return tint !== undefined ? { theme, tint } : { theme };
|
|
515
|
+
}
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
518
|
+
/** `<a:alpha val>` (1/100000) under a color element → 0–1 opacity, if reduced. */
|
|
519
|
+
function parseColorOpacity(colorElement) {
|
|
520
|
+
const alpha = parseInt(get(colorElement, "a:srgbClr.a:alpha.a$.val") ||
|
|
521
|
+
get(colorElement, "a:schemeClr.a:alpha.a$.val") ||
|
|
522
|
+
"0");
|
|
523
|
+
return alpha > 0 && alpha < 100000 ? alpha / 100000 : undefined;
|
|
524
|
+
}
|
|
525
|
+
/** `<a:prstGeom>` → geometry preset + `<a:avLst>` adjust guides. */
|
|
526
|
+
function parseShapeGeometry(spPr) {
|
|
527
|
+
const prstGeom = get(spPr, "a:prstGeom");
|
|
528
|
+
const prst = get(prstGeom, "a$.prst");
|
|
529
|
+
if (!prst)
|
|
530
|
+
return undefined;
|
|
531
|
+
let adjustments;
|
|
532
|
+
for (const gd of toArray(get(prstGeom, "a:avLst.a:gd"))) {
|
|
533
|
+
const name = get(gd, "a$.name");
|
|
534
|
+
const fmla = get(gd, "a$.fmla") || "";
|
|
535
|
+
const match = /^val\s+(-?\d+)$/.exec(fmla);
|
|
536
|
+
if (name && match) {
|
|
537
|
+
(adjustments ??= {})[name] = parseInt(match[1]);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return { preset: PRESET_RENAMES[prst] ?? prst, adjustments };
|
|
541
|
+
}
|
|
542
|
+
/** Empty elements (`<a:noFill/>`) parse to `""` — presence must not be truthiness. */
|
|
543
|
+
const hasElement = (obj, path) => get(obj, path) !== undefined;
|
|
544
|
+
/** Explicit `<a:noFill>`/`<a:solidFill>`/`<a:gradFill>` on `spPr` (style refs are separate). */
|
|
545
|
+
function parseShapeFill(spPr) {
|
|
546
|
+
if (hasElement(spPr, "a:noFill"))
|
|
547
|
+
return { kind: "none" };
|
|
548
|
+
const solidFill = get(spPr, "a:solidFill");
|
|
549
|
+
if (solidFill) {
|
|
550
|
+
const color = parseDrawingColorValue(solidFill);
|
|
551
|
+
if (color) {
|
|
552
|
+
return { kind: "solid", color, opacity: parseColorOpacity(solidFill) };
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
const gradFill = get(spPr, "a:gradFill");
|
|
556
|
+
if (gradFill) {
|
|
557
|
+
const stops = toArray(get(gradFill, "a:gsLst.a:gs"))
|
|
558
|
+
.map((gs) => ({
|
|
559
|
+
position: parseInt(get(gs, "a$.pos") || "0") / 100000,
|
|
560
|
+
color: parseDrawingColorValue(gs) ?? "#FFFFFF",
|
|
561
|
+
opacity: parseColorOpacity(gs),
|
|
562
|
+
}))
|
|
563
|
+
.sort((a, b) => a.position - b.position);
|
|
564
|
+
if (stops.length) {
|
|
565
|
+
const ang = parseInt(get(gradFill, "a:lin.a$.ang") || "0");
|
|
566
|
+
return {
|
|
567
|
+
kind: "gradient",
|
|
568
|
+
stops,
|
|
569
|
+
angle: ang ? ang / 60000 : 90,
|
|
570
|
+
shading: get(gradFill, "a:path") ? "radial" : "linear",
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
return undefined;
|
|
575
|
+
}
|
|
576
|
+
const DASH_RENAMES = {
|
|
577
|
+
solid: "solid",
|
|
578
|
+
dot: "dot",
|
|
579
|
+
sysDot: "dot",
|
|
580
|
+
dash: "dash",
|
|
581
|
+
sysDash: "dash",
|
|
582
|
+
dashDot: "dashDot",
|
|
583
|
+
sysDashDot: "dashDot",
|
|
584
|
+
lgDash: "longDash",
|
|
585
|
+
lgDashDot: "longDashDot",
|
|
586
|
+
lgDashDotDot: "longDashDotDot",
|
|
587
|
+
};
|
|
588
|
+
/** `<a:ln>` → outline; `<a:noFill>` inside it means explicitly strokeless (width 0). */
|
|
589
|
+
function parseShapeOutline(spPr) {
|
|
590
|
+
const ln = get(spPr, "a:ln");
|
|
591
|
+
if (ln === undefined)
|
|
592
|
+
return undefined;
|
|
593
|
+
if (hasElement(ln, "a:noFill"))
|
|
594
|
+
return { width: 0 };
|
|
595
|
+
const solidFill = get(ln, "a:solidFill");
|
|
596
|
+
const color = parseDrawingColorValue(solidFill);
|
|
597
|
+
const wEmu = parseInt(get(ln, "a$.w") || "0");
|
|
598
|
+
const dashVal = get(ln, "a:prstDash.a$.val");
|
|
599
|
+
if (!color && !wEmu && !dashVal)
|
|
600
|
+
return undefined;
|
|
601
|
+
return {
|
|
602
|
+
color,
|
|
603
|
+
width: wEmu ? emuToPixels(wEmu) : undefined,
|
|
604
|
+
dash: dashVal ? DASH_RENAMES[dashVal] : undefined,
|
|
605
|
+
opacity: solidFill ? parseColorOpacity(solidFill) : undefined,
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
/** `<a:effectLst><a:outerShdw>` → drop shadow (distance+direction → x/y offsets). */
|
|
609
|
+
function parseShapeShadow(spPr) {
|
|
610
|
+
const shdw = get(spPr, "a:effectLst.a:outerShdw");
|
|
611
|
+
if (!shdw)
|
|
612
|
+
return undefined;
|
|
613
|
+
const distPx = emuToPixels(parseInt(get(shdw, "a$.dist") || "0"));
|
|
614
|
+
const dirRad = (parseInt(get(shdw, "a$.dir") || "0") / 60000) * (Math.PI / 180);
|
|
615
|
+
const blurRad = parseInt(get(shdw, "a$.blurRad") || "0");
|
|
616
|
+
return {
|
|
617
|
+
color: parseDrawingColorValue(shdw),
|
|
618
|
+
opacity: parseColorOpacity(shdw),
|
|
619
|
+
blurRadius: blurRad ? emuToPixels(blurRad) : undefined,
|
|
620
|
+
offsetXPixels: distPx ? Math.round(Math.cos(dirRad) * distPx) : undefined,
|
|
621
|
+
offsetYPixels: distPx ? Math.round(Math.sin(dirRad) * distPx) : undefined,
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
/** `<xdr:style>` fill/line/effect/font references into the theme format scheme. */
|
|
625
|
+
function parseShapeStyleRefs(shape) {
|
|
626
|
+
const style = get(shape, "xdr:style") || get(shape, "style");
|
|
627
|
+
if (!style)
|
|
628
|
+
return undefined;
|
|
629
|
+
const parseRef = (name) => {
|
|
630
|
+
const ref = get(style, name);
|
|
631
|
+
if (!ref)
|
|
632
|
+
return undefined;
|
|
633
|
+
const index = parseInt(get(ref, "a$.idx") || "0");
|
|
634
|
+
const color = parseDrawingColorValue(ref);
|
|
635
|
+
return color ? { index, color } : undefined;
|
|
636
|
+
};
|
|
637
|
+
const refs = {
|
|
638
|
+
fill: parseRef("a:fillRef"),
|
|
639
|
+
line: parseRef("a:lnRef"),
|
|
640
|
+
effect: parseRef("a:effectRef"),
|
|
641
|
+
};
|
|
642
|
+
const fontRef = get(style, "a:fontRef");
|
|
643
|
+
if (fontRef) {
|
|
644
|
+
const scheme = get(fontRef, "a$.idx");
|
|
645
|
+
if (scheme === "major" || scheme === "minor") {
|
|
646
|
+
refs.font = { scheme, color: parseDrawingColorValue(fontRef) };
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return refs.fill || refs.line || refs.effect || refs.font ? refs : undefined;
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* Whether an `<xdr:sp>` should import as a drawing shape (`EmbedShapeSpec`)
|
|
653
|
+
* rather than a textbox. Text boxes are excluded explicitly (`txBox="1"`), and
|
|
654
|
+
* a rect with no `<xdr:style>` block stays a textbox too — routing those to
|
|
655
|
+
* the shape renderer would repaint plain text notes with the default accent
|
|
656
|
+
* shape style.
|
|
657
|
+
*/
|
|
658
|
+
export function isDrawingShape(shape) {
|
|
659
|
+
const txBox = get(shape, "xdr:nvSpPr.xdr:cNvSpPr.a$.txBox") ||
|
|
660
|
+
get(shape, "nvSpPr.cNvSpPr.a$.txBox");
|
|
661
|
+
if (txBox === "1" || txBox === true)
|
|
662
|
+
return false;
|
|
663
|
+
const spPr = get(shape, "xdr:spPr") || get(shape, "spPr");
|
|
664
|
+
const preset = get(spPr, "a:prstGeom.a$.prst");
|
|
665
|
+
if (preset && preset !== "rect")
|
|
666
|
+
return true;
|
|
667
|
+
return hasElement(shape, "xdr:style") || hasElement(shape, "style");
|
|
668
|
+
}
|
|
669
|
+
/** Parse an `<xdr:sp>` drawing shape into an {@link EmbedShapeSpec}. */
|
|
670
|
+
export function parseShapeSpec(shape) {
|
|
671
|
+
const spPr = get(shape, "xdr:spPr") || get(shape, "spPr");
|
|
672
|
+
const name = get(shape, "xdr:nvSpPr.xdr:cNvPr.a$.name") ||
|
|
673
|
+
get(shape, "nvSpPr.cNvPr.a$.name");
|
|
674
|
+
// Shape text rides the textbox content model; box-level background/borders
|
|
675
|
+
// are shape fill/outline concerns, so only the text fields carry over. An
|
|
676
|
+
// empty text body (Excel writes one on every shape) is omitted entirely.
|
|
677
|
+
let textBody;
|
|
678
|
+
const txBody = get(shape, "xdr:txBody") || get(shape, "txBody");
|
|
679
|
+
if (txBody) {
|
|
680
|
+
const tb = parseTextBoxContent(txBody, shape);
|
|
681
|
+
const hasText = Boolean(tb.text?.trim()) ||
|
|
682
|
+
Boolean(tb.richText?.some((run) => run.text.trim()));
|
|
683
|
+
if (hasText) {
|
|
684
|
+
textBody = {
|
|
685
|
+
text: tb.text,
|
|
686
|
+
richText: tb.richText,
|
|
687
|
+
textFormat: tb.textFormat,
|
|
688
|
+
verticalAlignment: tb.verticalAlignment,
|
|
689
|
+
horizontalAlignment: tb.horizontalAlignment,
|
|
690
|
+
wrapStrategy: tb.wrapStrategy,
|
|
691
|
+
textRotation: tb.textRotation,
|
|
692
|
+
padding: tb.padding,
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
const xfrm = get(spPr, "a:xfrm");
|
|
697
|
+
const flipH = get(xfrm, "a$.flipH");
|
|
698
|
+
const flipV = get(xfrm, "a$.flipV");
|
|
699
|
+
return {
|
|
700
|
+
type: "shape",
|
|
701
|
+
name,
|
|
702
|
+
geometry: parseShapeGeometry(spPr) ?? { preset: "rect" },
|
|
703
|
+
fill: parseShapeFill(spPr),
|
|
704
|
+
outline: parseShapeOutline(spPr),
|
|
705
|
+
shadow: parseShapeShadow(spPr),
|
|
706
|
+
styleRefs: parseShapeStyleRefs(shape),
|
|
707
|
+
textBody,
|
|
708
|
+
flipHorizontal: flipH === "1" || flipH === true ? true : undefined,
|
|
709
|
+
flipVertical: flipV === "1" || flipV === true ? true : undefined,
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* Parse textbox content from DrawingML text body
|
|
714
|
+
* @param txBody The text body element from DrawingML
|
|
715
|
+
* @param shape The shape element containing formatting properties
|
|
716
|
+
* @returns EmbedTextBoxSpec object
|
|
717
|
+
*/
|
|
718
|
+
function parseTextBoxContent(txBody, shape) {
|
|
719
|
+
const richText = [];
|
|
720
|
+
let plainText = "";
|
|
721
|
+
// Get paragraphs
|
|
722
|
+
const paragraphs = get(txBody, "a:p") || [];
|
|
723
|
+
const paragraphArray = Array.isArray(paragraphs) ? paragraphs : [paragraphs];
|
|
724
|
+
for (const paragraph of paragraphArray) {
|
|
725
|
+
// Extract paragraph properties for indentation and bullets
|
|
726
|
+
const pPr = get(paragraph, "a:pPr") || {};
|
|
727
|
+
const indentEmu = parseInt(get(pPr, "a$.marL") || get(pPr, "a$.indent") || "0");
|
|
728
|
+
// Convert EMUs to approximate character spaces (roughly 90000 EMUs ≈ 1 character space)
|
|
729
|
+
const indentSpaces = Math.round(indentEmu / 90000);
|
|
730
|
+
// Check for bullets
|
|
731
|
+
let bulletChar = "";
|
|
732
|
+
const buChar = get(pPr, "a:buChar.a$.char");
|
|
733
|
+
const buAutoNum = get(pPr, "a:buAutoNum");
|
|
734
|
+
const buNone = get(pPr, "a:buNone");
|
|
735
|
+
if (!buNone) {
|
|
736
|
+
if (buChar) {
|
|
737
|
+
// Custom bullet character (e.g., "•", "-", etc.)
|
|
738
|
+
bulletChar = buChar + " ";
|
|
739
|
+
}
|
|
740
|
+
else if (buAutoNum) {
|
|
741
|
+
// Auto-numbered bullets (would need context to track numbering)
|
|
742
|
+
bulletChar = "• ";
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
// Get text runs
|
|
746
|
+
const runs = get(paragraph, "a:r") || [];
|
|
747
|
+
const runArray = Array.isArray(runs) ? runs : runs ? [runs] : [];
|
|
748
|
+
// Add indentation and bullet to the first run of the paragraph
|
|
749
|
+
let isFirstRun = true;
|
|
750
|
+
for (const run of runArray) {
|
|
751
|
+
let text = get(run, "a:t.t$") || get(run, "a:t") || "";
|
|
752
|
+
// Handle tab characters
|
|
753
|
+
const tabElements = get(run, "a:tab");
|
|
754
|
+
if (tabElements) {
|
|
755
|
+
const tabCount = Array.isArray(tabElements) ? tabElements.length : 1;
|
|
756
|
+
text = "\t".repeat(tabCount) + text;
|
|
757
|
+
}
|
|
758
|
+
// Add indentation and bullet to the first run
|
|
759
|
+
if (isFirstRun) {
|
|
760
|
+
if (indentSpaces > 0) {
|
|
761
|
+
const indent = " ".repeat(indentSpaces);
|
|
762
|
+
text = indent + text;
|
|
763
|
+
}
|
|
764
|
+
if (bulletChar) {
|
|
765
|
+
text = bulletChar + text;
|
|
766
|
+
}
|
|
767
|
+
isFirstRun = false;
|
|
768
|
+
}
|
|
769
|
+
plainText += text;
|
|
770
|
+
// Parse run properties
|
|
771
|
+
const rPr = get(run, "a:rPr") || {};
|
|
772
|
+
const format = {};
|
|
773
|
+
// Font size (in points * 100, e.g., 1100 = 11pt)
|
|
774
|
+
const sz = parseInt(get(rPr, "a$.sz") || "0");
|
|
775
|
+
if (sz > 0) {
|
|
776
|
+
format.fontSize = sz / 100;
|
|
777
|
+
}
|
|
778
|
+
// Bold
|
|
779
|
+
const bold = get(rPr, "a$.b");
|
|
780
|
+
if (bold === "1" || bold === true) {
|
|
781
|
+
format.bold = true;
|
|
782
|
+
}
|
|
783
|
+
// Italic
|
|
784
|
+
const italic = get(rPr, "a$.i");
|
|
785
|
+
if (italic === "1" || italic === true) {
|
|
786
|
+
format.italic = true;
|
|
787
|
+
}
|
|
788
|
+
// Underline
|
|
789
|
+
const underline = get(rPr, "a$.u");
|
|
790
|
+
if (underline && underline !== "none") {
|
|
791
|
+
format.underline = true;
|
|
792
|
+
}
|
|
793
|
+
// Strikethrough
|
|
794
|
+
const strike = get(rPr, "a$.strike");
|
|
795
|
+
if (strike && strike !== "noStrike") {
|
|
796
|
+
format.strikethrough = true;
|
|
797
|
+
}
|
|
798
|
+
// Font family
|
|
799
|
+
const fontFamily = get(rPr, "a:latin.a$.typeface");
|
|
800
|
+
if (fontFamily) {
|
|
801
|
+
format.fontFamily = fontFamily;
|
|
802
|
+
}
|
|
803
|
+
// Text color (supports RGB and theme colors)
|
|
804
|
+
const solidFill = get(rPr, "a:solidFill");
|
|
805
|
+
const color = parseDrawingColor(solidFill);
|
|
806
|
+
if (color) {
|
|
807
|
+
format.color = color;
|
|
808
|
+
}
|
|
809
|
+
richText.push({
|
|
810
|
+
text,
|
|
811
|
+
format: Object.keys(format).length > 0 ? format : undefined,
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
// Add paragraph break (newline) between paragraphs
|
|
815
|
+
if (paragraphArray.indexOf(paragraph) < paragraphArray.length - 1) {
|
|
816
|
+
plainText += "\n";
|
|
817
|
+
richText.push({ text: "\n" });
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
// Get shape properties for background, borders, etc.
|
|
821
|
+
const spPr = get(shape, "xdr:spPr") || get(shape, "spPr");
|
|
822
|
+
const spec = {
|
|
823
|
+
type: "textbox",
|
|
824
|
+
text: plainText,
|
|
825
|
+
richText: richText.length > 0 ? richText : undefined,
|
|
826
|
+
};
|
|
827
|
+
// Parse background color (supports RGB and theme colors)
|
|
828
|
+
const solidFill = get(spPr, "a:solidFill");
|
|
829
|
+
const bgColor = parseDrawingColor(solidFill);
|
|
830
|
+
if (bgColor) {
|
|
831
|
+
spec.backgroundColor = bgColor;
|
|
832
|
+
}
|
|
833
|
+
// Parse text alignment and other properties from body properties
|
|
834
|
+
const bodyPr = get(txBody, "a:bodyPr") || {};
|
|
835
|
+
const anchor = get(bodyPr, "a$.anchor");
|
|
836
|
+
if (anchor) {
|
|
837
|
+
// Map DrawingML anchor to our vertical alignment
|
|
838
|
+
const anchorMap = {
|
|
839
|
+
t: "top",
|
|
840
|
+
ctr: "middle",
|
|
841
|
+
b: "bottom",
|
|
842
|
+
};
|
|
843
|
+
spec.verticalAlignment = anchorMap[anchor];
|
|
844
|
+
}
|
|
845
|
+
// Parse wrap strategy
|
|
846
|
+
const wrap = get(bodyPr, "a$.wrap");
|
|
847
|
+
if (wrap) {
|
|
848
|
+
const wrapMap = {
|
|
849
|
+
square: "wrap",
|
|
850
|
+
none: "overflow",
|
|
851
|
+
};
|
|
852
|
+
spec.wrapStrategy = wrapMap[wrap];
|
|
853
|
+
}
|
|
854
|
+
// Parse padding (insets) - convert from EMUs to pixels
|
|
855
|
+
const lIns = parseInt(get(bodyPr, "a$.lIns") || "0");
|
|
856
|
+
const rIns = parseInt(get(bodyPr, "a$.rIns") || "0");
|
|
857
|
+
const tIns = parseInt(get(bodyPr, "a$.tIns") || "0");
|
|
858
|
+
const bIns = parseInt(get(bodyPr, "a$.bIns") || "0");
|
|
859
|
+
// Use average of insets as padding (or could store separately if needed)
|
|
860
|
+
const avgPadding = (lIns + rIns + tIns + bIns) / 4;
|
|
861
|
+
if (avgPadding > 0) {
|
|
862
|
+
spec.padding = emuToPixels(avgPadding);
|
|
863
|
+
}
|
|
864
|
+
return spec;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Determine if a two-cell anchored image is inside a cell
|
|
868
|
+
* @param editAs The editAs attribute value
|
|
869
|
+
* @param fromCol From column
|
|
870
|
+
* @param fromRow From row
|
|
871
|
+
* @param toCol To column
|
|
872
|
+
* @param toRow To row
|
|
873
|
+
* @returns Boolean indicating if image is inside a cell
|
|
874
|
+
*/
|
|
875
|
+
function determineIfTwoCellInsideCell(editAs, fromCol, fromRow, toCol, toRow) {
|
|
876
|
+
// Two-cell anchors represent floating images in Excel. We only mark them as
|
|
877
|
+
// "cell" content when the rectangle is constrained to a single cell.
|
|
878
|
+
return fromCol === toCol && fromRow === toRow;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Determine if a oneCellAnchor image is inside a cell
|
|
882
|
+
* Using EMU values for accurate assessment
|
|
883
|
+
* @param fromColOff Column offset in EMUs
|
|
884
|
+
* @param fromRowOff Row offset in EMUs
|
|
885
|
+
* @param fLocksWithSheet Whether image locks with sheet
|
|
886
|
+
* @param cx Image width in EMUs
|
|
887
|
+
* @param cy Image height in EMUs
|
|
888
|
+
* @returns Boolean indicating if the image is inside a cell
|
|
889
|
+
*/
|
|
890
|
+
export function determineIfOneCellInsideCell(fromColOff, fromRowOff, fLocksWithSheet, cx, cy) {
|
|
891
|
+
const widthPixels = emuToPixels(Math.max(0, cx));
|
|
892
|
+
const heightPixels = emuToPixels(Math.max(0, cy));
|
|
893
|
+
const exceedsCellSize = (!!widthPixels && widthPixels > DEFAULT_CELL_IMAGE_MAX_SIZE_PX) ||
|
|
894
|
+
(!!heightPixels && heightPixels > DEFAULT_CELL_IMAGE_MAX_SIZE_PX);
|
|
895
|
+
if (exceedsCellSize) {
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
if (fLocksWithSheet === "1") {
|
|
899
|
+
return true;
|
|
900
|
+
}
|
|
901
|
+
const offsetXPixels = Math.abs(emuToPixels(fromColOff));
|
|
902
|
+
const offsetYPixels = Math.abs(emuToPixels(fromRowOff));
|
|
903
|
+
return (offsetXPixels <= CELL_IMAGE_OFFSET_THRESHOLD_PX &&
|
|
904
|
+
offsetYPixels <= CELL_IMAGE_OFFSET_THRESHOLD_PX);
|
|
905
|
+
}
|