reamkit 1.1.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 (68) hide show
  1. package/README.md +11 -5
  2. package/dist/esm/{layout → core}/arc-to-bezier.d.ts +1 -1
  3. package/dist/esm/{layout → core}/arc-to-bezier.js +2 -2
  4. package/dist/esm/core/converter/project.js +2 -0
  5. package/dist/esm/core/converter/ream.js +4 -3
  6. package/dist/esm/core/document-model/index.d.ts +1 -1
  7. package/dist/esm/core/document-model/types.d.ts +60 -0
  8. package/dist/esm/{layout → core/drawingml}/chart-geometry.d.ts +2 -2
  9. package/dist/esm/{layout → core/drawingml}/chart-geometry.js +79 -117
  10. package/dist/esm/core/drawingml/chart-parser.d.ts +3 -0
  11. package/dist/esm/core/drawingml/chart-parser.js +28 -1
  12. package/dist/esm/{layout → core/drawingml}/preset-geometry.d.ts +2 -2
  13. package/dist/esm/{layout → core/drawingml}/preset-geometry.js +3 -3
  14. package/dist/esm/core/drawingml/shape-render.d.ts +8 -0
  15. package/dist/esm/core/drawingml/shape-render.js +71 -0
  16. package/dist/esm/core/ir/features.d.ts +1 -0
  17. package/dist/esm/core/ir/features.js +1 -0
  18. package/dist/esm/core/ir/flow.d.ts +3 -0
  19. package/dist/esm/core/links.d.ts +6 -0
  20. package/dist/esm/core/links.js +19 -0
  21. package/dist/esm/core/numbering/apply.js +5 -2
  22. package/dist/esm/core/opc/index.d.ts +1 -0
  23. package/dist/esm/core/opc/package.js +3 -2
  24. package/dist/esm/core/opc/relationship-types.d.ts +1 -0
  25. package/dist/esm/core/opc/relationship-types.js +5 -2
  26. package/dist/esm/core/style-cascade/index.d.ts +1 -0
  27. package/dist/esm/core/style-cascade/index.js +1 -0
  28. package/dist/esm/core/style-cascade/table.d.ts +2 -0
  29. package/dist/esm/core/style-cascade/table.js +161 -0
  30. package/dist/esm/core/vector.d.ts +2 -0
  31. package/dist/esm/core/vector.js +19 -1
  32. package/dist/esm/excel/print-model.d.ts +3 -0
  33. package/dist/esm/excel/print-model.js +4 -8
  34. package/dist/esm/excel/sheet-drawing.d.ts +9 -0
  35. package/dist/esm/excel/sheet-drawing.js +113 -0
  36. package/dist/esm/excel/worksheet-parser.d.ts +1 -0
  37. package/dist/esm/excel/worksheet-parser.js +4 -1
  38. package/dist/esm/excel/xlsx-reader.js +41 -0
  39. package/dist/esm/excel/xlsx-to-pdf.js +25 -18
  40. package/dist/esm/html/html-writer.js +188 -16
  41. package/dist/esm/index.d.ts +1 -0
  42. package/dist/esm/layout/page-doc.d.ts +4 -0
  43. package/dist/esm/layout/styled-layout.d.ts +21 -3
  44. package/dist/esm/layout/styled-layout.js +745 -259
  45. package/dist/esm/pdf/encryption.d.ts +34 -0
  46. package/dist/esm/pdf/encryption.js +143 -0
  47. package/dist/esm/pdf/index.d.ts +2 -1
  48. package/dist/esm/pdf/struct-tree.d.ts +7 -1
  49. package/dist/esm/pdf/struct-tree.js +22 -6
  50. package/dist/esm/pdf/styled-page-emitter.d.ts +3 -1
  51. package/dist/esm/pdf/styled-page-emitter.js +185 -35
  52. package/dist/esm/pdf/styled-page-renderer.d.ts +1 -0
  53. package/dist/esm/pdf/styled-page-renderer.js +17 -2
  54. package/dist/esm/pdf/writer.d.ts +2 -0
  55. package/dist/esm/pdf/writer.js +6 -1
  56. package/dist/esm/pdf/xmp.d.ts +1 -0
  57. package/dist/esm/pdf/xmp.js +4 -0
  58. package/dist/esm/svg/svg-writer.js +2 -6
  59. package/dist/esm/word/document-parser.d.ts +3 -0
  60. package/dist/esm/word/document-parser.js +214 -23
  61. package/dist/esm/word/docx-reader.js +37 -15
  62. package/dist/esm/word/docx-to-pdf.js +23 -13
  63. package/dist/esm/word/drawing-parser.d.ts +4 -1
  64. package/dist/esm/word/drawing-parser.js +53 -2
  65. package/dist/esm/word/index.d.ts +2 -2
  66. package/dist/esm/word/styles-parser.js +134 -1
  67. package/dist/esm/word/table-parser.js +35 -0
  68. package/package.json +1 -1
