reamkit 1.2.0 → 1.3.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.
Files changed (37) hide show
  1. package/README.md +3 -2
  2. package/dist/esm/core/converter/ream.js +4 -3
  3. package/dist/esm/core/document-model/types.d.ts +2 -0
  4. package/dist/esm/core/drawingml/chart-geometry.d.ts +1 -1
  5. package/dist/esm/core/drawingml/chart-geometry.js +79 -117
  6. package/dist/esm/core/drawingml/chart-parser.d.ts +3 -0
  7. package/dist/esm/core/drawingml/chart-parser.js +28 -1
  8. package/dist/esm/core/numbering/apply.js +2 -1
  9. package/dist/esm/core/opc/index.d.ts +1 -0
  10. package/dist/esm/core/opc/package.js +3 -2
  11. package/dist/esm/core/opc/relationship-types.d.ts +1 -0
  12. package/dist/esm/core/opc/relationship-types.js +5 -2
  13. package/dist/esm/excel/print-model.d.ts +3 -0
  14. package/dist/esm/excel/print-model.js +4 -8
  15. package/dist/esm/excel/sheet-drawing.d.ts +9 -0
  16. package/dist/esm/excel/sheet-drawing.js +113 -0
  17. package/dist/esm/excel/worksheet-parser.d.ts +1 -0
  18. package/dist/esm/excel/worksheet-parser.js +4 -1
  19. package/dist/esm/excel/xlsx-reader.js +41 -0
  20. package/dist/esm/excel/xlsx-to-pdf.js +25 -18
  21. package/dist/esm/index.d.ts +1 -0
  22. package/dist/esm/layout/page-doc.d.ts +1 -0
  23. package/dist/esm/layout/styled-layout.d.ts +2 -0
  24. package/dist/esm/layout/styled-layout.js +321 -171
  25. package/dist/esm/pdf/encryption.d.ts +34 -0
  26. package/dist/esm/pdf/encryption.js +143 -0
  27. package/dist/esm/pdf/index.d.ts +2 -1
  28. package/dist/esm/pdf/styled-page-emitter.d.ts +2 -0
  29. package/dist/esm/pdf/styled-page-emitter.js +25 -7
  30. package/dist/esm/pdf/styled-page-renderer.d.ts +1 -0
  31. package/dist/esm/pdf/styled-page-renderer.js +17 -2
  32. package/dist/esm/pdf/writer.d.ts +2 -0
  33. package/dist/esm/pdf/writer.js +6 -1
  34. package/dist/esm/word/document-parser.js +4 -0
  35. package/dist/esm/word/docx-reader.js +7 -11
  36. package/dist/esm/word/docx-to-pdf.js +23 -13
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -168,8 +168,9 @@ repeated titles, page breaks), DrawingML shapes and charts, OMML math,
168
168
  Type0+CIDFontType2 embedding with subsetting, Knuth-Plass line breaking,
169
169
  Liang hyphenation, OpenType ligatures/kerning + Arabic cursive joining,
170
170
  BiDi (UAX #9), hyperlinks (PDF link annotations + HTML anchors,
171
- scheme-allowlisted), tagged PDF, PDF/A-1/2/3 (a/b/u), digital signatures
172
- (PKCS#7/ECDSA/PAdES/RFC 3161), SVG page preview, flowed HTML export.
171
+ scheme-allowlisted), tagged PDF, PDF/A-1/2/3 (a/b/u), PDF/UA-1, AES-256
172
+ encryption, digital signatures (PKCS#7/ECDSA/PAdES/RFC 3161), SVG page
173
+ preview, flowed HTML export. Reads OOXML Transitional and Strict.
173
174
 
174
175
  See `handoff.md` for the full feature matrix and known limitations.
175
176
 
@@ -3,7 +3,7 @@ import { FontRegistry } from "../font/font-registry.js";
3
3
  import { ConversionLossError } from "../ir/loss.js";
4
4
  import { layoutStyledDocument } from "../../layout/styled-layout.js";
5
5
  import { signPdf } from "../../pdf/signature.js";
6
- import { renderStyledPdf } from "../../pdf/styled-page-renderer.js";
6
+ import { renderStyledPdf, renderStyledPdfEncrypted } from "../../pdf/styled-page-renderer.js";
7
7
  import "../../pdf/index.js";
8
8
  import { flowRenderOptions } from "./project.js";
9
9
  import { writeHtml } from "../../html/html-writer.js";
@@ -73,7 +73,7 @@ var Ream = class Ream {
73
73
  relationship: "Source",
74
74
  description: "Source document"
75
75
  });
