reamkit 1.23.0 → 1.25.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 (102) hide show
  1. package/README.md +22 -11
  2. package/dist/esm/core/bmp.d.ts +33 -0
  3. package/dist/esm/core/bmp.js +276 -0
  4. package/dist/esm/core/converter/facade.d.ts +3 -3
  5. package/dist/esm/core/converter/facade.js +12 -0
  6. package/dist/esm/core/converter/ream.d.ts +48 -4
  7. package/dist/esm/core/converter/ream.js +25 -4
  8. package/dist/esm/core/document-model/index.d.ts +1 -1
  9. package/dist/esm/core/document-model/types.d.ts +54 -0
  10. package/dist/esm/core/drawingml/chart-geometry.js +3 -2
  11. package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
  12. package/dist/esm/core/drawingml/diagram/colors.js +125 -0
  13. package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
  14. package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
  15. package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
  16. package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
  17. package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
  18. package/dist/esm/core/drawingml/diagram/run.js +50 -0
  19. package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
  20. package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
  21. package/dist/esm/core/drawingml/preset-geometry.js +116 -6
  22. package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
  23. package/dist/esm/core/drawingml/text-warp.js +355 -0
  24. package/dist/esm/core/drawingml/theme-parser.js +9 -3
  25. package/dist/esm/core/font/measure.d.ts +12 -0
  26. package/dist/esm/core/font/measure.js +36 -0
  27. package/dist/esm/core/images.d.ts +30 -2
  28. package/dist/esm/core/images.js +121 -5
  29. package/dist/esm/core/metafile/emf.js +144 -16
  30. package/dist/esm/core/metafile/picture.d.ts +49 -0
  31. package/dist/esm/core/metafile/picture.js +70 -1
  32. package/dist/esm/core/metafile/wmf.js +53 -4
  33. package/dist/esm/core/ole/escher-blip.js +11 -1
  34. package/dist/esm/core/outline.d.ts +17 -0
  35. package/dist/esm/core/outline.js +30 -0
  36. package/dist/esm/core/style-cascade/resolver.js +1 -0
  37. package/dist/esm/core/style-cascade/types.d.ts +3 -1
  38. package/dist/esm/excel/print-model.js +2 -2
  39. package/dist/esm/excel/sheet-drawing.js +1 -1
  40. package/dist/esm/excel/sheet-to-flow.d.ts +10 -0
  41. package/dist/esm/excel/sheet-to-flow.js +30 -3
  42. package/dist/esm/html/html-writer.js +5 -3
  43. package/dist/esm/index.d.ts +3 -0
  44. package/dist/esm/index.js +2 -1
  45. package/dist/esm/layout/page-doc.d.ts +35 -0
  46. package/dist/esm/layout/page-doc.js +14 -1
  47. package/dist/esm/layout/styled-layout.js +217 -30
  48. package/dist/esm/markdown/markdown-writer.d.ts +41 -0
  49. package/dist/esm/markdown/markdown-writer.js +733 -0
  50. package/dist/esm/pdf/shading.js +8 -6
  51. package/dist/esm/pdf/styled-page-emitter.js +62 -4
  52. package/dist/esm/pdf/vector-graphics.js +1 -1
  53. package/dist/esm/pdf-reader/annots.d.ts +24 -0
  54. package/dist/esm/pdf-reader/annots.js +126 -0
  55. package/dist/esm/pdf-reader/content.d.ts +131 -5
  56. package/dist/esm/pdf-reader/content.js +169 -12
  57. package/dist/esm/pdf-reader/display.d.ts +56 -0
  58. package/dist/esm/pdf-reader/display.js +162 -0
  59. package/dist/esm/pdf-reader/document.d.ts +36 -1
  60. package/dist/esm/pdf-reader/document.js +92 -25
  61. package/dist/esm/pdf-reader/embedded-fonts.d.ts +31 -0
  62. package/dist/esm/pdf-reader/embedded-fonts.js +94 -0
  63. package/dist/esm/pdf-reader/flow-build.d.ts +61 -6
  64. package/dist/esm/pdf-reader/flow-build.js +128 -22
  65. package/dist/esm/pdf-reader/font.js +185 -4
  66. package/dist/esm/pdf-reader/image-decode.js +56 -5
  67. package/dist/esm/pdf-reader/images.d.ts +6 -0
  68. package/dist/esm/pdf-reader/images.js +25 -5
  69. package/dist/esm/pdf-reader/jpeg.d.ts +18 -0
  70. package/dist/esm/pdf-reader/jpeg.js +419 -0
  71. package/dist/esm/pdf-reader/layout.d.ts +1 -1
  72. package/dist/esm/pdf-reader/layout.js +221 -32
  73. package/dist/esm/pdf-reader/pattern-tint.d.ts +17 -0
  74. package/dist/esm/pdf-reader/pattern-tint.js +181 -0
  75. package/dist/esm/pdf-reader/reader.d.ts +9 -1
  76. package/dist/esm/pdf-reader/reader.js +22 -6
  77. package/dist/esm/pdf-reader/shading.d.ts +14 -0
  78. package/dist/esm/pdf-reader/shading.js +27 -1
  79. package/dist/esm/pdf-reader/tagged.js +156 -17
  80. package/dist/esm/pdf-reader/text.d.ts +13 -1
  81. package/dist/esm/pdf-reader/text.js +70 -3
  82. package/dist/esm/pdf-reader/vector.d.ts +25 -1
  83. package/dist/esm/pdf-reader/vector.js +168 -12
  84. package/dist/esm/pptx/ppt/ppt-reader.js +95 -27
  85. package/dist/esm/pptx/ppt/ppt-text.d.ts +41 -0
  86. package/dist/esm/pptx/ppt/ppt-text.js +327 -37
  87. package/dist/esm/pptx/pptx-reader.js +90 -10
  88. package/dist/esm/pptx/slide-parser.d.ts +4 -1
  89. package/dist/esm/pptx/slide-parser.js +104 -13
  90. package/dist/esm/pptx/sp-helpers.d.ts +7 -3
  91. package/dist/esm/pptx/sp-helpers.js +45 -7
  92. package/dist/esm/pptx/table-style.d.ts +7 -0
  93. package/dist/esm/pptx/table-style.js +59 -7
  94. package/dist/esm/svg/svg-writer.js +1 -0
  95. package/dist/esm/word/document-parser.d.ts +4 -1
  96. package/dist/esm/word/document-parser.js +4 -1
  97. package/dist/esm/word/docx-reader.js +26 -13
  98. package/dist/esm/word/docx-writer.js +15 -1
  99. package/dist/esm/word/drawing-parser.d.ts +20 -0
  100. package/dist/esm/word/drawing-parser.js +44 -5
  101. package/dist/esm/word/table-parser.js +3 -0
  102. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { pt } from "../../core/ir/units.js";