package/README.md CHANGED
@@ -85,7 +85,9 @@ are always used first — glyph-exact, no substitution.
85
85
  ### Archival PDF/A + embedded source
86
86
 
87
87
  The whole PDF/A family is supported (1a/1b, 2a/2b/2u, 3a/3b/3u —
88
- veraPDF-validated). PDF/A-3 can carry the source document inside the PDF:
88
+ veraPDF-validated), plus accessible **PDF/UA-1** (`pdfUA: true`, also
89
+ veraPDF-validated and combinable with PDF/A in one file). PDF/A-3 can carry
90
+ the source document inside the PDF:
89
91
 
90
92
  ```ts
91
93
  const { bytes: pdfa, losses } = await doc.convertWithReport('pdf', {
@@ -157,14 +159,18 @@ automatically from the document's `docProps/core.xml`), `attachments`
157
159
 
158
160
  ## Scope
159
161
 
160
- Implemented: WordprocessingML text/styles/tables/lists/multi-section
161
- layout/headers-footers/images/tracked changes, SpreadsheetML grids,
162
+ Implemented: WordprocessingML text/styles/tables (incl. table styles)/lists/
163
+ multi-section and multi-column layout/headers-footers (incl. PAGE/NUMPAGES
164
+ fields)/footnotes and endnotes/hyperlinks and bookmarks/floating drawings/
165
+ images/tracked changes, SpreadsheetML grids,
162
166
  number formats and the print model (gridlines, print area, fit-to-page,
163
167
  repeated titles, page breaks), DrawingML shapes and charts, OMML math,
164
168
  Type0+CIDFontType2 embedding with subsetting, Knuth-Plass line breaking,
165
169
  Liang hyphenation, OpenType ligatures/kerning + Arabic cursive joining,
166
- BiDi (UAX #9), tagged PDF, PDF/A-1/2/3 (a/b/u), digital signatures
167
- (PKCS#7/ECDSA/PAdES/RFC 3161), SVG page preview, flowed HTML export.
170
+ BiDi (UAX #9), hyperlinks (PDF link annotations + HTML anchors,
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.
168
174
 
169
175
  See `handoff.md` for the full feature matrix and known limitations.
170
176
 
@@ -1,4 +1,4 @@
1
- import { PathSegment } from '../core/vector.js';
1
+ import { PathSegment } from './vector.js';
2
2
  export declare function arcPoint(cx: number, cy: number, rx: number, ry: number, angleRad: number): readonly [number, number];
3
3
  export declare function arcToBeziers(cx: number, cy: number, rx: number, ry: number, startAngleRad: number, sweepAngleRad: number): Array<PathSegment>;
4
4
  export declare function ellipseSegments(w: number, h: number): ReadonlyArray<PathSegment>;
@@ -1,5 +1,5 @@
1
- import { PathBuilder } from "../core/vector.js";
2
- //#region src/layout/arc-to-bezier.ts
1
+ import { PathBuilder } from "./vector.js";
2
+ //#region src/core/arc-to-bezier.ts
3
3
  function arcPoint(cx, cy, rx, ry, angleRad) {
4
4
  return [cx + rx * Math.cos(angleRad), cy + ry * Math.sin(angleRad)];
5
5
  }
@@ -7,6 +7,8 @@ function flowRenderOptions(flow) {
7
7
  ...flow.sections.length > 0 ? { sections: flow.sections } : {},
8
8
  ...flow.section ? { section: flow.section } : {},
9
9
  ...flow.headersFooters ? { headersFooters: flow.headersFooters } : {},
10
+ ...flow.footnotes ? { footnotes: flow.footnotes } : {},
11
+ ...flow.endnotes ? { endnotes: flow.endnotes } : {},
10
12
  resources: flow.resources,
11
13
  ...flow.charts ? { charts: flow.charts } : {},
12
14
  ...flow.embeddedFonts ? { embeddedFonts: flow.embeddedFonts } : {},
@@ -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 {
@@ -1 +1 @@
1
- export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, Chart, ChartBlock, ChartDataPoint, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, SectionProperties, ShapeBlock, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableProperties, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
1
+ export type { AbstractNumbering, Alignment, Border, BorderStyle, BodyElement, CellBorders, CellMerge, DocumentInfo, CellMargins, CellProperties, CellShading, Chart, ChartBlock, ChartDataPoint, ChartSeries, ChartType, CustomGeometry, CustomPathCmd, DocumentModel, FontFamilyMap, HeaderFooterReference, HeaderFooterType, ImageBlock, InlineImage, MathAccent, MathBar, MathDelimiter, MathEqArray, MathFraction, MathFunc, MathGroupChr, MathLimit, MathMatrix, MathNary, MathNode, MathRadical, MathRow, MathRun, MathScript, Numbering, NumberingFormat, NumberingInstance, NumberingLevel, NumberingReference, PageMargins, PageSize, Paragraph, ParagraphProperties, Run, RunProperties, RowProperties, Section, FloatAnchor, SectionColumns, SectionProperties, ShapeBlock, ShapeDash, ShapeFill, ShapeFillKind, ShapeGeometry, ShapeLine, ShapeTextBody, ShapeTransform, Style, StyleSheet, StyleType, Table, TableCell, TableLook, TableProperties, TableStyleCondition, TableStyleConditionType, TableStyleLayer, TableRow, UnderlineStyle, VerticalAlign, } from './types.js';
@@ -126,6 +126,13 @@ export interface Run {
126
126
  readonly native?: NativeBag;
127
127
  readonly text: string;
128
128
  readonly properties: RunProperties;
129
+ readonly href?: string;
130
+ readonly field?: 'PAGE' | 'NUMPAGES';
131
+ readonly anchor?: string;
132
+ readonly footnoteRef?: string;
133
+ readonly endnoteRef?: string;
134
+ readonly noteNumber?: true;
135
+ readonly listMarker?: true;
129
136
  readonly inlineImage?: InlineImage;
130
137
  readonly math?: MathNode;
131
138
  readonly pageBreak?: boolean;
@@ -134,6 +141,7 @@ export interface Paragraph {
134
141
  readonly native?: NativeBag;
135
142
  readonly properties: ParagraphProperties;
136
143
  readonly runs: ReadonlyArray<Run>;
144
+ readonly bookmarks?: ReadonlyArray<string>;
137
145
  }
138
146
  export type NumberingFormat = 'decimal' | 'lowerLetter' | 'upperLetter' | 'lowerRoman' | 'upperRoman' | 'bullet' | 'none';
139
147
  export interface NumberingReference {
@@ -161,6 +169,18 @@ export interface Numbering {
161
169
  readonly numInstances: ReadonlyMap<string, NumberingInstance>;
162
170
  }
163
171
  export type StyleType = 'paragraph' | 'character' | 'table' | 'numbering';
172
+ export interface TableStyleLayer {
173
+ readonly borders?: CellBorders;
174
+ readonly cellMargins?: CellMargins;
175
+ readonly shading?: CellShading;
176
+ readonly runProperties?: RunProperties;
177
+ readonly paragraphProperties?: ParagraphProperties;
178
+ }
179
+ export type TableStyleConditionType = 'wholeTable' | 'band1Vert' | 'band2Vert' | 'band1Horz' | 'band2Horz' | 'firstCol' | 'lastCol' | 'firstRow' | 'lastRow' | 'nwCell' | 'neCell' | 'swCell' | 'seCell';
180
+ export interface TableStyleCondition {
181
+ readonly type: TableStyleConditionType;
182
+ readonly layer: TableStyleLayer;
183
+ }
164
184
  export interface Style {
165
185
  readonly id: string;
166
186
  readonly type: StyleType;
@@ -168,6 +188,10 @@ export interface Style {
168
188
  readonly isDefault: boolean;
169
189
  readonly runProperties: RunProperties;
170
190
  readonly paragraphProperties: ParagraphProperties;
191
+ readonly tableLayer?: TableStyleLayer;
192
+ readonly tableConditions?: ReadonlyArray<TableStyleCondition>;
193
+ readonly rowBandSize?: number;
194
+ readonly colBandSize?: number;
171
195
  }
172
196
  export interface StyleSheet {
173
197
  readonly defaultRunProperties: RunProperties;
@@ -213,7 +237,17 @@ export interface RowProperties {
213
237
  readonly isHeader?: boolean;
214
238
  readonly pageBreakBefore?: boolean;
215
239
  }
240
+ export interface TableLook {
241
+ readonly firstRow?: boolean;
242
+ readonly lastRow?: boolean;
243
+ readonly firstColumn?: boolean;
244
+ readonly lastColumn?: boolean;
245
+ readonly noHBand?: boolean;
246
+ readonly noVBand?: boolean;
247
+ }
216
248
  export interface TableProperties {
249
+ readonly styleId?: string;
250
+ readonly look?: TableLook;
217
251
  readonly widthPt?: Pt;
218
252
  readonly widthFraction?: number;
219
253
  readonly widthType?: 'auto' | 'dxa' | 'pct' | 'nil';
@@ -237,6 +271,7 @@ export interface Table {
237
271
  readonly rows: ReadonlyArray<TableRow>;
238
272
  }
239
273
  export interface ImageBlock {
274
+ readonly float?: FloatAnchor;
240
275
  readonly resource?: ResourceId;
241
276
  readonly width: Pt;
242
277
  readonly height: Pt;
@@ -312,6 +347,7 @@ export interface ShapeTextBody {
312
347
  readonly anchor?: 't' | 'ctr' | 'b';
313
348
  }
314
349
  export interface ShapeBlock {
350
+ readonly float?: FloatAnchor;
315
351
  readonly width: Pt;
316
352
  readonly height: Pt;
317
353
  readonly geometry: ShapeGeometry;
@@ -347,8 +383,10 @@ export interface Chart {
347
383
  readonly showValues?: boolean;
348
384
  readonly catAxisTitle?: string;
349
385
  readonly valAxisTitle?: string;
386
+ readonly seriesColorCycle?: ReadonlyArray<string>;
350
387
  }
351
388
  export interface ChartBlock {
389
+ readonly float?: FloatAnchor;
352
390
  readonly chartRelId: string;
353
391
  readonly width: Pt;
354
392
  readonly height: Pt;
@@ -396,6 +434,28 @@ export interface SectionProperties {
396
434
  readonly footers: ReadonlyArray<HeaderFooterReference>;
397
435
  readonly titlePg?: boolean;
398
436
  readonly evenAndOddHeaders?: boolean;
437
+ readonly columns?: SectionColumns;
438
+ }
439
+ export interface FloatAnchor {
440
+ readonly wrap: 'none' | 'square' | 'tight' | 'through' | 'topAndBottom';
441
+ readonly behind?: boolean;
442
+ readonly posH?: {
443
+ readonly relativeFrom: 'margin' | 'page' | 'column';
444
+ readonly offsetPt?: Pt;
445
+ readonly align?: 'left' | 'center' | 'right';
446
+ };
447
+ readonly posV?: {
448
+ readonly relativeFrom: 'margin' | 'page' | 'paragraph' | 'line';
449
+ readonly offsetPt?: Pt;
450
+ };
451
+ }
452
+ export interface SectionColumns {
453
+ readonly count: number;
454
+ readonly spacePt: number;
455
+ readonly explicit?: ReadonlyArray<{
456
+ readonly widthPt: number;
457
+ readonly spacePt: number;
458
+ }>;
399
459
  }
400
460
  export interface Section {
401
461
  readonly properties: SectionProperties;
@@ -1,4 +1,4 @@
1
- import { Chart, ChartSeries } from '../core/document-model/index.js';
1
+ import { Chart, ChartSeries } from '../document-model/index.js';
2
2
  export interface ChartRect {
3
3
  readonly x: number;
4
4
  readonly y: number;
@@ -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 };
@@ -1,5 +1,5 @@
1
- import { CustomGeometry } from '../core/document-model/index.js';
2
- import { PathSegment, VectorPath } from '../core/vector.js';
1
+ import { CustomGeometry } from '../document-model/index.js';
2
+ import { PathSegment, VectorPath } from '../vector.js';
3
3
  export declare function rectSegments(w: number, h: number): ReadonlyArray<PathSegment>;
4
4
  export declare function rectPath(w: number, h: number): VectorPath;
5
5
  export declare function presetPaths(preset: string, w: number, h: number, adjust: ReadonlyMap<string, number>): Array<VectorPath> | null;
@@ -1,6 +1,6 @@
1
- import { PathBuilder } from "../core/vector.js";
2
- import { arcToBeziers, ellipseSegments, roundRectSegments } from "./arc-to-bezier.js";
3
- //#region src/layout/preset-geometry.ts
1
+ import { PathBuilder } from "../vector.js";
2
+ import { arcToBeziers, ellipseSegments, roundRectSegments } from "../arc-to-bezier.js";
3
+ //#region src/core/drawingml/preset-geometry.ts
4
4
  function rectSegments(w, h) {
5
5
  return new PathBuilder().moveTo(0, 0).lineTo(w, 0).lineTo(w, h).lineTo(0, h).close().build().segments;
6
6
  }
@@ -0,0 +1,8 @@
1
+ import { ShapeGeometry, ShapeLine } from '../document-model/index.js';
2
+ import { StrokeStyle, VectorPath } from '../vector.js';
3
+ export declare const EMU_PER_PT = 12700;
4
+ export declare const DEFAULT_INSET_LR_PT: number;
5
+ export declare const DEFAULT_INSET_TB_PT: number;
6
+ export declare function buildShapePaths(geometry: ShapeGeometry, widthPt: number, heightPt: number): Array<VectorPath>;
7
+ export declare function buildStroke(line: ShapeLine | undefined): StrokeStyle | undefined;
8
+ export declare function buildShapeTransform(pageX: number, pageY: number, widthPt: number, heightPt: number, rotation60k: number, flipH: boolean, flipV: boolean): [number, number, number, number, number, number];
@@ -0,0 +1,71 @@
1
+ import { customPaths, presetPaths, rectPath } from "./preset-geometry.js";
2
+ //#region src/core/drawingml/shape-render.ts
3
+ var EMU_PER_PT = 12700;
4
+ var DEFAULT_LINE_WIDTH_EMU = 9525;
5
+ var DEFAULT_INSET_LR_PT = 91440 / EMU_PER_PT;
6
+ var DEFAULT_INSET_TB_PT = 45720 / EMU_PER_PT;
7
+ function buildShapePaths(geometry, widthPt, heightPt) {
8
+ if (geometry.kind === "preset") return presetPaths(geometry.preset ?? "rect", widthPt, heightPt, geometry.adjust ?? /* @__PURE__ */ new Map()) ?? [rectPath(widthPt, heightPt)];
9
+ if (geometry.custom) return customPaths(geometry.custom, widthPt, heightPt);
10
+ return [rectPath(widthPt, heightPt)];
11
+ }
12
+ function buildStroke(line) {
13
+ if (!line || line.fill === "none") return void 0;
14
+ const widthPt = line.width ?? DEFAULT_LINE_WIDTH_EMU / 12700;
15
+ const dash = line.dash && line.dash !== "solid" ? dashPattern(line.dash, widthPt) : void 0;
16
+ const cap = line.cap === "flat" ? "butt" : line.cap;
17
+ return {
18
+ colorHex: line.colorHex ?? "000000",
19
+ widthPt,
20
+ ...dash ? { dash } : {},
21
+ ...cap ? { cap } : {}
22
+ };
23
+ }
24
+ function dashPattern(dash, w) {
25
+ const u = Math.max(w, .1);
26
+ switch (dash) {
27
+ case "solid": return;
28
+ case "dot": return [u, 2 * u];
29
+ case "dash": return [4 * u, 3 * u];
30
+ case "dashDot": return [
31
+ 4 * u,
32
+ 3 * u,
33
+ u,
34
+ 3 * u
35
+ ];
36
+ case "lgDash": return [8 * u, 3 * u];
37
+ case "lgDashDot": return [
38
+ 8 * u,
39
+ 3 * u,
40
+ u,
41
+ 3 * u
42
+ ];
43
+ case "sysDash": return [3 * u, u];
44
+ case "sysDot": return [u, u];
45
+ }
46
+ }
47
+ function buildShapeTransform(pageX, pageY, widthPt, heightPt, rotation60k, flipH, flipV) {
48
+ const theta = -rotation60k / 6e4 * (Math.PI / 180);
49
+ const sx = flipH ? -1 : 1;
50
+ const sy = flipV ? -1 : 1;
51
+ const cos = Math.cos(theta);
52
+ const sin = Math.sin(theta);
53
+ const a = sx * cos;
54
+ const b = sx * sin;
55
+ const c = -sy * sin;
56
+ const d = sy * cos;
57
+ const cxL = widthPt / 2;
58
+ const cyL = heightPt / 2;
59
+ const centerX = pageX + cxL;
60
+ const centerY = pageY + cyL;
61
+ return [
62
+ a,
63
+ b,
64
+ c,
65
+ d,
66
+ centerX - (a * cxL + c * cyL),
67
+ centerY - (b * cxL + d * cyL)
68
+ ];
69
+ }
70
+ //#endregion
71
+ export { DEFAULT_INSET_LR_PT, DEFAULT_INSET_TB_PT, buildShapePaths, buildShapeTransform, buildStroke };
@@ -8,6 +8,7 @@ export declare const FEATURES: {
8
8
  readonly headersFooters: "headersFooters";
9
9
  readonly images: "images";
10
10
  readonly imagesJp2: "images.jp2";
11
+ readonly hyperlinks: "hyperlinks";
11
12
  readonly shapes: "shapes";
12
13
  readonly charts: "charts";
13
14
  readonly math: "math";