reamkit 1.15.4 → 1.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/core/converter/facade.d.ts +5 -0
- package/dist/esm/core/converter/ream.d.ts +6 -0
- package/dist/esm/core/converter/ream.js +34 -8
- package/dist/esm/core/document-model/index.d.ts +1 -1
- package/dist/esm/core/document-model/types.d.ts +187 -1
- package/dist/esm/core/drawingml/chart-geometry.d.ts +28 -0
- package/dist/esm/core/drawingml/chart-geometry.js +371 -88
- package/dist/esm/core/drawingml/chart-parser.js +262 -11
- package/dist/esm/core/drawingml/colors.d.ts +6 -6
- package/dist/esm/core/drawingml/colors.js +58 -18
- package/dist/esm/core/drawingml/preset-geometry.js +7 -6
- package/dist/esm/core/drawingml/sparkline-geometry.js +6 -4
- package/dist/esm/core/drawingml/theme-parser.d.ts +41 -0
- package/dist/esm/core/drawingml/theme-parser.js +74 -1
- package/dist/esm/core/font/ttf-subset.js +26 -1
- package/dist/esm/core/images.js +172 -43
- package/dist/esm/core/indexed-colors.d.ts +11 -0
- package/dist/esm/core/indexed-colors.js +81 -0
- package/dist/esm/core/ir/sheet.d.ts +61 -0
- package/dist/esm/{excel → core}/number-format.d.ts +37 -0
- package/dist/esm/core/number-format.js +800 -0
- package/dist/esm/core/opc/alternate-content.d.ts +13 -0
- package/dist/esm/core/opc/alternate-content.js +72 -0
- package/dist/esm/core/opc/core-properties.js +1 -0
- package/dist/esm/core/opc/package.d.ts +14 -1
- package/dist/esm/core/opc/package.js +43 -4
- package/dist/esm/core/opc/relationships.js +1 -0
- package/dist/esm/core/opc/xml-entities.d.ts +12 -0
- package/dist/esm/core/opc/xml-entities.js +91 -0
- package/dist/esm/core/spreadsheet-model/index.d.ts +1 -1
- package/dist/esm/core/spreadsheet-model/types.d.ts +137 -0
- package/dist/esm/core/vector.d.ts +13 -0
- package/dist/esm/excel/activex-parser.js +1 -0
- package/dist/esm/excel/column-bands.d.ts +26 -1
- package/dist/esm/excel/column-bands.js +156 -20
- package/dist/esm/excel/comments-parser.js +5 -3
- package/dist/esm/excel/conditional-format.d.ts +25 -2
- package/dist/esm/excel/conditional-format.js +63 -19
- package/dist/esm/excel/escaped-text.d.ts +9 -0
- package/dist/esm/excel/escaped-text.js +20 -0
- package/dist/esm/excel/form-control-parser.js +1 -0
- package/dist/esm/excel/formula/dates.js +1 -1
- package/dist/esm/excel/header-footer.d.ts +9 -1
- package/dist/esm/excel/header-footer.js +162 -14
- package/dist/esm/excel/index.d.ts +1 -1
- package/dist/esm/excel/index.js +2 -2
- package/dist/esm/excel/pivot-table-parser.js +1 -0
- package/dist/esm/excel/print-model.d.ts +75 -0
- package/dist/esm/excel/print-model.js +898 -76
- package/dist/esm/excel/printer-settings.d.ts +16 -0
- package/dist/esm/excel/printer-settings.js +36 -0
- package/dist/esm/excel/rich-value.d.ts +13 -0
- package/dist/esm/excel/rich-value.js +120 -0
- package/dist/esm/excel/shared-strings-parser.js +11 -7
- package/dist/esm/excel/sheet-drawing.d.ts +11 -0
- package/dist/esm/excel/sheet-drawing.js +26 -3
- package/dist/esm/excel/sheet-shape-parser.d.ts +53 -1
- package/dist/esm/excel/sheet-shape-parser.js +461 -32
- package/dist/esm/excel/sheet-to-flow.d.ts +23 -2
- package/dist/esm/excel/sheet-to-flow.js +551 -36
- package/dist/esm/excel/slicer-parser.js +1 -0
- package/dist/esm/excel/styles-parser.d.ts +30 -2
- package/dist/esm/excel/styles-parser.js +177 -40
- package/dist/esm/excel/table-parser.js +1 -0
- package/dist/esm/excel/vml-drawing.d.ts +68 -0
- package/dist/esm/excel/vml-drawing.js +158 -0
- package/dist/esm/excel/workbook-parser.d.ts +5 -0
- package/dist/esm/excel/workbook-parser.js +5 -1
- package/dist/esm/excel/worksheet-parser.d.ts +2 -1
- package/dist/esm/excel/worksheet-parser.js +150 -61
- package/dist/esm/excel/xlsx-reader.js +242 -11
- package/dist/esm/excel/xlsx-to-pdf.js +12 -1
- package/dist/esm/html/html-writer.js +11 -2
- package/dist/esm/layout/page-doc.d.ts +26 -0
- package/dist/esm/layout/styled-layout.d.ts +2 -0
- package/dist/esm/layout/styled-layout.js +493 -64
- package/dist/esm/pdf/cid-font.js +20 -9
- package/dist/esm/pdf/objects.d.ts +13 -0
- package/dist/esm/pdf/objects.js +18 -1
- package/dist/esm/pdf/styled-page-emitter.js +164 -32
- package/dist/esm/pdf/text-page-renderer.js +1 -0
- package/dist/esm/pdf/vector-graphics.d.ts +3 -1
- package/dist/esm/pdf/vector-graphics.js +19 -2
- package/dist/esm/pptx/pptx-reader.js +1 -0
- package/dist/esm/pptx/slide-parser.js +12 -1
- package/dist/esm/svg/svg-writer.js +23 -4
- package/dist/esm/word/document-parser.js +1 -0
- package/dist/esm/word/drawing-parser.d.ts +34 -1
- package/dist/esm/word/drawing-parser.js +52 -2
- package/dist/esm/word/numbering-parser.js +1 -0
- package/dist/esm/word/settings-parser.js +1 -0
- package/dist/esm/word/styles-parser.js +1 -0
- package/package.json +7 -3
- package/dist/esm/excel/number-format.js +0 -476
|
@@ -3,6 +3,7 @@ import { XMLParser } from "fast-xml-parser";
|
|
|
3
3
|
//#region src/core/drawingml/theme-parser.ts
|
|
4
4
|
var decoder = new TextDecoder("utf-8");
|
|
5
5
|
var parser = new XMLParser({
|
|
6
|
+
htmlEntities: true,
|
|
6
7
|
ignoreAttributes: false,
|
|
7
8
|
attributeNamePrefix: "@_",
|
|
8
9
|
preserveOrder: true,
|
|
@@ -53,6 +54,78 @@ function parseTheme(themeXml) {
|
|
|
53
54
|
}
|
|
54
55
|
return out;
|
|
55
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse a theme's line-style widths (ECMA-376 §20.1.4.1.21 `a:lnStyleLst`).
|
|
59
|
+
*
|
|
60
|
+
* A shape drawn from the gallery keeps its outline as `<a:lnRef idx="N">`,
|
|
61
|
+
* which is a 1-based index into this list — the reference names the colour and
|
|
62
|
+
* the list holds the width. The standard Office theme is 0.75pt / 2pt / 3pt.
|
|
63
|
+
*
|
|
64
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
65
|
+
* @returns The widths in points, in list order; empty when the theme declares
|
|
66
|
+
* no `a:fmtScheme`.
|
|
67
|
+
*/
|
|
68
|
+
function parseThemeLineWidths(themeXml) {
|
|
69
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
70
|
+
"a:theme",
|
|
71
|
+
"a:themeElements",
|
|
72
|
+
"a:fmtScheme",
|
|
73
|
+
"a:lnStyleLst"
|
|
74
|
+
]);
|
|
75
|
+
if (!list) return [];
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const ln of poChildren(list)) {
|
|
78
|
+
if (!poIs(ln, "a:ln")) continue;
|
|
79
|
+
const w = Number(poAttr(ln, "w") ?? "");
|
|
80
|
+
out.push(Number.isFinite(w) && w > 0 ? w / EMU_PER_POINT : .75);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse a theme's fill styles (§20.1.4.1.13 `a:fillStyleLst`), as the raw nodes.
|
|
86
|
+
*
|
|
87
|
+
* A shape drawn from the gallery carries no fill of its own — only
|
|
88
|
+
* `<a:fillRef idx="N">`, a 1-based index into this list, and a colour to put
|
|
89
|
+
* where the styles say `phClr`. The standard Office theme's slots are a solid,
|
|
90
|
+
* a subtle gradient and a stronger one, so reading the reference's colour alone
|
|
91
|
+
* paints slot 3 flat: 47504.xlsx's rectangle is a gradient in both references
|
|
92
|
+
* and a single blue in ours.
|
|
93
|
+
*
|
|
94
|
+
* The nodes are handed back unparsed because what they hold is a whole fill —
|
|
95
|
+
* solid, gradient, pattern — which the shape readers already know how to read.
|
|
96
|
+
*
|
|
97
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
98
|
+
* @returns The `a:fillStyleLst` children in list order; empty when the theme
|
|
99
|
+
* declares no `a:fmtScheme`.
|
|
100
|
+
*/
|
|
101
|
+
function parseThemeFillStyles(themeXml) {
|
|
102
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
103
|
+
"a:theme",
|
|
104
|
+
"a:themeElements",
|
|
105
|
+
"a:fmtScheme",
|
|
106
|
+
"a:fillStyleLst"
|
|
107
|
+
]);
|
|
108
|
+
return list ? [...poChildren(list)] : [];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse a theme's effect styles (§20.1.4.1.15 `a:effectStyleLst`), as the raw
|
|
112
|
+
* nodes. `<a:effectRef idx="N">` is a 1-based index into this list, exactly as
|
|
113
|
+
* the fill and line references index theirs.
|
|
114
|
+
*
|
|
115
|
+
* @param themeXml The raw theme part bytes, UTF-8.
|
|
116
|
+
* @returns The `a:effectStyle` children in list order; empty when the theme
|
|
117
|
+
* declares no `a:fmtScheme`.
|
|
118
|
+
*/
|
|
119
|
+
function parseThemeEffectStyles(themeXml) {
|
|
120
|
+
const list = poFindByPath(parser.parse(decoder.decode(themeXml)), [
|
|
121
|
+
"a:theme",
|
|
122
|
+
"a:themeElements",
|
|
123
|
+
"a:fmtScheme",
|
|
124
|
+
"a:effectStyleLst"
|
|
125
|
+
]);
|
|
126
|
+
return list ? [...poChildren(list)] : [];
|
|
127
|
+
}
|
|
128
|
+
var EMU_PER_POINT = 12700;
|
|
56
129
|
function colorOf(slot) {
|
|
57
130
|
for (const c of poChildren(slot)) if (poIs(c, "a:srgbClr")) {
|
|
58
131
|
const v = poAttr(c, "val");
|
|
@@ -63,4 +136,4 @@ function colorOf(slot) {
|
|
|
63
136
|
}
|
|
64
137
|
}
|
|
65
138
|
//#endregion
|
|
66
|
-
export { parseTheme };
|
|
139
|
+
export { parseTheme, parseThemeEffectStyles, parseThemeFillStyles, parseThemeLineWidths };
|
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
var HEAD_CHECKSUM_ADJUSTMENT_OFFSET = 8;
|
|
3
3
|
var HEAD_INDEX_TO_LOC_FORMAT_OFFSET = 50;
|
|
4
4
|
var MAGIC_HEAD_CHECKSUM = 2981146554;
|
|
5
|
+
/**
|
|
6
|
+
* The tables a `/FontFile2` may carry (ISO 32000-1 §9.9.2).
|
|
7
|
+
*
|
|
8
|
+
* The spec names `glyf`, `head`, `hhea`, `hmtx`, `loca` and `maxp` as required,
|
|
9
|
+
* `cvt `/`fpgm`/`prep` when the glyphs are hinted, and `cmap` for a SYMBOLIC
|
|
10
|
+
* font. A CIDFontType2 with `/CIDToGIDMap /Identity` is not symbolic in that
|
|
11
|
+
* sense — §9.7.4.2 makes the CID the glyph index and never consults `cmap`, so
|
|
12
|
+
* 9.3 KB of it rode along in every font we embedded. Everything else is dead
|
|
13
|
+
* weight too, in a PDF that does its own positioning and text extraction: we copied `post`, `GPOS`, `GSUB`, `GDEF`, `name`,
|
|
14
|
+
* `hdmx`, `LTSH` and the rest through untouched, and they were 120 KB of the
|
|
15
|
+
* 136 KB font program in 55906-MultiSheetRefs.xlsx. `OS/2` is kept because
|
|
16
|
+
* viewers read its metrics when a descriptor is incomplete.
|
|
17
|
+
*/
|
|
18
|
+
var EMBEDDABLE_TABLES = new Set([
|
|
19
|
+
"glyf",
|
|
20
|
+
"head",
|
|
21
|
+
"hhea",
|
|
22
|
+
"hmtx",
|
|
23
|
+
"loca",
|
|
24
|
+
"maxp",
|
|
25
|
+
"cvt ",
|
|
26
|
+
"fpgm",
|
|
27
|
+
"prep",
|
|
28
|
+
"OS/2"
|
|
29
|
+
]);
|
|
5
30
|
var COMPOSITE_ARG_1_AND_2_ARE_WORDS = 1;
|
|
6
31
|
var COMPOSITE_WE_HAVE_A_SCALE = 8;
|
|
7
32
|
var COMPOSITE_MORE_COMPONENTS = 32;
|
|
@@ -115,7 +140,7 @@ function assembleSubsetTtf(parsed, newGlyf, newLoca) {
|
|
|
115
140
|
newHead[HEAD_CHECKSUM_ADJUSTMENT_OFFSET + 3] = 0;
|
|
116
141
|
newHead[HEAD_INDEX_TO_LOC_FORMAT_OFFSET] = 0;
|
|
117
142
|
newHead[HEAD_INDEX_TO_LOC_FORMAT_OFFSET + 1] = 1;
|
|
118
|
-
const orderedTags = [...parsed.tables.keys()];
|
|
143
|
+
const orderedTags = [...parsed.tables.keys()].filter((t) => EMBEDDABLE_TABLES.has(t));
|
|
119
144
|
const tableData = /* @__PURE__ */ new Map();
|
|
120
145
|
for (const tag of orderedTags) if (tag === "glyf") tableData.set(tag, newGlyf);
|
|
121
146
|
else if (tag === "loca") tableData.set(tag, newLocaBytes);
|
package/dist/esm/core/images.js
CHANGED
|
@@ -146,6 +146,8 @@ function decodePng(bytes) {
|
|
|
146
146
|
let bitDepth = 0;
|
|
147
147
|
let colorType = 0;
|
|
148
148
|
let interlaceMethod = 0;
|
|
149
|
+
let palette;
|
|
150
|
+
let paletteAlpha;
|
|
149
151
|
const idatChunks = [];
|
|
150
152
|
let pos = 8;
|
|
151
153
|
while (pos + 12 <= bytes.length) {
|
|
@@ -158,57 +160,161 @@ function decodePng(bytes) {
|
|
|
158
160
|
bitDepth = bytes[dataOff + 8];
|
|
159
161
|
colorType = bytes[dataOff + 9];
|
|
160
162
|
interlaceMethod = bytes[dataOff + 12];
|
|
161
|
-
} else if (type === "
|
|
163
|
+
} else if (type === "PLTE") palette = bytes.subarray(dataOff, dataOff + len);
|
|
164
|
+
else if (type === "tRNS") paletteAlpha = bytes.subarray(dataOff, dataOff + len);
|
|
165
|
+
else if (type === "IDAT") idatChunks.push(bytes.subarray(dataOff, dataOff + len));
|
|
162
166
|
else if (type === "IEND") break;
|
|
163
167
|
pos = dataOff + len + 4;
|
|
164
168
|
}
|
|
165
169
|
if (width === 0 || height === 0) throw new Error("PNG: missing IHDR");
|
|
166
170
|
if (idatChunks.length === 0) throw new Error("PNG: no IDAT");
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
|
|
171
|
+
if (![
|
|
172
|
+
1,
|
|
173
|
+
2,
|
|
174
|
+
4,
|
|
175
|
+
8,
|
|
176
|
+
16
|
|
177
|
+
].includes(bitDepth)) throw new Error(`PNG: bit depth ${bitDepth} not supported`);
|
|
170
178
|
const channels = pngChannels(colorType);
|
|
171
179
|
if (channels === 0) throw new Error(`PNG color type ${colorType} not supported`);
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
180
|
+
const raw = decodeSamples(unzlibSync(concatBytes(idatChunks)), width, height, channels, bitDepth, interlaceMethod === 1, colorType !== 3);
|
|
181
|
+
return splitChannels(width, height, colorType, raw, palette, paletteAlpha);
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* §7.2 / §9 — the image's samples, one byte each, in `width × height ×
|
|
185
|
+
* channels` order: the IDAT stream inflated, each scanline unfiltered against
|
|
186
|
+
* the one before it, and (when the image is interlaced) each of Adam7's seven
|
|
187
|
+
* passes scattered back into the full-size grid.
|
|
188
|
+
*
|
|
189
|
+
* @param inflated The inflated IDAT stream.
|
|
190
|
+
* @param width Image width in pixels.
|
|
191
|
+
* @param height Image height in pixels.
|
|
192
|
+
* @param channels Samples per pixel for the colour type.
|
|
193
|
+
* @param bitDepth Bits per sample (1, 2, 4, 8 or 16).
|
|
194
|
+
* @param interlaced True for interlace method 1 (Adam7).
|
|
195
|
+
* @param scaleToByte Stretch a sub-byte sample to 0…255 — right for an
|
|
196
|
+
* intensity, wrong for a palette index.
|
|
197
|
+
* @returns One byte per sample.
|
|
198
|
+
*/
|
|
199
|
+
function decodeSamples(inflated, width, height, channels, bitDepth, interlaced, scaleToByte) {
|
|
200
|
+
const out = new Uint8Array(width * height * channels);
|
|
201
|
+
const passes = interlaced ? ADAM7_PASSES : [{
|
|
202
|
+
xStart: 0,
|
|
203
|
+
yStart: 0,
|
|
204
|
+
xStep: 1,
|
|
205
|
+
yStep: 1
|
|
206
|
+
}];
|
|
207
|
+
const maxSample = (1 << Math.min(bitDepth, 8)) - 1;
|
|
208
|
+
const bpp = Math.max(1, Math.ceil(channels * bitDepth / 8));
|
|
209
|
+
let off = 0;
|
|
210
|
+
for (const p of passes) {
|
|
211
|
+
const pw = Math.ceil((width - p.xStart) / p.xStep);
|
|
212
|
+
const ph = Math.ceil((height - p.yStart) / p.yStep);
|
|
213
|
+
if (pw <= 0 || ph <= 0) continue;
|
|
214
|
+
const lineBytes = Math.ceil(pw * channels * bitDepth / 8);
|
|
215
|
+
let prev = null;
|
|
216
|
+
for (let y = 0; y < ph; y++) {
|
|
217
|
+
if (off + 1 + lineBytes > inflated.length) throw new Error("PNG: truncated image data");
|
|
218
|
+
const filterType = inflated[off];
|
|
219
|
+
const line = unfilterScanline(inflated, off + 1, lineBytes, bpp, filterType, prev);
|
|
220
|
+
off += 1 + lineBytes;
|
|
221
|
+
const destY = p.yStart + y * p.yStep;
|
|
222
|
+
for (let px = 0; px < pw; px++) {
|
|
223
|
+
const destX = p.xStart + px * p.xStep;
|
|
224
|
+
const dest = (destY * width + destX) * channels;
|
|
225
|
+
for (let ch = 0; ch < channels; ch++) {
|
|
226
|
+
const v = sampleAt(line, px * channels + ch, bitDepth);
|
|
227
|
+
out[dest + ch] = scaleToByte && bitDepth < 8 ? Math.round(v * 255 / maxSample) : v;
|
|
228
|
+
}
|
|
205
229
|
}
|
|
206
|
-
|
|
230
|
+
prev = line;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return out;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* §9.2 — Adam7's seven passes, each a sub-grid of the image: where the pass
|
|
237
|
+
* starts and how far apart its pixels sit.
|
|
238
|
+
*/
|
|
239
|
+
var ADAM7_PASSES = [
|
|
240
|
+
{
|
|
241
|
+
xStart: 0,
|
|
242
|
+
yStart: 0,
|
|
243
|
+
xStep: 8,
|
|
244
|
+
yStep: 8
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
xStart: 4,
|
|
248
|
+
yStart: 0,
|
|
249
|
+
xStep: 8,
|
|
250
|
+
yStep: 8
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
xStart: 0,
|
|
254
|
+
yStart: 4,
|
|
255
|
+
xStep: 4,
|
|
256
|
+
yStep: 8
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
xStart: 2,
|
|
260
|
+
yStart: 0,
|
|
261
|
+
xStep: 4,
|
|
262
|
+
yStep: 4
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
xStart: 0,
|
|
266
|
+
yStart: 2,
|
|
267
|
+
xStep: 2,
|
|
268
|
+
yStep: 4
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
xStart: 1,
|
|
272
|
+
yStart: 0,
|
|
273
|
+
xStep: 2,
|
|
274
|
+
yStep: 2
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
xStart: 0,
|
|
278
|
+
yStart: 1,
|
|
279
|
+
xStep: 1,
|
|
280
|
+
yStep: 2
|
|
281
|
+
}
|
|
282
|
+
];
|
|
283
|
+
function unfilterScanline(src, from, lineBytes, bpp, filterType, prev) {
|
|
284
|
+
const decoded = new Uint8Array(lineBytes);
|
|
285
|
+
for (let x = 0; x < lineBytes; x++) {
|
|
286
|
+
const filt = src[from + x];
|
|
287
|
+
const a = x < bpp ? 0 : decoded[x - bpp];
|
|
288
|
+
const b = prev ? prev[x] : 0;
|
|
289
|
+
const c = !prev || x < bpp ? 0 : prev[x - bpp];
|
|
290
|
+
let v;
|
|
291
|
+
switch (filterType) {
|
|
292
|
+
case 0:
|
|
293
|
+
v = filt;
|
|
294
|
+
break;
|
|
295
|
+
case 1:
|
|
296
|
+
v = filt + a;
|
|
297
|
+
break;
|
|
298
|
+
case 2:
|
|
299
|
+
v = filt + b;
|
|
300
|
+
break;
|
|
301
|
+
case 3:
|
|
302
|
+
v = filt + Math.floor((a + b) / 2);
|
|
303
|
+
break;
|
|
304
|
+
case 4:
|
|
305
|
+
v = filt + paethPredictor(a, b, c);
|
|
306
|
+
break;
|
|
307
|
+
default: throw new Error(`PNG: unknown filter type ${filterType}`);
|
|
207
308
|
}
|
|
208
|
-
|
|
209
|
-
prev = decoded;
|
|
309
|
+
decoded[x] = v & 255;
|
|
210
310
|
}
|
|
211
|
-
return
|
|
311
|
+
return decoded;
|
|
312
|
+
}
|
|
313
|
+
function sampleAt(line, i, bitDepth) {
|
|
314
|
+
if (bitDepth === 8) return line[i];
|
|
315
|
+
if (bitDepth === 16) return line[i * 2];
|
|
316
|
+
const per = 8 / bitDepth;
|
|
317
|
+
return (line[Math.floor(i / per)] ?? 0) >> 8 - bitDepth * (i % per + 1) & (1 << bitDepth) - 1;
|
|
212
318
|
}
|
|
213
319
|
function flattenAlphaOnWhite(decoded) {
|
|
214
320
|
const alpha = decoded.smaskRaw;
|
|
@@ -231,7 +337,7 @@ function flattenAlphaOnWhite(decoded) {
|
|
|
231
337
|
bitsPerComponent: decoded.bitsPerComponent
|
|
232
338
|
};
|
|
233
339
|
}
|
|
234
|
-
function splitChannels(width, height, colorType, raw) {
|
|
340
|
+
function splitChannels(width, height, colorType, raw, palette, paletteAlpha) {
|
|
235
341
|
const pixelCount = width * height;
|
|
236
342
|
if (colorType === 0) return {
|
|
237
343
|
width,
|
|
@@ -240,6 +346,28 @@ function splitChannels(width, height, colorType, raw) {
|
|
|
240
346
|
colorSpace: "DeviceGray",
|
|
241
347
|
bitsPerComponent: 8
|
|
242
348
|
};
|
|
349
|
+
if (colorType === 3) {
|
|
350
|
+
if (!palette || palette.length < 3) throw new Error("PNG: palette image without PLTE");
|
|
351
|
+
const entries = Math.floor(palette.length / 3);
|
|
352
|
+
const rgb = new Uint8Array(pixelCount * 3);
|
|
353
|
+
const alpha = paletteAlpha && paletteAlpha.length > 0 ? new Uint8Array(pixelCount) : void 0;
|
|
354
|
+
for (let i = 0; i < pixelCount; i++) {
|
|
355
|
+
const idx = raw[i];
|
|
356
|
+
const src = (idx < entries ? idx : 0) * 3;
|
|
357
|
+
rgb[i * 3] = palette[src];
|
|
358
|
+
rgb[i * 3 + 1] = palette[src + 1];
|
|
359
|
+
rgb[i * 3 + 2] = palette[src + 2];
|
|
360
|
+
if (alpha) alpha[i] = paletteAlpha[idx] ?? 255;
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
width,
|
|
364
|
+
height,
|
|
365
|
+
raw: rgb,
|
|
366
|
+
colorSpace: "DeviceRGB",
|
|
367
|
+
bitsPerComponent: 8,
|
|
368
|
+
...alpha ? { smaskRaw: alpha } : {}
|
|
369
|
+
};
|
|
370
|
+
}
|
|
243
371
|
if (colorType === 2) return {
|
|
244
372
|
width,
|
|
245
373
|
height,
|
|
@@ -281,11 +409,12 @@ function splitChannels(width, height, colorType, raw) {
|
|
|
281
409
|
smaskRaw: alpha
|
|
282
410
|
};
|
|
283
411
|
}
|
|
284
|
-
throw new Error(`PNG color type ${colorType} not supported
|
|
412
|
+
throw new Error(`PNG color type ${colorType} not supported`);
|
|
285
413
|
}
|
|
286
414
|
function pngChannels(colorType) {
|
|
287
415
|
if (colorType === 0) return 1;
|
|
288
416
|
if (colorType === 2) return 3;
|
|
417
|
+
if (colorType === 3) return 1;
|
|
289
418
|
if (colorType === 4) return 2;
|
|
290
419
|
if (colorType === 6) return 4;
|
|
291
420
|
return 0;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ECMA-376 §18.8.27 — the legacy indexed colour palette a `<color indexed="N">`
|
|
3
|
+
* refers to. It predates `rgb` and theme colours and is still what Excel writes
|
|
4
|
+
* for anything picked from the classic 40-colour dropdown, so a file using it
|
|
5
|
+
* is not unusual: tdf58243.xlsx colours its header cells `indexed="10"`, and
|
|
6
|
+
* ignoring the attribute rendered them black where every other reader shows red.
|
|
7
|
+
*
|
|
8
|
+
* Entries 0-7 are repeated at 8-15 (a quirk of the original palette); 64 and 65
|
|
9
|
+
* are the system foreground and background.
|
|
10
|
+
*/
|
|
11
|
+
export declare const INDEXED_COLORS: ReadonlyArray<string>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
//#region src/core/indexed-colors.ts
|
|
2
|
+
/**
|
|
3
|
+
* ECMA-376 §18.8.27 — the legacy indexed colour palette a `<color indexed="N">`
|
|
4
|
+
* refers to. It predates `rgb` and theme colours and is still what Excel writes
|
|
5
|
+
* for anything picked from the classic 40-colour dropdown, so a file using it
|
|
6
|
+
* is not unusual: tdf58243.xlsx colours its header cells `indexed="10"`, and
|
|
7
|
+
* ignoring the attribute rendered them black where every other reader shows red.
|
|
8
|
+
*
|
|
9
|
+
* Entries 0-7 are repeated at 8-15 (a quirk of the original palette); 64 and 65
|
|
10
|
+
* are the system foreground and background.
|
|
11
|
+
*/
|
|
12
|
+
var INDEXED_COLORS = [
|
|
13
|
+
"000000",
|
|
14
|
+
"FFFFFF",
|
|
15
|
+
"FF0000",
|
|
16
|
+
"00FF00",
|
|
17
|
+
"0000FF",
|
|
18
|
+
"FFFF00",
|
|
19
|
+
"FF00FF",
|
|
20
|
+
"00FFFF",
|
|
21
|
+
"000000",
|
|
22
|
+
"FFFFFF",
|
|
23
|
+
"FF0000",
|
|
24
|
+
"00FF00",
|
|
25
|
+
"0000FF",
|
|
26
|
+
"FFFF00",
|
|
27
|
+
"FF00FF",
|
|
28
|
+
"00FFFF",
|
|
29
|
+
"800000",
|
|
30
|
+
"008000",
|
|
31
|
+
"000080",
|
|
32
|
+
"808000",
|
|
33
|
+
"800080",
|
|
34
|
+
"008080",
|
|
35
|
+
"C0C0C0",
|
|
36
|
+
"808080",
|
|
37
|
+
"9999FF",
|
|
38
|
+
"993366",
|
|
39
|
+
"FFFFCC",
|
|
40
|
+
"CCFFFF",
|
|
41
|
+
"660066",
|
|
42
|
+
"FF8080",
|
|
43
|
+
"0066CC",
|
|
44
|
+
"CCCCFF",
|
|
45
|
+
"000080",
|
|
46
|
+
"FF00FF",
|
|
47
|
+
"FFFF00",
|
|
48
|
+
"00FFFF",
|
|
49
|
+
"800080",
|
|
50
|
+
"800000",
|
|
51
|
+
"008080",
|
|
52
|
+
"0000FF",
|
|
53
|
+
"00CCFF",
|
|
54
|
+
"CCFFFF",
|
|
55
|
+
"CCFFCC",
|
|
56
|
+
"FFFF99",
|
|
57
|
+
"99CCFF",
|
|
58
|
+
"FF99CC",
|
|
59
|
+
"CC99FF",
|
|
60
|
+
"FFCC99",
|
|
61
|
+
"3366FF",
|
|
62
|
+
"33CCCC",
|
|
63
|
+
"99CC00",
|
|
64
|
+
"FFCC00",
|
|
65
|
+
"FF9900",
|
|
66
|
+
"FF6600",
|
|
67
|
+
"666699",
|
|
68
|
+
"969696",
|
|
69
|
+
"003366",
|
|
70
|
+
"339966",
|
|
71
|
+
"003300",
|
|
72
|
+
"333300",
|
|
73
|
+
"993300",
|
|
74
|
+
"993366",
|
|
75
|
+
"333399",
|
|
76
|
+
"333333",
|
|
77
|
+
"000000",
|
|
78
|
+
"FFFFFF"
|
|
79
|
+
];
|
|
80
|
+
//#endregion
|
|
81
|
+
export { INDEXED_COLORS };
|
|
@@ -10,6 +10,9 @@ export interface SheetChartRef {
|
|
|
10
10
|
readonly chartPartPath: string;
|
|
11
11
|
readonly widthPt: number;
|
|
12
12
|
readonly heightPt: number;
|
|
13
|
+
/** Where the anchor puts it, in points from the grid's top-left. */
|
|
14
|
+
readonly xPt?: number;
|
|
15
|
+
readonly yPt?: number;
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* §20.5.2.1 xdr:pic — a picture anchored over a sheet's grid, sized from its
|
|
@@ -20,6 +23,9 @@ export interface SheetImageRef {
|
|
|
20
23
|
readonly resourceId: ResourceId;
|
|
21
24
|
readonly widthPt: number;
|
|
22
25
|
readonly heightPt: number;
|
|
26
|
+
/** Where the anchor puts it, in points from the grid's top-left. */
|
|
27
|
+
readonly xPt?: number;
|
|
28
|
+
readonly yPt?: number;
|
|
23
29
|
}
|
|
24
30
|
/** One item (label + selection state) in a {@link SheetSlicer}. */
|
|
25
31
|
export interface SheetSlicerItem {
|
|
@@ -73,10 +79,38 @@ export interface SheetComment {
|
|
|
73
79
|
* spin/scroll/list controls. Render-only.
|
|
74
80
|
*/
|
|
75
81
|
export interface SheetFormControl {
|
|
82
|
+
/**
|
|
83
|
+
* §18.3.1.19 `<control name>` — the shape's NAME, an identifier like
|
|
84
|
+
* "CheckBox28". Excel shows it in the name box, never on the page; it is what
|
|
85
|
+
* the after-the-grid listing calls a control that has no geometry.
|
|
86
|
+
*/
|
|
76
87
|
readonly name?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The visible label, from the control's legacy VML `<v:textbox>`. A control
|
|
90
|
+
* drawn in place draws THIS beside its widget — never {@link name}, which is
|
|
91
|
+
* an internal id: 45540_form_Header.xlsx has forty captionless check boxes
|
|
92
|
+
* and printing their names put "CheckBox28" across the form's own text.
|
|
93
|
+
*/
|
|
94
|
+
readonly caption?: string;
|
|
77
95
|
readonly objectType?: string;
|
|
78
96
|
readonly checked?: boolean;
|
|
79
97
|
readonly value?: number;
|
|
98
|
+
/** Where the control sits on the sheet, in points from the grid's origin. */
|
|
99
|
+
readonly box?: SheetControlBox;
|
|
100
|
+
/** The caption's declared size, when the shape names one. */
|
|
101
|
+
readonly fontSizePt?: number;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A control's rectangle on the sheet, in points from the grid's top-left — read
|
|
105
|
+
* from its legacy VML shape, the only part that says where a control goes.
|
|
106
|
+
* Absent when the drawing carries no geometry, in which case the control is
|
|
107
|
+
* listed after the grid rather than drawn in place.
|
|
108
|
+
*/
|
|
109
|
+
export interface SheetControlBox {
|
|
110
|
+
readonly xPt: number;
|
|
111
|
+
readonly yPt: number;
|
|
112
|
+
readonly widthPt: number;
|
|
113
|
+
readonly heightPt: number;
|
|
80
114
|
}
|
|
81
115
|
/**
|
|
82
116
|
* An ActiveX control resolved against its activeX part (E-SHEET W10): the control
|
|
@@ -87,6 +121,8 @@ export interface SheetFormControl {
|
|
|
87
121
|
*/
|
|
88
122
|
export interface SheetActiveXControl {
|
|
89
123
|
readonly type: string;
|
|
124
|
+
/** Where the control sits on the sheet — from the VML shape sharing its `shapeId`. */
|
|
125
|
+
readonly box?: SheetControlBox;
|
|
90
126
|
/** §18.3.1.19 `<control name>` — the control's identifier, when it came that way. */
|
|
91
127
|
readonly name?: string;
|
|
92
128
|
readonly caption?: string;
|
|
@@ -97,6 +133,12 @@ export interface SheetActiveXControl {
|
|
|
97
133
|
export interface Sheet {
|
|
98
134
|
/** The sheet (tab) name. */
|
|
99
135
|
readonly name: string;
|
|
136
|
+
/**
|
|
137
|
+
* §18.2.19 `<sheet @state>` — the tab is `hidden` or `veryHidden`. Carried
|
|
138
|
+
* because a consumer that shows the workbook (the HTML writer) may still want
|
|
139
|
+
* it; the paginated projection skips it, as Excel and LibreOffice do.
|
|
140
|
+
*/
|
|
141
|
+
readonly hidden?: boolean;
|
|
100
142
|
/**
|
|
101
143
|
* The grid + per-sheet geometry exactly as parsed: cells, columns, rows,
|
|
102
144
|
* merges, dimensions, pageSetup/printOptions, manual breaks, drawingRelId.
|
|
@@ -165,4 +207,23 @@ export interface SheetDoc {
|
|
|
165
207
|
readonly resources: ResourceStore;
|
|
166
208
|
/** Document metadata from docProps/core.xml. */
|
|
167
209
|
readonly info?: DocumentInfo;
|
|
210
|
+
/**
|
|
211
|
+
* §20.1.6.2 the workbook theme's colour scheme, slot name → 6-hex. Cell
|
|
212
|
+
* colours are resolved against it at parse time; a header/footer's `&K` theme
|
|
213
|
+
* reference is resolved at projection time, which is why the palette travels.
|
|
214
|
+
*/
|
|
215
|
+
readonly themePalette?: ReadonlyMap<string, string>;
|
|
216
|
+
/**
|
|
217
|
+
* §18.3.* — how many embedded objects (`<oleObject progId="Package">` and the
|
|
218
|
+
* like) the workbook carries. They print as an icon and a caption in Excel
|
|
219
|
+
* and Calc, both of which live in a metafile; the projection reports them.
|
|
220
|
+
*/
|
|
221
|
+
readonly embeddedObjects?: number;
|
|
222
|
+
/**
|
|
223
|
+
* §20.5.2.x — how many anchored pictures are a metafile (WMF / EMF / PICT)
|
|
224
|
+
* rather than a raster. They keep their anchor and their box, and draw
|
|
225
|
+
* nothing: replaying a metafile is a different feature from embedding an
|
|
226
|
+
* image. The projection reports them.
|
|
227
|
+
*/
|
|
228
|
+
readonly metafilePictures?: number;
|
|
168
229
|
}
|
|
@@ -13,6 +13,20 @@
|
|
|
13
13
|
* @returns The formatted display string.
|
|
14
14
|
*/
|
|
15
15
|
export declare function applyNumberFormat(rawValue: string, numFmtId: number, customFormats: ReadonlyMap<number, string>, date1904?: boolean): string;
|
|
16
|
+
/**
|
|
17
|
+
* The colour a number format paints its cell in (§18.8.31), as a 6-digit RRGGBB,
|
|
18
|
+
* or undefined when the section that applies declares none.
|
|
19
|
+
*
|
|
20
|
+
* A `[Red]` at the head of a section is part of the format, not decoration: the
|
|
21
|
+
* accounting codes write the negative section as `[Red]-#,##0.00`, and rendering
|
|
22
|
+
* it in the cell's own font colour loses the one signal the format exists for.
|
|
23
|
+
* `[Color 12]` indexes the same legacy palette a `<color indexed>` does.
|
|
24
|
+
*
|
|
25
|
+
* @param rawValue The cell's raw stored value — it selects the section.
|
|
26
|
+
* @param numFmtId The number-format id from the cell's `cellXf`.
|
|
27
|
+
* @param customFormats Custom format codes by id (from `<numFmts>`).
|
|
28
|
+
*/
|
|
29
|
+
export declare function numberFormatColorHex(rawValue: string, numFmtId: number, customFormats: ReadonlyMap<number, string>): string | undefined;
|
|
16
30
|
/**
|
|
17
31
|
* Excel serial date → JS `Date`. The default 1900 epoch uses 1899-12-30 as day 0
|
|
18
32
|
* (so serial 1 is 1900-01-01) and inherits the Lotus 1-2-3 leap-year bug: serial 60
|
|
@@ -35,3 +49,26 @@ export declare function excelSerialToDate(serial: number, date1904: boolean): Da
|
|
|
35
49
|
* @param month0 The 0-indexed month (0 = January).
|
|
36
50
|
*/
|
|
37
51
|
export declare function excelSerialFromUtcParts(year: number, month0: number, day: number, date1904: boolean): number;
|
|
52
|
+
/**
|
|
53
|
+
* A General number rounded to the decimals that fit `maxChars` characters.
|
|
54
|
+
*
|
|
55
|
+
* General is not a fixed format: a spreadsheet shows as many decimal places as
|
|
56
|
+
* the column has room for and ROUNDS to that, so 4.3900875881221957 in a
|
|
57
|
+
* column eight characters wide reads 4.390088. We rendered every stored digit
|
|
58
|
+
* and let the cell clip it, which turns the same value into 4.390087 — off by
|
|
59
|
+
* one in the last place shown, with nothing to say a digit was cut.
|
|
60
|
+
*
|
|
61
|
+
* The integer part is never dropped: a number too wide even without decimals
|
|
62
|
+
* keeps them all and the cell says so its own way (see hashOnOverflow).
|
|
63
|
+
*
|
|
64
|
+
* `fits` decides, and it must measure in the face this will be DRAWN in rather
|
|
65
|
+
* than count characters against the column's width in the document's unit.
|
|
66
|
+
* Counted that way we produced nine digits for a column that holds nine of
|
|
67
|
+
* Excel's and eight of ours, and the layout clipped the ninth — the very
|
|
68
|
+
* truncation this exists to prevent. Fewer digits than the reference shows is a
|
|
69
|
+
* coarser number; a clipped one is a different number.
|
|
70
|
+
*
|
|
71
|
+
* @param rawValue The cell's stored value.
|
|
72
|
+
* @param fits Whether a rendering will fit the cell.
|
|
73
|
+
*/
|
|
74
|
+
export declare function generalToWidth(rawValue: string, fits: (text: string) => boolean): string;
|