2
2
  import { ResourceStore } from "../../core/ir/resources.js";
3
3
  import { FEATURES } from "../../core/ir/features.js";
4
+ import { knockOutColor } from "../../core/images.js";
4
5
  import { isEmf } from "../../core/metafile/emf.js";
5
6
  import { isWmf } from "../../core/metafile/wmf.js";
6
7
  import { EMPTY_STYLE_SHEET, resolveBodyStyles } from "../../core/style-cascade/resolver.js";
@@ -136,8 +137,9 @@ function bulletedRuns(para) {
136
137
  const runs = para.runs.map(toRun);
137
138
  if (para.bullet === void 0) return runs;
138
139
  const { bold: _b, italic: _i, ...rest } = runs[0]?.properties ?? {};
140
+ const gap = hangs(para) ? " " : " ";
139
141
  return [{
140
- text: `${para.bullet} `,
142
+ text: `${para.bullet}${gap}`,
141
143
  properties: rest
142
144
  }, ...runs];
143
145
  }
@@ -175,16 +177,13 @@ function backdropFill(bg, resources) {
175
177
  if (bg.image) return {
176
178
  kind: "picture",
177
179
  imageResource: resources.put(bg.image.bytes),
178
- ...bg.imageTiled ? { tiled: true } : {}
180
+ ...bg.imageTiled ? {
181
+ tiled: true,
182
+ tileFromCentre: true
183
+ } : {}
179
184
  };
180
185
  if (bg.gradient) {
181
- const stops = [{
182
- offset: 0,
183
- colorHex: bg.gradient.fromHex
184
- }, {
185
- offset: 1,
186
- colorHex: bg.gradient.toHex
187
- }];
186
+ const stops = gradientStops(bg.gradient);
188
187
  return {
189
188
  kind: "gradient",
190
189
  gradient: bg.gradient.radial ? {
@@ -242,9 +241,10 @@ function positionedImage(rect, image, resources) {
242
241
  kind: "image",
243
242
  image: {
244
243
  float: floatAt(rect),
245
- resource: resources.put(image.bytes),
244
+ resource: resources.put(drawnBytes(image)),
246
245
  width: pt(rect.w),
247
246
  height: pt(rect.h),
247
+ ...image.crop ? { crop: image.crop } : {},
248
248
  paragraphProperties: {}
249
249
  }
250
250
  };
@@ -290,34 +290,72 @@ function toCustomGeometry(g) {
290
290
  commands
291
291
  };
292
292
  }
293
+ /**
294
+ * §2.3.7.6 `fillFocus` — the stops a shaded fill's two colours make.
295
+ *
296
+ * A focus of zero is the plain ramp everyone expects: the first colour at one
297
+ * end, the second at the other. Any other value means the sweep runs OUT from
298
+ * one of them — a focus of 50 puts the first colour halfway along with the
299
+ * second at BOTH ends, which is what 23884's every slide asks for and why its
300
+ * background read as a flat wash into violet where the reference is blue
301
+ * across the middle and dark only at the corners.
302
+ *
303
+ * @param g The gradient as the `.ppt` states it.
304
+ * @returns The stops, in order.
305
+ */
306
+ function gradientStops(g) {
307
+ const focus = g.focusPct ?? 0;
308
+ if (focus === 0) return [{
309
+ offset: 0,
310
+ colorHex: g.fromHex
311
+ }, {
312
+ offset: 1,
313
+ colorHex: g.toHex
314
+ }];
315
+ if (Math.abs(focus) >= 100) return [{
316
+ offset: 0,
317
+ colorHex: g.toHex
318
+ }, {
319
+ offset: 1,
320
+ colorHex: g.fromHex
321
+ }];
322
+ const peak = focus > 0 ? g.fromHex : g.toHex;
323
+ const ends = focus > 0 ? g.toHex : g.fromHex;
324
+ const at = focus > 0 ? focus / 100 : 1 + focus / 100;
325
+ return [
326
+ {
327
+ offset: 0,
328
+ colorHex: ends
329
+ },
330
+ {
331
+ offset: at,
332
+ colorHex: peak
333
+ },
334
+ {
335
+ offset: 1,
336
+ colorHex: ends
337
+ }
338
+ ];
339
+ }
293
340
  function positionedAutoShape(rect, auto, resources) {
294
341
  const line = isLineShape(auto.shapeType);
295
342
  const fill = line ? { kind: "none" } : auto.image ? {
296
343
  kind: "picture",
297
344
  imageResource: resources.put(auto.image.bytes),
298
- ...auto.imageTiled ? { tiled: true } : {},
345
+ ...auto.imageTiled ? {
346
+ tiled: true,
347
+ tileFromCentre: true
348
+ } : {},
299
349
  ...auto.tileSizePt ? { tileSizePt: auto.tileSizePt } : {}
300
350
  } : auto.gradient ? {
301
351
  kind: "gradient",
302
352
  gradient: auto.gradient.radial ? {
303
353
  kind: "radial",
304
- stops: [{
305
- offset: 0,
306
- colorHex: auto.gradient.fromHex
307
- }, {
308
- offset: 1,
309
- colorHex: auto.gradient.toHex
310
- }]
354
+ stops: gradientStops(auto.gradient)
311
355
  } : {
312
356
  kind: "linear",
313
357
  angle: auto.gradient.angleDeg,
314
- stops: [{
315
- offset: 0,
316
- colorHex: auto.gradient.fromHex
317
- }, {
318
- offset: 1,
319
- colorHex: auto.gradient.toHex
320
- }]
358
+ stops: gradientStops(auto.gradient)
321
359
  }
322
360
  } : auto.fillColorHex ? {
323
361
  kind: "solid",
@@ -353,13 +391,30 @@ function inFlowImage(image, resources) {
353
391
  return {
354
392
  kind: "image",
355
393
  image: {
356
- resource: resources.put(image.bytes),
394
+ resource: resources.put(drawnBytes(image)),
357
395
  width: pt(size.w * .75),
358
396
  height: pt(size.h * .75),
397
+ ...image.crop ? { crop: image.crop } : {},
359
398
  paragraphProperties: {}
360
399
  }
361
400
  };
362
401
  }
402
+ /**
403
+ * The bytes a picture is actually DRAWN from.
404
+ *
405
+ * §2.3.23 `pictureTransparent` names a colour the picture is drawn without, and
406
+ * a raster carries no alpha channel to say so — so the knock-out is baked into
407
+ * bytes of its own. The resource store hashes content, so two shapes knocking
408
+ * different colours out of the same blip stay two resources by themselves, and
409
+ * one that knocks out nothing keeps the bytes it arrived with.
410
+ *
411
+ * @param image The picture as the shape states it.
412
+ * @returns The bytes to store, knocked out where the shape asks for it.
413
+ */
414
+ function drawnBytes(image) {
415
+ if (image.transparentHex === void 0 || isMetafile(image.bytes)) return image.bytes;
416
+ return knockOutColor(image.bytes, image.transparentHex) ?? image.bytes;
417
+ }
363
418
  function isMetafile(d) {
364
419
  return isEmf(d) || isWmf(d);
365
420
  }
@@ -418,12 +473,25 @@ function toRun(r) {
418
473
  function toParaProperties(p, breakBefore) {
419
474
  const alignment = p.align !== void 0 ? alignmentFrom(p.align) : void 0;
420
475
  const level = p.level ?? 0;
476
+ const leftPt = p.leftMarginPt ?? (level > 0 ? level * LEVEL_INDENT_PT : void 0);
477
+ const firstPt = p.indentPt !== void 0 ? p.indentPt - (leftPt ?? 0) : void 0;
421
478
  return {
422
479
  ...breakBefore ? { pageBreakBefore: true } : {},
423
480
  ...alignment ? { alignment } : {},
424
- ...level > 0 ? { indentLeft: pt(level * LEVEL_INDENT_PT) } : {}
481
+ ...leftPt !== void 0 ? { indentLeft: pt(leftPt) } : {},
482
+ ...firstPt !== void 0 && firstPt !== 0 ? { indentFirstLine: pt(firstPt) } : {},
483
+ ...p.spaceBeforePt !== void 0 ? { spacingBefore: pt(p.spaceBeforePt) } : {},
484
+ ...p.spaceAfterPt !== void 0 ? { spacingAfter: pt(p.spaceAfterPt) } : {},
485
+ ...p.lineSpacing !== void 0 && p.lineSpacing > 0 ? {
486
+ spacingLineRule: "auto",
487
+ spacingLine: pt(p.lineSpacing / 100 * 12)
488
+ } : {}
425
489
  };
426
490
  }
491
+ /** Whether the paragraph's first line starts LEFT of its body — a hanging bullet. */
492
+ function hangs(p) {
493
+ return p.indentPt !== void 0 && p.leftMarginPt !== void 0 && p.indentPt < p.leftMarginPt;
494
+ }
427
495
  function alignmentFrom(a) {
428
496
  switch (a) {
429
497
  case 1: return "center";
@@ -28,6 +28,18 @@ export interface PptParagraph {
28
28
  * carries none.
29
29
  */
30
30
  readonly bullet?: string;
31
+ /**
32
+ * §2.9.20 `leftMargin` — where the paragraph's BODY sits, in points from the
33
+ * text box's own left edge.
34
+ */
35
+ readonly leftMarginPt?: number;
36
+ /** §2.9.20 `indent` — where its FIRST line starts. Left of the body ⇒ hanging. */
37
+ readonly indentPt?: number;
38
+ /** §2.9.32 `lineSpacing`, as a PERCENTAGE of the line's height — 100 is single. */
39
+ readonly lineSpacing?: number;
40
+ /** §2.9.32 `spaceBefore` / `spaceAfter`, in points. */
41
+ readonly spaceBeforePt?: number;
42
+ readonly spaceAfterPt?: number;
31
43
  }
32
44
  /**
33
45
  * An embedded picture referenced by a slide shape — the raw image bytes pulled
@@ -35,6 +47,22 @@ export interface PptParagraph {
35
47
  */
36
48
  export interface PptImage {
37
49
  readonly bytes: Uint8Array;
50
+ /**
51
+ * §2.3.23 `cropFrom*` — the fraction of each edge of the SOURCE cut away
52
+ * before it is fitted to the shape's box. Absent ⇒ the whole picture.
53
+ */
54
+ readonly crop?: {
55
+ readonly left: number;
56
+ readonly top: number;
57
+ readonly right: number;
58
+ readonly bottom: number;
59
+ };
60
+ /**
61
+ * §2.3.23 `pictureTransparent` — the colour the picture is drawn WITHOUT,
62
+ * 6-hex and no leading `#`. Clip art of this age states its ground here
63
+ * rather than carrying an alpha channel.
64
+ */
65
+ readonly transparentHex?: string;
38
66
  }
39
67
  /** A shape's rectangle on the slide, in points (from the OfficeArtClientAnchor). */
40
68
  export interface PptRect {
@@ -99,6 +127,12 @@ export interface PptAutoShape {
99
127
  readonly toHex: string;
100
128
  readonly angleDeg: number;
101
129
  readonly radial: boolean;
130
+ /**
131
+ * §2.3.7.6 `fillFocus` — where along the sweep the FIRST colour peaks, as a
132
+ * percentage. Zero is a plain ramp; 50 puts it in the middle with the
133
+ * second colour at both ends, which is a different picture entirely.
134
+ */
135
+ readonly focusPct?: number;
102
136
  };
103
137
  /**
104
138
  * §2.3.7.1 MSOFILLTYPE 3 — a picture stretched over the shape, its blip named
@@ -138,6 +172,13 @@ export interface PptShape {
138
172
  * of them would carry "Click to edit Master title style".
139
173
  */
140
174
  readonly placeholder?: boolean;
175
+ /**
176
+ * §2.9.51 `OEPlaceholderAtom.placeholderId` — WHICH placeholder it is. The
177
+ * three a master keeps for the slide's furniture — 7 the date, 8 the slide
178
+ * number, 9 the footer — are the only ones whose text does not live in the
179
+ * shape at all (§2.4.15).
180
+ */
181
+ readonly placeholderId?: number;
141
182
  readonly paragraphs?: ReadonlyArray<PptParagraph>;
142
183
  readonly image?: PptImage;
143
184
  readonly autoShape?: PptAutoShape;