76
- let pdf = renderStyledPdf(this.flow.body, {
76
+ const styled = {
77
77
  registry,
78
78
  ...registriesByFamily ? { registriesByFamily } : {},
79
79
  ...flowRenderOptions(this.flow),
@@ -81,7 +81,8 @@ var Ream = class Ream {
81
81
  ...attachments.length > 0 ? { attachments } : {},
82
82
  ...signature ? { signaturePlaceholder: signature } : {},
83
83
  ...renderOptions
84
- });
84
+ };
85
+ let pdf = styled.encrypt ? await renderStyledPdfEncrypted(this.flow.body, styled) : renderStyledPdf(this.flow.body, styled);
85
86
  if (signature) pdf = await signPdf(pdf, signature);
86
87
  this.enforceStrict(options, losses);
87
88
  return {
@@ -132,6 +132,7 @@ export interface Run {
132
132
  readonly footnoteRef?: string;
133
133
  readonly endnoteRef?: string;
134
134
  readonly noteNumber?: true;
135
+ readonly listMarker?: true;
135
136
  readonly inlineImage?: InlineImage;
136
137
  readonly math?: MathNode;
137
138
  readonly pageBreak?: boolean;
@@ -382,6 +383,7 @@ export interface Chart {
382
383
  readonly showValues?: boolean;
383
384
  readonly catAxisTitle?: string;
384
385
  readonly valAxisTitle?: string;
386
+ readonly seriesColorCycle?: ReadonlyArray<string>;
385
387
  }
386
388
  export interface ChartBlock {
387
389
  readonly float?: FloatAnchor;
@@ -48,7 +48,7 @@ export type MeasureText = (text: string, sizePt: number) => number;
48
48
  export declare const CHART_LABEL_PT = 9;
49
49
  export declare const CHART_TITLE_PT = 13;
50
50
  export declare const SERIES_COLORS: string[];
51
- export declare const seriesColor: (s: ChartSeries, i: number) => string;
51
+ export declare const seriesColor: (s: ChartSeries, i: number, cycle?: ReadonlyArray<string>) => string;
52
52
  export interface Scale {
53
53
  readonly min: number;
54
54
  readonly max: number;
@@ -10,7 +10,7 @@ var SERIES_COLORS = [
10
10
  "5B9BD5",
11
11
  "70AD47"
12
12
  ];
13
- var seriesColor = (s, i) => s.colorHex ?? SERIES_COLORS[i % SERIES_COLORS.length];
13
+ var seriesColor = (s, i, cycle) => s.colorHex ?? (cycle && cycle.length > 0 ? cycle[i % cycle.length] : SERIES_COLORS[i % SERIES_COLORS.length]);
14
14
  function niceNum(range, round) {
15
15
  const exp = Math.floor(Math.log10(range));
16
16
  const f = range / 10 ** exp;
@@ -40,6 +40,68 @@ var ticks = (s) => {
40
40
  for (let v = s.min; v <= s.max + 1e-9; v += s.step) out.push(Math.abs(v) < 1e-9 ? 0 : v);
41
41
  return out;
42
42
  };
43
+ function pushChartTitle(labels, chart, wPt, hPt) {
44
+ if (!chart.title) return;
45
+ labels.push({
46
+ text: chart.title,
47
+ x: wPt / 2,
48
+ y: hPt - 4 - 13,
49
+ sizePt: 13,
50
+ colorHex: TITLE_COLOR,
51
+ align: "center"
52
+ });
53
+ }
54
+ function buildLegendBlock(chart, wPt, hPt, measure) {
55
+ return layoutLegend(chart.series.map((s, i) => ({
56
+ name: s.name ?? "",
57
+ colorHex: seriesColor(s, i, chart.seriesColorCycle)
58
+ })).filter((e) => e.name !== ""), chart.hasLegend, chart.legendPos ?? "b", wPt, hPt, measure);
59
+ }
60
+ function pushGridTicks(polylines, labels, tickVals, fmt, axis, at, x0, y0, plotW, plotH) {
61
+ for (const v of tickVals) if (axis === "x") {
62
+ const gx = at(v);
63
+ polylines.push({
64
+ points: [[gx, y0], [gx, y0 + plotH]],
65
+ strokeHex: GRID_COLOR,
66
+ widthPt: .75
67
+ });
68
+ labels.push({
69
+ text: fmt(v),
70
+ x: gx,
71
+ y: y0 - 9,
72
+ sizePt: 9,
73
+ colorHex: LABEL_COLOR,
74
+ align: "center"
75
+ });
76
+ } else {
77
+ const gy = at(v);
78
+ polylines.push({
79
+ points: [[x0, gy], [x0 + plotW, gy]],
80
+ strokeHex: GRID_COLOR,
81
+ widthPt: .75
82
+ });
83
+ labels.push({
84
+ text: fmt(v),
85
+ x: x0 - 3,
86
+ y: gy - 9 / 3,
87
+ sizePt: 9,
88
+ colorHex: LABEL_COLOR,
89
+ align: "right"
90
+ });
91
+ }
92
+ }
93
+ function pushAxisLines(polylines, x0, y0, plotW, plotH) {
94
+ polylines.push({
95
+ points: [[x0, y0], [x0, y0 + plotH]],
96
+ strokeHex: AXIS_COLOR,
97
+ widthPt: 1
98
+ });
99
+ polylines.push({
100
+ points: [[x0, y0], [x0 + plotW, y0]],
101
+ strokeHex: AXIS_COLOR,
102
+ widthPt: 1
103
+ });
104
+ }
43
105
  function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
44
106
  const rects = [];
45
107
  const polylines = [];
@@ -53,10 +115,7 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
53
115
  let top = 4;
54
116
  if (chart.title) top += 13 * 1.6;
55
117
  if (chart.valAxisTitle) top += 9 * 1.4;
56
- const legend = layoutLegend(chart.series.map((s, i) => ({
57
- name: s.name ?? "",
58
- colorHex: seriesColor(s, i)
59
- })).filter((e) => e.name !== ""), chart.hasLegend, chart.legendPos ?? "b", wPt, hPt, measure);
118
+ const legend = buildLegendBlock(chart, wPt, hPt, measure);
60
119
  const plotRight = wPt - 4 - legend.rightWidth;
61
120
  const tickLabelW = Math.max(0, ...tickVals.map((v) => measure(fmtVal(v), 9))) + 4;
62
121
  const catLabelH = 9 * 1.6;
@@ -67,14 +126,7 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
67
126
  const plotH = Math.max(1, hPt - top - y0);
68
127
  const valueOffset = (v) => (v - scale.min) / (scale.max - scale.min) * (horizontal ? plotW : plotH);
69
128
  const zeroOffset = valueOffset(0);
70
- if (chart.title) labels.push({
71
- text: chart.title,
72
- x: wPt / 2,
73
- y: hPt - 4 - 13,
74
- sizePt: 13,
75
- colorHex: TITLE_COLOR,
76
- align: "center"
77
- });
129
+ pushChartTitle(labels, chart, wPt, hPt);
78
130
  if (chart.valAxisTitle) labels.push({
79
131
  text: chart.valAxisTitle,
80
132
  x: x0,
@@ -91,40 +143,8 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
91
143
  colorHex: LABEL_COLOR,
92
144
  align: "center"
93
145
  });
94
- for (const v of tickVals) {
95
- const off = valueOffset(v);
96
- if (horizontal) {
97
- const gx = x0 + off;
98
- polylines.push({
99
- points: [[gx, y0], [gx, y0 + plotH]],
100
- strokeHex: GRID_COLOR,
101
- widthPt: .75
102
- });
103
- labels.push({
104
- text: fmtVal(v),
105
- x: gx,
106
- y: y0 - 9,
107
- sizePt: 9,
108
- colorHex: LABEL_COLOR,
109
- align: "center"
110
- });
111
- } else {
112
- const gy = y0 + off;
113
- polylines.push({
114
- points: [[x0, gy], [x0 + plotW, gy]],
115
- strokeHex: GRID_COLOR,
116
- widthPt: .75
117
- });
118
- labels.push({
119
- text: fmtVal(v),
120
- x: x0 - 3,
121
- y: gy - 9 / 3,
122
- sizePt: 9,
123
- colorHex: LABEL_COLOR,
124
- align: "right"
125
- });
126
- }
127
- }
146
+ if (horizontal) pushGridTicks(polylines, labels, tickVals, fmtVal, "x", (v) => x0 + valueOffset(v), x0, y0, plotW, plotH);
147
+ else pushGridTicks(polylines, labels, tickVals, fmtVal, "y", (v) => y0 + valueOffset(v), x0, y0, plotW, plotH);
128
148
  const slot = (horizontal ? plotH : plotW) / nCats;
129
149
  for (let c = 0; c < nCats; c++) {
130
150
  const cat = chart.categories[c] ?? "";
@@ -147,16 +167,7 @@ function buildFrame(chart, wPt, hPt, measure, horizontal, opts = {}) {
147
167
  align: "center"
148
168
  });
149
169
  }
150
- polylines.push({
151
- points: [[x0, y0], [x0, y0 + plotH]],
152
- strokeHex: AXIS_COLOR,
153
- widthPt: 1
154
- });
155
- polylines.push({
156
- points: [[x0, y0], [x0 + plotW, y0]],
157
- strokeHex: AXIS_COLOR,
158
- widthPt: 1
159
- });
170
+ pushAxisLines(polylines, x0, y0, plotW, plotH);
160
171
  legend.emit(rects, labels);
161
172
  return {
162
173
  x0,
@@ -232,7 +243,7 @@ function buildBarScene(chart, wPt, hPt, measure) {
232
243
  const o1 = f.valueOffset(top);
233
244
  const lo = Math.min(o0, o1);
234
245
  const span = Math.abs(o1 - o0);
235
- const color = pointColor(series, c) ?? seriesColor(series, s);
246
+ const color = pointColor(series, c) ?? seriesColor(series, s, chart.seriesColorCycle);
236
247
  if (horizontal) f.rects.push({
237
248
  x: f.x0 + lo,
238
249
  y: along,
@@ -271,7 +282,7 @@ function buildBarScene(chart, wPt, hPt, measure) {
271
282
  for (let s = 0; s < chart.series.length; s++) {
272
283
  const series = chart.series[s];
273
284
  const len = f.valueOffset(series.values[c] ?? 0) - f.zeroOffset;
274
- const color = pointColor(series, c) ?? seriesColor(series, s);
285
+ const color = pointColor(series, c) ?? seriesColor(series, s, chart.seriesColorCycle);
275
286
  const along = slotStart + s * barW;
276
287
  if (horizontal) {
277
288
  const bx = f.x0 + f.zeroOffset + Math.min(0, len);
@@ -356,7 +367,7 @@ function buildAreaScene(chart, wPt, hPt, measure) {
356
367
  const denom = percent ? chart.series.reduce((a, ss) => a + Math.abs(ss.values[c] ?? 0), 0) || 1 : 1;
357
368
  return b + (series.values[c] ?? 0) / denom;
358
369
  });
359
- polygons.push(areaBand(top, base, f, xAt, seriesColor(series, s)));
370
+ polygons.push(areaBand(top, base, f, xAt, seriesColor(series, s, chart.seriesColorCycle)));
360
371
  for (let c = 0; c < nCats; c++) cum[c] = top[c];
361
372
  }
362
373
  } else {
@@ -364,7 +375,7 @@ function buildAreaScene(chart, wPt, hPt, measure) {
364
375
  for (let s = chart.series.length - 1; s >= 0; s--) {
365
376
  const series = chart.series[s];
366
377
  const top = Array.from({ length: nCats }, (_, c) => series.values[c] ?? 0);
367
- polygons.push(areaBand(top, base, f, xAt, seriesColor(series, s)));
378
+ polygons.push(areaBand(top, base, f, xAt, seriesColor(series, s, chart.seriesColorCycle)));
368
379
  }
369
380
  }
370
381
  return {
@@ -397,69 +408,20 @@ function buildScatterScene(chart, wPt, hPt, measure) {
397
408
  const yTicks = ticks(yScale);
398
409
  let top = 4;
399
410
  if (chart.title) top += 13 * 1.6;
400
- const legend = layoutLegend(chart.series.map((s, i) => ({
401
- name: s.name ?? "",
402
- colorHex: seriesColor(s, i)
403
- })).filter((e) => e.name !== ""), chart.hasLegend, chart.legendPos ?? "b", wPt, hPt, measure);
411
+ const legend = buildLegendBlock(chart, wPt, hPt, measure);
404
412
  const x0 = 4 + (Math.max(0, ...yTicks.map((v) => measure(formatTick(v, yScale.step), 9))) + 4);
405
413
  const y0 = 4 + legend.bottomHeight + 9 * 1.6;
406
414
  const plotW = Math.max(1, wPt - 4 - legend.rightWidth - x0);
407
415
  const plotH = Math.max(1, hPt - top - y0);
408
416
  const xAt = (v) => x0 + (v - xScale.min) / (xScale.max - xScale.min) * plotW;
409
417
  const yAt = (v) => y0 + (v - yScale.min) / (yScale.max - yScale.min) * plotH;
410
- if (chart.title) labels.push({
411
- text: chart.title,
412
- x: wPt / 2,
413
- y: hPt - 4 - 13,
414
- sizePt: 13,
415
- colorHex: TITLE_COLOR,
416
- align: "center"
417
- });
418
- for (const v of yTicks) {
419
- const gy = yAt(v);
420
- polylines.push({
421
- points: [[x0, gy], [x0 + plotW, gy]],
422
- strokeHex: GRID_COLOR,
423
- widthPt: .75
424
- });
425
- labels.push({
426
- text: formatTick(v, yScale.step),
427
- x: x0 - 3,
428
- y: gy - 9 / 3,
429
- sizePt: 9,
430
- colorHex: LABEL_COLOR,
431
- align: "right"
432
- });
433
- }
434
- for (const v of xTicks) {
435
- const gx = xAt(v);
436
- polylines.push({
437
- points: [[gx, y0], [gx, y0 + plotH]],
438
- strokeHex: GRID_COLOR,
439
- widthPt: .75
440
- });
441
- labels.push({
442
- text: formatTick(v, xScale.step),
443
- x: gx,
444
- y: y0 - 9,
445
- sizePt: 9,
446
- colorHex: LABEL_COLOR,
447
- align: "center"
448
- });
449
- }
450
- polylines.push({
451
- points: [[x0, y0], [x0, y0 + plotH]],
452
- strokeHex: AXIS_COLOR,
453
- widthPt: 1
454
- });
455
- polylines.push({
456
- points: [[x0, y0], [x0 + plotW, y0]],
457
- strokeHex: AXIS_COLOR,
458
- widthPt: 1
459
- });
418
+ pushChartTitle(labels, chart, wPt, hPt);
419
+ pushGridTicks(polylines, labels, yTicks, (v) => formatTick(v, yScale.step), "y", yAt, x0, y0, plotW, plotH);
420
+ pushGridTicks(polylines, labels, xTicks, (v) => formatTick(v, xScale.step), "x", xAt, x0, y0, plotW, plotH);
421
+ pushAxisLines(polylines, x0, y0, plotW, plotH);
460
422
  for (let s = 0; s < chart.series.length; s++) {
461
423
  const series = chart.series[s];
462
- const color = seriesColor(series, s);
424
+ const color = seriesColor(series, s, chart.seriesColorCycle);
463
425
  for (let i = 0; i < series.values.length; i++) {
464
426
  const px = xAt(series.xValues?.[i] ?? i);
465
427
  const py = yAt(series.values[i] ?? 0);
@@ -485,7 +447,7 @@ function buildLineScene(chart, wPt, hPt, measure) {
485
447
  const f = buildFrame(chart, wPt, hPt, measure, false, { dataRange: allVals.length > 0 ? [Math.min(...allVals), Math.max(...allVals)] : [0, 1] });
486
448
  for (let s = 0; s < chart.series.length; s++) {
487
449
  const series = chart.series[s];
488
- const color = seriesColor(series, s);
450
+ const color = seriesColor(series, s, chart.seriesColorCycle);
489
451
  const pts = [];
490
452
  for (let c = 0; c < f.nCats; c++) {
491
453
  const x = f.x0 + c * f.slot + f.slot / 2;
@@ -1,3 +1,6 @@
1
1
  import { Chart } from '../document-model/index.js';
2
+ import { OpcPackage } from '../opc/index.js';
2
3
  import { ColorResolver } from './colors.js';
3
4
  export declare function parseChart(chartXml: Uint8Array, resolveColor: ColorResolver): Chart | null;
5
+ export declare function parseChartColorStyle(colorsXml: Uint8Array, resolveColor: ColorResolver): Array<string>;
6
+ export declare function withChartColorStyle(chart: Chart, pkg: OpcPackage, chartPartPath: string, resolveColor: ColorResolver): Chart;
@@ -191,5 +191,32 @@ function isLegendPos(v) {
191
191
  function isGrouping(v) {
192
192
  return v === "clustered" || v === "stacked" || v === "percentStacked" || v === "standard";
193
193
  }
194
+ function parseChartColorStyle(colorsXml, resolveColor) {
195
+ const root = parser.parse(new TextDecoder().decode(colorsXml)).find((n) => {
196
+ const tag = Object.keys(n).find((k) => k !== ":@" && k !== "#text");
197
+ return tag !== void 0 && tag.endsWith("colorStyle");
198
+ });
199
+ if (!root) return [];
200
+ const out = [];
201
+ for (const child of poChildren(root)) {
202
+ const hex = resolveColorNode(child, resolveColor);
203
+ if (hex !== void 0) out.push(hex);
204
+ }
205
+ return out;
206
+ }
207
+ function withChartColorStyle(chart, pkg, chartPartPath, resolveColor) {
208
+ for (const rel of pkg.getPartRelationships(chartPartPath)) {
209
+ if (rel.type !== REL_CHART_COLOR_STYLE) continue;
210
+ const resolved = pkg.resolveRelatedPart(chartPartPath, rel);
211
+ if (!resolved) continue;
212
+ const cycle = parseChartColorStyle(resolved.data, resolveColor);
213
+ if (cycle.length > 0) return {
214
+ ...chart,
215
+ seriesColorCycle: cycle
216
+ };
217
+ }
218
+ return chart;
219
+ }
220
+ var REL_CHART_COLOR_STYLE = "http://schemas.microsoft.com/office/2011/relationships/chartColorStyle";
194
221
  //#endregion
195
- export { parseChart };
222
+ export { parseChart, withChartColorStyle };
@@ -12,7 +12,8 @@ function applyNumbering(body, numbering) {
12
12
  const level = (instance ? numbering.abstractNums.get(instance.abstractNumId) : void 0)?.levels.get(ref.ilvl);
13
13
  const markerRun = {
14
14
  text: `${marker}\t`,
15
- properties: level?.runProperties ?? {}
15
+ properties: level?.runProperties ?? {},
16
+ listMarker: true
16
17
  };
17
18
  const newProps = mergeIndentFromLevel(p.properties, level?.paragraphProperties);
18
19
  return {
@@ -3,3 +3,4 @@ export type { Relationship } from './relationships.js';
3
3
  export { REL_OFFICE_DOCUMENT, REL_CORE_PROPERTIES, REL_EXTENDED_PROPERTIES, } from './relationship-types.js';
4
4
  export { parseCoreProperties } from './core-properties.js';
5
5
  export type { CoreProperties } from './core-properties.js';
6
+ export { isOoxmlRel } from './relationship-types.js';
@@ -1,5 +1,5 @@
1
1
  import { parseRelationships } from "./relationships.js";
2
- import "./relationship-types.js";
2
+ import { isOoxmlRel } from "./relationship-types.js";
3
3
  import { unzipSync } from "fflate";
4
4
  //#region src/core/opc/package.ts
5
5
  var ROOT_RELS_PATH = "_rels/.rels";
@@ -11,6 +11,7 @@ var OpcPackage = class OpcPackage {
11
11
  }
12
12
  relsCache = /* @__PURE__ */ new Map();
13
13
  static open(buffer, options = {}) {
14
+ if (buffer.length >= 4 && buffer[0] === 208 && buffer[1] === 207 && buffer[2] === 17 && buffer[3] === 224) throw new Error("OLE compound file: a password-protected (encrypted) OOXML document or a legacy binary .doc/.xls — re-save as an unencrypted .docx/.xlsx");
14
15
  const maxArchive = options.maxArchiveBytes ?? 128 * MIB;
15
16
  const maxEntry = options.maxEntryBytes ?? 256 * MIB;
16
17
  const maxTotal = options.maxTotalBytes ?? 512 * MIB;
@@ -77,7 +78,7 @@ var OpcPackage = class OpcPackage {
77
78
  };
78
79
  }
79
80
  getMainDocumentPath() {
80
- const candidates = this.rootRelationships.filter((r) => r.type === "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" && r.targetMode === "Internal");
81
+ const candidates = this.rootRelationships.filter((r) => isOoxmlRel(r.type, "officeDocument") && r.targetMode === "Internal");
81
82
  if (candidates.length === 0) throw new Error("OPC package has no officeDocument relationship");
82
83
  if (candidates.length > 1) throw new Error(`OPC package has multiple officeDocument relationships (${candidates.length})`);
83
84
  return resolveTarget("/", candidates[0].target);
@@ -1,3 +1,4 @@
1
1
  export declare const REL_OFFICE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
2
2
  export declare const REL_CORE_PROPERTIES = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties";
3
3
  export declare const REL_EXTENDED_PROPERTIES = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties";
4
+ export declare function isOoxmlRel(type: string, name: string): boolean;
@@ -1,4 +1,7 @@
1
1
  //#region src/core/opc/relationship-types.ts
2
- var REL_OFFICE_DOCUMENT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
2
+ var OOXML_REL_BASES = ["http://schemas.openxmlformats.org/officeDocument/2006/relationships/", "http://purl.oclc.org/ooxml/officeDocument/relationships/"];
3
+ function isOoxmlRel(type, name) {
4
+ return OOXML_REL_BASES.some((base) => type === base + name);
5
+ }
3
6
  //#endregion
4
- export { REL_OFFICE_DOCUMENT };
7
+ export { isOoxmlRel };
@@ -1,5 +1,8 @@
1
1
  import { BodyElement, SectionProperties } from '../core/document-model/index.js';
2
2
  import { CellRange, DefinedName, ParsedWorksheet, XlsxStyles } from './index.js';
3
+ export declare const TWIPS_PER_EXCEL_CHAR = 105;
4
+ export declare const DEFAULT_COL_TWIPS = 960;
5
+ export declare const DEFAULT_ROW_TWIPS = 300;
3
6
  export declare function sectionFromWorksheet(worksheet: ParsedWorksheet): SectionProperties | undefined;
4
7
  export declare function resolvePrintArea(definedNames: ReadonlyArray<DefinedName>, sheetIdx: number): CellRange | undefined;
5
8
  export declare function resolvePrintTitleRows(definedNames: ReadonlyArray<DefinedName>, sheetIdx: number): {
@@ -2,10 +2,6 @@ import { eighthPtToPt, halfPtToPt, twipsToPt } from "../core/ir/units.js";
2
2
  import { parseAreaRef, parseTitleRowRange } from "./defined-name-ref.js";
3
3
  import { applyNumberFormat } from "./number-format.js";
4
4
  import "./index.js";
5
- //#region src/excel/print-model.ts
6
- var TWIPS_PER_EXCEL_CHAR = 105;
7
- var DEFAULT_COL_TWIPS = 960;
8
- var DEFAULT_ROW_TWIPS = 300;
9
5
  var TWIPS_PER_POINT = 20;
10
6
  var TWIPS_PER_INCH = 1440;
11
7
  var PAPER_SIZES_TWIPS = new Map([
@@ -154,9 +150,9 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
154
150
  const cEnd = Math.min(m.endColumn, colWindowEnd);
155
151
  for (let r = Math.max(m.startRow, rowStart); r <= rEnd; r++) for (let c = Math.max(m.startColumn, colStart); c <= cEnd; c++) if (!(r === m.startRow && c === m.startColumn)) insideMerge.add(key(r, c));
156
152
  }
157
- const columnWidths = new Array(colCount).fill(DEFAULT_COL_TWIPS);
153
+ const columnWidths = new Array(colCount).fill(960);
158
154
  for (const col of worksheet.columns) {
159
- const twips = Math.round(col.widthChars * TWIPS_PER_EXCEL_CHAR);
155
+ const twips = Math.round(col.widthChars * 105);
160
156
  for (let abs = col.min - 1; abs <= col.max - 1; abs++) {
161
157
  const i = abs - colStart;
162
158
  if (i >= 0 && i < colCount) columnWidths[i] = twips;
@@ -164,7 +160,7 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
164
160
  }
165
161
  const totalGridTwips = columnWidths.reduce((sum, w) => sum + w, 0);
166
162
  let totalGridHeightTwips = 0;
167
- for (let r = 0; r < rowCount; r++) totalGridHeightTwips += rowHeightMap.get(r)?.heightTwips ?? DEFAULT_ROW_TWIPS;
163
+ for (let r = 0; r < rowCount; r++) totalGridHeightTwips += rowHeightMap.get(r)?.heightTwips ?? 300;
168
164
  const printScale = computePrintScale(worksheet, totalGridTwips, sheetContentWidthTwips(worksheet), totalGridHeightTwips, sheetContentHeightTwips(worksheet));
169
165
  const scaled = printScale < .999;
170
166
  const breakRows = new Set(worksheet.rowBreaks ?? []);
@@ -217,7 +213,7 @@ function worksheetToBody(worksheet, sharedStrings, styles, date1904, print) {
217
213
  cc++;
218
214
  }
219
215
  if (cc < colCount) {
220
- const charsFit = Math.max(1, Math.round(availTwips / TWIPS_PER_EXCEL_CHAR));
216
+ const charsFit = Math.max(1, Math.round(availTwips / 105));
221
217
  if (text.length > charsFit) text = text.slice(0, charsFit);
222
218
  }
223
219
  }
@@ -0,0 +1,9 @@
1
+ import { OpcPackage } from '../core/opc/index.js';
2
+ import { ParsedWorksheet } from './worksheet-parser.js';
3
+ export interface SheetChartRef {
4
+ readonly chartPartPath: string;
5
+ readonly widthPt: number;
6
+ readonly heightPt: number;
7
+ readonly anchorRow: number;
8
+ }
9
+ export declare function parseSheetDrawing(drawingXml: Uint8Array, drawingPartPath: string, pkg: OpcPackage, worksheet: ParsedWorksheet): Array<SheetChartRef>;
@@ -0,0 +1,113 @@
1
+ import { emuToPt } from "../core/ir/units.js";
2
+ import "./print-model.js";
3
+ import { XMLParser } from "fast-xml-parser";
4
+ //#region src/excel/sheet-drawing.ts
5
+ var CHART_URI = "http://schemas.openxmlformats.org/drawingml/2006/chart";
6
+ var parser = new XMLParser({
7
+ ignoreAttributes: false,
8
+ attributeNamePrefix: "@_",
9
+ removeNSPrefix: true,
10
+ parseTagValue: false
11
+ });
12
+ var TWIPS_PER_PT = 20;
13
+ function parseSheetDrawing(drawingXml, drawingPartPath, pkg, worksheet) {
14
+ const root = parser.parse(new TextDecoder().decode(drawingXml))["wsDr"];
15
+ if (!root || typeof root !== "object") return [];
16
+ const rootObj = root;
17
+ const colWidthPt = makeColWidthPt(worksheet);
18
+ const rowHeightPt = makeRowHeightPt(worksheet);
19
+ const rels = pkg.getPartRelationships(drawingPartPath);
20
+ const out = [];
21
+ for (const kind of [
22
+ "twoCellAnchor",
23
+ "oneCellAnchor",
24
+ "absoluteAnchor"
25
+ ]) for (const anchor of asArray(rootObj[kind])) {
26
+ if (!anchor || typeof anchor !== "object") continue;
27
+ const a = anchor;
28
+ const chartRelId = chartRelIdOf(a);
29
+ if (!chartRelId) continue;
30
+ const rel = rels.find((r) => r.id === chartRelId);
31
+ const resolved = rel ? pkg.resolveRelatedPart(drawingPartPath, rel) : void 0;
32
+ if (!resolved) continue;
33
+ const from = cellMarker(a["from"]);
34
+ let widthPt = 0;
35
+ let heightPt = 0;
36
+ if (kind === "twoCellAnchor") {
37
+ const to = cellMarker(a["to"]);
38
+ if (!from || !to) continue;
39
+ widthPt = spanPt(from.col, from.colOffPt, to.col, to.colOffPt, colWidthPt);
40
+ heightPt = spanPt(from.row, from.rowOffPt, to.row, to.rowOffPt, rowHeightPt);
41
+ } else {
42
+ const ext = a["ext"];
43
+ if (!ext || typeof ext !== "object") continue;
44
+ const e = ext;
45
+ widthPt = emuToPt(num(e["@_cx"]) ?? 0);
46
+ heightPt = emuToPt(num(e["@_cy"]) ?? 0);
47
+ }
48
+ if (widthPt <= 0 || heightPt <= 0) continue;
49
+ out.push({
50
+ chartPartPath: resolved.path,
51
+ widthPt,
52
+ heightPt,
53
+ anchorRow: from?.row ?? 0
54
+ });
55
+ }
56
+ return out.sort((x, y) => x.anchorRow - y.anchorRow);
57
+ }
58
+ function chartRelIdOf(anchor) {
59
+ const frame = anchor["graphicFrame"];
60
+ if (!frame || typeof frame !== "object") return void 0;
61
+ const graphic = frame["graphic"];
62
+ if (!graphic || typeof graphic !== "object") return void 0;
63
+ const data = graphic["graphicData"];
64
+ if (!data || typeof data !== "object") return void 0;
65
+ const d = data;
66
+ if (d["@_uri"] !== CHART_URI) return void 0;
67
+ const chart = d["chart"];
68
+ if (!chart || typeof chart !== "object") return void 0;
69
+ const id = chart["@_id"];
70
+ return typeof id === "string" && id !== "" ? id : void 0;
71
+ }
72
+ function cellMarker(node) {
73
+ if (!node || typeof node !== "object") return void 0;
74
+ const m = node;
75
+ const col = num(m["col"]);
76
+ const row = num(m["row"]);
77
+ if (col === void 0 || row === void 0) return void 0;
78
+ return {
79
+ col,
80
+ row,
81
+ colOffPt: emuToPt(num(m["colOff"]) ?? 0),
82
+ rowOffPt: emuToPt(num(m["rowOff"]) ?? 0)
83
+ };
84
+ }
85
+ function spanPt(from, fromOffPt, to, toOffPt, trackPt) {
86
+ let span = 0;
87
+ for (let i = from; i < to; i++) span += trackPt(i);
88
+ return span - fromOffPt + toOffPt;
89
+ }
90
+ function makeColWidthPt(ws) {
91
+ return (col) => {
92
+ for (const c of ws.columns) if (col >= c.min - 1 && col <= c.max - 1) return c.widthChars * 105 / TWIPS_PER_PT;
93
+ return 960 / TWIPS_PER_PT;
94
+ };
95
+ }
96
+ function makeRowHeightPt(ws) {
97
+ return (row) => {
98
+ for (const r of ws.rowHeights) if (r.row === row) return r.heightPt;
99
+ return 300 / TWIPS_PER_PT;
100
+ };
101
+ }
102
+ function num(v) {
103
+ if (typeof v === "number" && Number.isFinite(v)) return v;
104
+ if (typeof v === "string" && v !== "") {
105
+ const n = Number(v);
106
+ if (Number.isFinite(n)) return n;
107
+ }
108
+ }
109
+ function asArray(v) {
110
+ return Array.isArray(v) ? v : v !== void 0 ? [v] : [];
111
+ }
112
+ //#endregion
113
+ export { parseSheetDrawing };
@@ -56,5 +56,6 @@ export interface ParsedWorksheet {
56
56
  readonly printOptions?: XlsxPrintOptions;
57
57
  readonly rowBreaks?: ReadonlyArray<number>;
58
58
  readonly colBreaks?: ReadonlyArray<number>;
59
+ readonly drawingRelId?: string;
59
60
  }
60
61
  export declare function parseWorksheet(data: Uint8Array): ParsedWorksheet;
@@ -32,13 +32,16 @@ function parseWorksheet(data) {
32
32
  const printOptions = parsePrintOptions(wsObj);
33
33
  const rowBreaks = parseBreaks(wsObj, "rowBreaks");
34
34
  const colBreaks = parseBreaks(wsObj, "colBreaks");
35
+ const drawingNode = wsObj["drawing"];
36
+ const drawingRelId = drawingNode && typeof drawingNode === "object" ? strAttr(drawingNode, "id") : void 0;
35
37
  const printModel = {
36
38
  ...pageMargins ? { pageMargins } : {},
37
39
  ...pageSetup ? { pageSetup } : {},
38
40
  ...fitToPage ? { fitToPage } : {},
39
41
  ...printOptions ? { printOptions } : {},
40
42
  ...rowBreaks.length > 0 ? { rowBreaks } : {},
41
- ...colBreaks.length > 0 ? { colBreaks } : {}
43
+ ...colBreaks.length > 0 ? { colBreaks } : {},
44
+ ...drawingRelId !== void 0 ? { drawingRelId } : {}
42
45
  };
43
46
  const sheetData = wsObj["sheetData"];
44
47
  if (!sheetData || typeof sheetData !== "object") return {