reamkit 1.22.0 → 1.24.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 (101) hide show
  1. package/dist/esm/core/bmp.d.ts +33 -0
  2. package/dist/esm/core/bmp.js +276 -0
  3. package/dist/esm/core/converter/ream.d.ts +16 -0
  4. package/dist/esm/core/converter/ream.js +59 -9
  5. package/dist/esm/core/document-model/types.d.ts +55 -0
  6. package/dist/esm/core/drawingml/chart-geometry.js +14 -7
  7. package/dist/esm/core/drawingml/colors.d.ts +4 -2
  8. package/dist/esm/core/drawingml/colors.js +15 -0
  9. package/dist/esm/core/drawingml/diagram/colors.d.ts +52 -0
  10. package/dist/esm/core/drawingml/diagram/colors.js +125 -0
  11. package/dist/esm/core/drawingml/diagram/data-model.d.ts +47 -0
  12. package/dist/esm/core/drawingml/diagram/data-model.js +119 -0
  13. package/dist/esm/core/drawingml/diagram/layout-engine.d.ts +46 -0
  14. package/dist/esm/core/drawingml/diagram/layout-engine.js +948 -0
  15. package/dist/esm/core/drawingml/diagram/run.d.ts +37 -0
  16. package/dist/esm/core/drawingml/diagram/run.js +50 -0
  17. package/dist/esm/core/drawingml/diagram/to-drawing.d.ts +16 -0
  18. package/dist/esm/core/drawingml/diagram/to-drawing.js +86 -0
  19. package/dist/esm/core/drawingml/preset-geometry.js +116 -6
  20. package/dist/esm/core/drawingml/text-warp.d.ts +58 -0
  21. package/dist/esm/core/drawingml/text-warp.js +355 -0
  22. package/dist/esm/core/drawingml/theme-parser.d.ts +38 -0
  23. package/dist/esm/core/drawingml/theme-parser.js +73 -4
  24. package/dist/esm/core/font/measure.d.ts +12 -0
  25. package/dist/esm/core/font/measure.js +36 -0
  26. package/dist/esm/core/fonts/families.d.ts +10 -0
  27. package/dist/esm/core/fonts/families.js +44 -0
  28. package/dist/esm/core/fonts/index.d.ts +3 -2
  29. package/dist/esm/core/fonts/remote-fonts.d.ts +50 -0
  30. package/dist/esm/core/fonts/remote-fonts.js +114 -8
  31. package/dist/esm/core/fonts/scripts.d.ts +26 -0
  32. package/dist/esm/core/fonts/scripts.js +177 -0
  33. package/dist/esm/core/images.d.ts +30 -2
  34. package/dist/esm/core/images.js +121 -5
  35. package/dist/esm/core/metafile/blit.d.ts +33 -0
  36. package/dist/esm/core/metafile/blit.js +67 -0
  37. package/dist/esm/core/metafile/dib.d.ts +61 -0
  38. package/dist/esm/core/metafile/dib.js +205 -0
  39. package/dist/esm/core/metafile/emf.js +280 -38
  40. package/dist/esm/core/metafile/picture.d.ts +61 -1
  41. package/dist/esm/core/metafile/picture.js +70 -1
  42. package/dist/esm/core/metafile/wmf.js +202 -13
  43. package/dist/esm/core/ole/escher-blip.d.ts +12 -0
  44. package/dist/esm/core/ole/escher-blip.js +98 -0
  45. package/dist/esm/{pdf-reader → core}/png-encode.js +1 -1
  46. package/dist/esm/excel/print-model.js +5 -3
  47. package/dist/esm/excel/sheet-drawing.js +1 -1
  48. package/dist/esm/excel/sheet-to-flow.js +16 -2
  49. package/dist/esm/excel/styles-parser.js +1 -1
  50. package/dist/esm/excel/xls/biff-reader.js +53 -18
  51. package/dist/esm/excel/xls/biff-styles.d.ts +5 -2
  52. package/dist/esm/excel/xls/biff-styles.js +9 -7
  53. package/dist/esm/excel/xls/escher.js +90 -24
  54. package/dist/esm/html/html-writer.js +2 -1
  55. package/dist/esm/layout/page-doc.d.ts +74 -0
  56. package/dist/esm/layout/page-doc.js +14 -1
  57. package/dist/esm/layout/styled-layout.d.ts +2 -2
  58. package/dist/esm/layout/styled-layout.js +475 -48
  59. package/dist/esm/pdf/shading.js +8 -6
  60. package/dist/esm/pdf/styled-page-emitter.js +77 -5
  61. package/dist/esm/pdf/vector-graphics.js +1 -1
  62. package/dist/esm/pdf-reader/image-decode.js +1 -1
  63. package/dist/esm/pptx/embedded-fonts.d.ts +31 -0
  64. package/dist/esm/pptx/embedded-fonts.js +104 -0
  65. package/dist/esm/pptx/placeholder-cascade.d.ts +73 -6
  66. package/dist/esm/pptx/placeholder-cascade.js +114 -18
  67. package/dist/esm/pptx/ppt/ppt-reader.js +191 -13
  68. package/dist/esm/pptx/ppt/ppt-text.d.ts +107 -1
  69. package/dist/esm/pptx/ppt/ppt-text.js +873 -144
  70. package/dist/esm/pptx/pptx-reader.d.ts +8 -0
  71. package/dist/esm/pptx/pptx-reader.js +117 -15
  72. package/dist/esm/pptx/preset-table-styles.d.ts +9 -0
  73. package/dist/esm/pptx/preset-table-styles.js +27 -0
  74. package/dist/esm/pptx/slide-parser.d.ts +11 -2
  75. package/dist/esm/pptx/slide-parser.js +203 -44
  76. package/dist/esm/pptx/sp-helpers.d.ts +9 -4
  77. package/dist/esm/pptx/sp-helpers.js +48 -9
  78. package/dist/esm/pptx/table-style.d.ts +16 -1
  79. package/dist/esm/pptx/table-style.js +104 -10
  80. package/dist/esm/svg/svg-writer.js +1 -0
  81. package/dist/esm/word/document-parser.d.ts +11 -2
  82. package/dist/esm/word/document-parser.js +10 -7
  83. package/dist/esm/word/docx-reader.js +32 -16
  84. package/dist/esm/word/docx-to-pdf.d.ts +8 -7
  85. package/dist/esm/word/docx-to-pdf.js +25 -7
  86. package/dist/esm/word/docx-writer.js +4 -0
  87. package/dist/esm/word/drawing-parser.d.ts +20 -0
  88. package/dist/esm/word/drawing-parser.js +67 -22
  89. package/dist/esm/word/numbering-parser.d.ts +2 -1
  90. package/dist/esm/word/numbering-parser.js +6 -6
  91. package/dist/esm/word/paragraph-properties.d.ts +2 -1
  92. package/dist/esm/word/paragraph-properties.js +2 -2
  93. package/dist/esm/word/run-properties.d.ts +5 -2
  94. package/dist/esm/word/run-properties.js +13 -8
  95. package/dist/esm/word/styles-parser.d.ts +2 -1
  96. package/dist/esm/word/styles-parser.js +12 -12
  97. package/dist/esm/word/table-parser.js +6 -3
  98. package/dist/esm/word/theme-fonts.d.ts +10 -0
  99. package/dist/esm/word/theme-fonts.js +28 -0
  100. package/package.json +1 -1
  101. /package/dist/esm/{pdf-reader → core}/png-encode.d.ts +0 -0
@@ -1532,6 +1532,34 @@ var FILL_TAGS = new Set([
1532
1532
  "a:pattFill",
1533
1533
  "a:grpFill"
1534
1534
  ]);
1535
+ function emptyGradient(node) {
1536
+ return poIs(node, "a:gradFill") && !poChildren(node).some((c) => poIs(c, "a:gsLst"));
1537
+ }
1538
+ /**
1539
+ * The fill with the direction the SHAPE states, where it states one and no
1540
+ * colours: §20.1.8.33's `a:gradFill` holding only an `a:lin` says "sweep the
1541
+ * gallery style's run of colours this way". 63200.pptx's ellipse asks for the
1542
+ * diagonal where the theme's slot sweeps straight down.
1543
+ *
1544
+ * @param fill The fill resolved from the style (or anywhere else).
1545
+ * @param spPr The shape's own properties.
1546
+ * @returns The fill, turned; unchanged when the shape states no bare direction.
1547
+ */
1548
+ function withStatedDirection(fill, spPr) {
1549
+ const gradient = fill.kind === "gradient" ? fill.gradient : void 0;
1550
+ if (gradient === void 0 || gradient.kind !== "linear" || spPr === void 0) return fill;
1551
+ const grad = poChildren(spPr).find((c) => emptyGradient(c));
1552
+ const lin = grad ? poChildren(grad).find((c) => poIs(c, "a:lin")) : void 0;
1553
+ const ang = lin ? poIntAttr(lin, "ang") : void 0;
1554
+ if (ang === void 0) return fill;
1555
+ return {
1556
+ ...fill,
1557
+ gradient: {
1558
+ ...gradient,
1559
+ angle: ang / 6e4 % 360
1560
+ }
1561
+ };
1562
+ }
1535
1563
  /**
1536
1564
  * Whether an `spPr` states a fill AT ALL — including `a:noFill`, which is a
1537
1565
  * shape saying it has none rather than saying nothing. A placeholder that says
@@ -1541,7 +1569,7 @@ var FILL_TAGS = new Set([
1541
1569
  * @returns Whether a fill element is present.
1542
1570
  */
1543
1571
  function statesFill(spPr) {
1544
- return spPr !== void 0 && poChildren(spPr).some((c) => FILL_TAGS.has(poTag(c) ?? ""));
1572
+ return spPr !== void 0 && poChildren(spPr).some((c) => FILL_TAGS.has(poTag(c) ?? "") && !emptyGradient(c));
1545
1573
  }
1546
1574
  function styleRefFill(style, resolveColor, themeStyles) {
1547
1575
  const ref = poChildren(style).find((c) => poIs(c, "a:fillRef"));
@@ -1818,7 +1846,10 @@ function fillFromNode(child, resolveColor, resolveImage) {
1818
1846
  const crop = parseSrcRect(poFindDescendant(child, "a:srcRect")) ?? fillRectCrop(child);
1819
1847
  const rect = fillRectBox(child);
1820
1848
  const duotone = blip ? duotoneOf(blip, resolveColor) : void 0;
1821
- const tiled = poChildren(child).some((c) => poIs(c, "a:tile"));
1849
+ const tile = poChildren(child).find((c) => poIs(c, "a:tile"));
1850
+ const stretched = poChildren(child).some((c) => poIs(c, "a:stretch"));
1851
+ const tiled = tile !== void 0 || !stretched;
1852
+ const tileScale = tile ? tileScaleOf(tile) : void 0;
1822
1853
  const fixed = blip ? poChildren(blip).find((c) => poIs(c, "a:alphaModFix")) : void 0;
1823
1854
  const amt = fixed ? poIntAttr(fixed, "amt") : void 0;
1824
1855
  const alpha = amt === void 0 ? void 0 : Math.min(1, Math.max(0, amt / 1e5));
@@ -1826,6 +1857,7 @@ function fillFromNode(child, resolveColor, resolveImage) {
1826
1857
  kind: "picture",
1827
1858
  imageResource: resource,
1828
1859
  ...tiled ? { tiled: true } : {},
1860
+ ...tileScale ? { tileScale } : {},
1829
1861
  ...crop ? { imageCrop: crop } : {},
1830
1862
  ...rect ? { imageFillRect: rect } : {},
1831
1863
  ...duotone ? { duotone } : {},
@@ -1978,6 +2010,10 @@ function nodeAlpha(color) {
1978
2010
  * @returns The pair, or `undefined` when the blip states no duotone.
1979
2011
  */
1980
2012
  function duotoneOf(blip, resolveColor) {
2013
+ if (poChildren(blip).some((c) => poIs(c, "a:grayscl"))) return {
2014
+ shadowHex: "000000",
2015
+ highlightHex: "FFFFFF"
2016
+ };
1981
2017
  const duotone = poChildren(blip).find((c) => poIs(c, "a:duotone"));
1982
2018
  if (!duotone) return void 0;
1983
2019
  const [shadowHex, highlightHex] = poChildren(duotone).map((c) => resolveColorNode(c, resolveColor)).filter((hex) => hex !== void 0);
@@ -1997,6 +2033,18 @@ function duotoneOf(blip, resolveColor) {
1997
2033
  * @returns The rect as fractions of the box, or `undefined` when every inset
1998
2034
  * is zero or negative.
1999
2035
  */
2036
+ function tileScaleOf(tile) {
2037
+ const pct = (name) => {
2038
+ const v = poIntAttr(tile, name);
2039
+ return v === void 0 || v <= 0 ? 1 : v / 1e5;
2040
+ };
2041
+ const sx = pct("sx");
2042
+ const sy = pct("sy");
2043
+ return sx === 1 && sy === 1 ? void 0 : {
2044
+ sx,
2045
+ sy
2046
+ };
2047
+ }
2000
2048
  function fillRectBox(blipFill) {
2001
2049
  const stretch = poChildren(blipFill).find((c) => poIs(c, "a:stretch"));
2002
2050
  const rect = stretch ? poChildren(stretch).find((c) => poIs(c, "a:fillRect")) : void 0;
@@ -2047,14 +2095,15 @@ function shadowFromOuterShdw(shdw, resolveColor) {
2047
2095
  const colorHex = colorNode ? resolveColorNode(colorNode, resolveColor) : void 0;
2048
2096
  if (!colorHex) return void 0;
2049
2097
  const alphaMod = colorNode ? readColorMods(colorNode).find((m) => m.kind === "alpha") : void 0;
2098
+ const alpha = alphaMod ? alphaMod.val : 1;
2050
2099
  const dist = emuToPt(poIntAttr(shdw, "dist") ?? 0);
2051
2100
  const rad = (poIntAttr(shdw, "dir") ?? 0) / 6e4 * Math.PI / 180;
2052
2101
  return {
2053
2102
  dxPt: dist * Math.cos(rad),
2054
2103
  dyPt: dist * Math.sin(rad),
2055
2104
  blurPt: emuToPt(poIntAttr(shdw, "blurRad") ?? 0),
2056
- colorHex,
2057
- alpha: alphaMod ? alphaMod.val : 1
2105
+ colorHex: alpha < 1 ? unblendWhite(colorHex, alpha) : colorHex,
2106
+ alpha
2058
2107
  };
2059
2108
  }
2060
2109
  /**
@@ -2203,25 +2252,21 @@ function colorFromContainer(parent, resolveColor) {
2203
2252
  /**
2204
2253
  * §20.1.2.3.1 — a gradient's stop transparencies, settled.
2205
2254
  *
2206
- * A page paints a gradient at ONE transparency, so only a gradient whose every
2207
- * stop is translucent can carry it: the strongest stop decides whether the
2208
- * shape is there at all, which is the question a 7%-and-fading glow asks
2209
- * (tdf123684's master draws one over a dark slide, and composited over the
2210
- * paper instead it was an opaque white disc).
2255
+ * The resolver composites a translucent colour over the PAPER, because a solid
2256
+ * fill has nowhere else to put the transparency. A gradient does: its stops
2257
+ * become a luminosity soft mask of the same sweep (§11.6.5.2,
2258
+ * `buildGradientAlphaMask`), so each stop keeps its own alpha and its own
2259
+ * colour, and the mask decides what shows through.
2211
2260
  *
2212
- * A gradient that mixes a translucent stop with an opaque one has no such
2213
- * answer, so it keeps the colours the resolver already washed toward the paper
2214
- * — an approximation, but the one that has always been drawn: smartart-simple's
2215
- * cyan-to-purple sweep sets 75% on its purple end alone.
2261
+ * That means the washing has to be undone here, on every stop — including the
2262
+ * opaque ones, where undoing it is a no-op. It used to be undone only when
2263
+ * EVERY stop was translucent, on the reasoning that a page paints a gradient at
2264
+ * one transparency; the mask makes that false, and the cost of the old reading
2265
+ * was a band that should have been half-transparent over a blue slide drawn as
2266
+ * an opaque pale stripe (45541's layout fades the middle of its left rule to
2267
+ * 50 %).
2216
2268
  */
2217
2269
  function normalizeStopAlpha(stops) {
2218
- if (gradientAlpha(stops) === void 0) {
2219
- for (const [i, s] of stops.entries()) if (s.alpha !== void 0) stops[i] = {
2220
- offset: s.offset,
2221
- colorHex: s.colorHex
2222
- };
2223
- return;
2224
- }
2225
2270
  for (const [i, s] of stops.entries()) stops[i] = {
2226
2271
  ...s,
2227
2272
  colorHex: unblendWhite(s.colorHex, s.alpha ?? 1)
@@ -2274,7 +2319,7 @@ function parseGradient(grad, resolveColor) {
2274
2319
  return {
2275
2320
  kind: "radial",
2276
2321
  stops,
2277
- ...poAttr(path, "path") === "rect" ? { sweep: "rect" } : {},
2322
+ ...poAttr(path, "path") === "rect" || poAttr(path, "path") === "shape" ? { sweep: "rect" } : {},
2278
2323
  ...center ? { center } : {}
2279
2324
  };
2280
2325
  }
@@ -2290,4 +2335,4 @@ function clampUnit(x) {
2290
2335
  return x < 0 ? 0 : x > 1 ? 1 : x;
2291
2336
  }
2292
2337
  //#endregion
2293
- export { colorChangeOf, expandMcChildren, parseCustGeom, parseDrawing, parseFill, parseLine, parsePrstGeom, parseShadow, parseVmlPicture, parseXfrm, shadowFromOuterShdw, statesFill, styleRefFill, styleRefFontColor, styleRefLine, vmlFill };
2338
+ export { colorChangeOf, expandMcChildren, parseCustGeom, parseDrawing, parseFill, parseLine, parsePrstGeom, parseShadow, parseSrcRect, parseVmlPicture, parseXfrm, shadowFromOuterShdw, statesFill, styleRefFill, styleRefFontColor, styleRefLine, vmlFill, withStatedDirection };
@@ -1,5 +1,6 @@
1
1
  import { Numbering } from '../core/document-model/index.js';
2
2
  import { ResourceId } from '../core/ir/index.js';
3
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
3
4
  /** The empty {@link Numbering} returned when a document has no `numbering.xml`. */
4
5
  export declare const EMPTY_NUMBERING: Numbering;
5
6
  /**
@@ -12,4 +13,4 @@ export declare const EMPTY_NUMBERING: Numbering;
12
13
  * @param data The raw `numbering.xml` bytes.
13
14
  * @returns The parsed numbering, or {@link EMPTY_NUMBERING} when the root is absent.
14
15
  */
15
- export declare function parseNumbering(data: Uint8Array, resolveImage?: (relId: string) => ResourceId | undefined): Numbering;
16
+ export declare function parseNumbering(data: Uint8Array, resolveImage?: (relId: string) => ResourceId | undefined, themeFonts?: ThemeFonts): Numbering;
@@ -56,7 +56,7 @@ var EMPTY_NUMBERING = {
56
56
  * @param data The raw `numbering.xml` bytes.
57
57
  * @returns The parsed numbering, or {@link EMPTY_NUMBERING} when the root is absent.
58
58
  */
59
- function parseNumbering(data, resolveImage) {
59
+ function parseNumbering(data, resolveImage, themeFonts) {
60
60
  const xml = decoder.decode(data);
61
61
  const root = asElement(parser.parse(xml)["w:numbering"]);
62
62
  if (!root) return EMPTY_NUMBERING;
@@ -69,7 +69,7 @@ function parseNumbering(data, resolveImage) {
69
69
  if (!id) continue;
70
70
  const levels = /* @__PURE__ */ new Map();
71
71
  for (const lvlNode of asArray(el["w:lvl"])) {
72
- const lvl = parseLevel(lvlNode, picBullets);
72
+ const lvl = parseLevel(lvlNode, picBullets, themeFonts);
73
73
  if (lvl) levels.set(lvl.ilvl, lvl);
74
74
  }
75
75
  abstractNums.set(id, {
@@ -94,7 +94,7 @@ function parseNumbering(data, resolveImage) {
94
94
  if (!Number.isFinite(ilvl)) continue;
95
95
  const start = Number(getValVal(ovr["w:startOverride"]));
96
96
  if (Number.isFinite(start)) startOverrides.set(ilvl, start);
97
- const lvl = parseLevel(ovr["w:lvl"], picBullets);
97
+ const lvl = parseLevel(ovr["w:lvl"], picBullets, themeFonts);
98
98
  if (lvl) levelOverrides.set(ilvl, lvl);
99
99
  }
100
100
  numInstances.set(numId, {
@@ -109,7 +109,7 @@ function parseNumbering(data, resolveImage) {
109
109
  numInstances
110
110
  };
111
111
  }
112
- function parseLevel(node, picBullets) {
112
+ function parseLevel(node, picBullets, themeFonts) {
113
113
  const lvlEl = asElement(node);
114
114
  if (!lvlEl) return void 0;
115
115
  const ilvlStr = getAttr(lvlEl, "ilvl");
@@ -131,8 +131,8 @@ function parseLevel(node, picBullets) {
131
131
  lvlText,
132
132
  ...isLegal ? { isLegal: true } : {},
133
133
  ...picBullet ? { picBullet } : {},
134
- paragraphProperties: parseParagraphProperties(lvlEl["w:pPr"]),
135
- runProperties: parseRunProperties(lvlEl["w:rPr"])
134
+ paragraphProperties: parseParagraphProperties(lvlEl["w:pPr"], 0, themeFonts),
135
+ runProperties: parseRunProperties(lvlEl["w:rPr"], themeFonts)
136
136
  };
137
137
  }
138
138
  function parsePicBullets(root, resolveImage) {
@@ -1,4 +1,5 @@
1
1
  import { ParagraphProperties } from '../core/document-model/index.js';
2
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
2
3
  /**
3
4
  * §17.3.1.1/§17.3.1.3 — the gap `w:*Autospacing` asks the consumer for. Word's
4
5
  * own automatic value is HTML's 14pt, and only a document old enough to state
@@ -19,4 +20,4 @@ export declare const HTML_AUTO_SPACING_PT = 14;
19
20
  * compatibility mode, and 0 (the default) for every Word 2007-or-later one.
20
21
  * @returns The extracted properties; an empty object when `pPr` is absent.
21
22
  */
22
- export declare function parseParagraphProperties(pPr: unknown, autoSpacingPt?: number): ParagraphProperties;
23
+ export declare function parseParagraphProperties(pPr: unknown, autoSpacingPt?: number, themeFonts?: ThemeFonts): ParagraphProperties;
@@ -104,7 +104,7 @@ function parseFramePr(node) {
104
104
  * compatibility mode, and 0 (the default) for every Word 2007-or-later one.
105
105
  * @returns The extracted properties; an empty object when `pPr` is absent.
106
106
  */
107
- function parseParagraphProperties(pPr, autoSpacingPt = 0) {
107
+ function parseParagraphProperties(pPr, autoSpacingPt = 0, themeFonts) {
108
108
  const el = asElement(pPr);
109
109
  if (!el) return {};
110
110
  const out = {};
@@ -197,7 +197,7 @@ function parseParagraphProperties(pPr, autoSpacingPt = 0) {
197
197
  }
198
198
  }
199
199
  if ("w:rPr" in el) {
200
- const rPr = parseRunProperties(el["w:rPr"]);
200
+ const rPr = parseRunProperties(el["w:rPr"], themeFonts);
201
201
  if (Object.keys(rPr).length > 0) out.runProperties = rPr;
202
202
  }
203
203
  return out;
@@ -1,4 +1,5 @@
1
1
  import { RunProperties } from '../core/document-model/index.js';
2
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
2
3
  /**
3
4
  * Parse a run-properties element (`w:rPr`, ECMA-376 Part 1 §17.3.2) into the
4
5
  * typed {@link RunProperties}. Reads the character formatting the renderer needs:
@@ -6,7 +7,9 @@ import { RunProperties } from '../core/document-model/index.js';
6
7
  * font family map, vertical alignment, RTL, and language; sizes convert from
7
8
  * half-points to points and colours normalize to uppercase hex.
8
9
  *
9
- * @param rPr The flat-tree `w:rPr` element (or `undefined`/non-element).
10
+ * @param rPr The flat-tree `w:rPr` element (or `undefined`/non-element).
11
+ * @param themeFonts The document theme's font scheme, for the fonts a run names
12
+ * by slot rather than by name (§17.3.2.26 `w:asciiTheme`).
10
13
  * @returns The parsed properties; an empty object when `rPr` is absent.
11
14
  */
12
- export declare function parseRunProperties(rPr: unknown): RunProperties;
15
+ export declare function parseRunProperties(rPr: unknown, themeFonts?: ThemeFonts): RunProperties;
@@ -1,5 +1,7 @@
1
1
  import { halfPtToPt, twipsToPt } from "../core/ir/units.js";
2
+ import { resolveThemeFont } from "../core/drawingml/theme-parser.js";
2
3
  import { asElement, getAttr, getVal, parseHalfPointAttr, parseToggle } from "./xml-helpers.js";
4
+ import { resolveWordThemeFont } from "./theme-fonts.js";
3
5
  import { shadingFillHex } from "./shading.js";
4
6
  //#region src/word/run-properties.ts
5
7
  var UNDERLINE_STYLES = new Set([
@@ -43,10 +45,12 @@ var HIGHLIGHT_COLORS = new Map([
43
45
  * font family map, vertical alignment, RTL, and language; sizes convert from
44
46
  * half-points to points and colours normalize to uppercase hex.
45
47
  *
46
- * @param rPr The flat-tree `w:rPr` element (or `undefined`/non-element).
48
+ * @param rPr The flat-tree `w:rPr` element (or `undefined`/non-element).
49
+ * @param themeFonts The document theme's font scheme, for the fonts a run names
50
+ * by slot rather than by name (§17.3.2.26 `w:asciiTheme`).
47
51
  * @returns The parsed properties; an empty object when `rPr` is absent.
48
52
  */
49
- function parseRunProperties(rPr) {
53
+ function parseRunProperties(rPr, themeFonts) {
50
54
  const el = asElement(rPr);
51
55
  if (!el) return {};
52
56
  const out = {};
@@ -90,7 +94,7 @@ function parseRunProperties(rPr) {
90
94
  else if (v === "auto") out.colorHex = "000000";
91
95
  }
92
96
  if ("w:rFonts" in el) {
93
- const ff = parseFontFamily(el["w:rFonts"]);
97
+ const ff = parseFontFamily(el["w:rFonts"], themeFonts);
94
98
  if (ff) out.fontFamily = ff;
95
99
  }
96
100
  if ("w:vertAlign" in el) {
@@ -121,12 +125,13 @@ function parseRunProperties(rPr) {
121
125
  }
122
126
  return out;
123
127
  }
124
- function parseFontFamily(node) {
128
+ function parseFontFamily(node, themeFonts) {
125
129
  const ff = {};
126
- const ascii = getAttr(node, "ascii");
127
- const hAnsi = getAttr(node, "hAnsi");
128
- const cs = getAttr(node, "cs");
129
- const eastAsia = getAttr(node, "eastAsia");
130
+ const slot = (literal, theme) => resolveThemeFont(getAttr(node, literal), themeFonts) ?? resolveWordThemeFont(getAttr(node, theme), themeFonts);
131
+ const ascii = slot("ascii", "asciiTheme");
132
+ const hAnsi = slot("hAnsi", "hAnsiTheme");
133
+ const cs = slot("cs", "cstheme");
134
+ const eastAsia = slot("eastAsia", "eastAsiaTheme");
130
135
  if (ascii) ff.ascii = ascii;
131
136
  if (hAnsi) ff.hAnsi = hAnsi;
132
137
  if (cs) ff.cs = cs;
@@ -1,4 +1,5 @@
1
1
  import { StyleSheet } from '../core/document-model/index.js';
2
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
2
3
  /**
3
4
  * Parse `word/styles.xml` (ECMA-376 Part 1 §17.7) into a {@link StyleSheet}: the
4
5
  * document defaults (`w:docDefaults` run/paragraph properties) plus the named
@@ -9,4 +10,4 @@ import { StyleSheet } from '../core/document-model/index.js';
9
10
  * @param stylesXml The raw `styles.xml` bytes.
10
11
  * @returns The parsed stylesheet, or `EMPTY_STYLE_SHEET` when the root is absent.
11
12
  */
12
- export declare function parseStyles(stylesXml: Uint8Array): StyleSheet;
13
+ export declare function parseStyles(stylesXml: Uint8Array, themeFonts?: ThemeFonts): StyleSheet;
@@ -32,7 +32,7 @@ var STYLE_TYPES = new Set([
32
32
  * @param stylesXml The raw `styles.xml` bytes.
33
33
  * @returns The parsed stylesheet, or `EMPTY_STYLE_SHEET` when the root is absent.
34
34
  */
35
- function parseStyles(stylesXml) {
35
+ function parseStyles(stylesXml, themeFonts) {
36
36
  const xml = decoder.decode(stylesXml);
37
37
  const root = asElement(parser.parse(xml)["w:styles"]);
38
38
  if (!root) return EMPTY_STYLE_SHEET;
@@ -41,9 +41,9 @@ function parseStyles(stylesXml) {
41
41
  let defaultParagraphProperties = {};
42
42
  if (docDefaults) {
43
43
  const rPrDef = asElement(docDefaults["w:rPrDefault"]);
44
- if (rPrDef) defaultRunProperties = parseRunProperties(rPrDef["w:rPr"]);
44
+ if (rPrDef) defaultRunProperties = parseRunProperties(rPrDef["w:rPr"], themeFonts);
45
45
  const pPrDef = asElement(docDefaults["w:pPrDefault"]);
46
- if (pPrDef) defaultParagraphProperties = parseParagraphProperties(pPrDef["w:pPr"]);
46
+ if (pPrDef) defaultParagraphProperties = parseParagraphProperties(pPrDef["w:pPr"], 0, themeFonts);
47
47
  }
48
48
  const styles = /* @__PURE__ */ new Map();
49
49
  for (const s of asArray(root["w:style"])) {
@@ -61,9 +61,9 @@ function parseStyles(stylesXml) {
61
61
  type,
62
62
  ...basedOnVal ? { basedOn: basedOnVal } : {},
63
63
  isDefault,
64
- runProperties: parseRunProperties(el["w:rPr"]),
65
- paragraphProperties: parseParagraphProperties(el["w:pPr"]),
66
- ...type === "table" ? parseTableStyleParts(el) : {}
64
+ runProperties: parseRunProperties(el["w:rPr"], themeFonts),
65
+ paragraphProperties: parseParagraphProperties(el["w:pPr"], 0, themeFonts),
66
+ ...type === "table" ? parseTableStyleParts(el, themeFonts) : {}
67
67
  };
68
68
  styles.set(id, style);
69
69
  }
@@ -88,9 +88,9 @@ var CONDITION_TYPES = new Set([
88
88
  "swCell",
89
89
  "seCell"
90
90
  ]);
91
- function parseTableStyleParts(el) {
91
+ function parseTableStyleParts(el, themeFonts) {
92
92
  const out = {};
93
- const base = parseTableStyleLayer(el);
93
+ const base = parseTableStyleLayer(el, themeFonts);
94
94
  if (base) out.tableLayer = base;
95
95
  const tblPr = asElement(el["w:tblPr"]);
96
96
  if (tblPr) {
@@ -105,7 +105,7 @@ function parseTableStyleParts(el) {
105
105
  if (!cond) continue;
106
106
  const typeAttr = getAttr(cond, "type");
107
107
  if (!typeAttr || !CONDITION_TYPES.has(typeAttr)) continue;
108
- const layer = parseTableStyleLayer(cond);
108
+ const layer = parseTableStyleLayer(cond, themeFonts);
109
109
  if (layer) conditions.push({
110
110
  type: typeAttr,
111
111
  layer
@@ -114,7 +114,7 @@ function parseTableStyleParts(el) {
114
114
  if (conditions.length > 0) out.tableConditions = conditions;
115
115
  return out;
116
116
  }
117
- function parseTableStyleLayer(el) {
117
+ function parseTableStyleLayer(el, themeFonts) {
118
118
  const tblPr = asElement(el["w:tblPr"]);
119
119
  const tcPr = asElement(el["w:tcPr"]);
120
120
  const borders = parseFlatBorders(tblPr ? asElement(tblPr["w:tblBorders"]) : void 0) ?? parseFlatBorders(tcPr ? asElement(tcPr["w:tcBorders"]) : void 0);
@@ -124,8 +124,8 @@ function parseTableStyleLayer(el) {
124
124
  const indType = tblInd ? getAttr(tblInd, "type") : void 0;
125
125
  const indentPt = indW !== void 0 && (indType === void 0 || indType === "dxa") ? twipsToPt(indW) : void 0;
126
126
  const shading = parseFlatShading(tcPr ? tcPr["w:shd"] : void 0);
127
- const runProperties = parseRunProperties(el["w:rPr"]);
128
- const paragraphProperties = parseParagraphProperties(el["w:pPr"]);
127
+ const runProperties = parseRunProperties(el["w:rPr"], themeFonts);
128
+ const paragraphProperties = parseParagraphProperties(el["w:pPr"], 0, themeFonts);
129
129
  const layer = {
130
130
  ...borders ? { borders } : {},
131
131
  ...cellMargins ? { cellMargins } : {},
@@ -115,11 +115,11 @@ function parseTable(tbl, ctx = DEFAULT_PARSE_CONTEXT) {
115
115
  function poChildrenThroughSdt(node, tag) {
116
116
  return childrenThroughSdt(node, tag).map((c) => c.node);
117
117
  }
118
- function childrenThroughSdt(node, tag) {
118
+ function childrenThroughSdt(node, tag, themeFonts) {
119
119
  const out = [];
120
120
  for (const child of poChildren(node)) if (poIs(child, tag)) out.push({ node: child });
121
121
  else if (poIs(child, "w:sdt")) {
122
- const props = sdtRunProperties(child);
122
+ const props = sdtRunProperties(child, themeFonts);
123
123
  for (const inner of poChildrenWith(poFirstChild(child, "w:sdtContent"), tag)) out.push({
124
124
  node: inner,
125
125
  ...props ? { sdtRunProps: props } : {}
@@ -270,7 +270,7 @@ function isDeletedRow(tr) {
270
270
  function parseTableRow(tr, ctx) {
271
271
  const properties = parseRowProperties(poFirstChild(tr, "w:trPr"));
272
272
  const cells = [];
273
- for (const { node, sdtRunProps } of childrenThroughSdt(tr, "w:tc")) cells.push(parseTableCell(node, ctx, sdtRunProps));
273
+ for (const { node, sdtRunProps } of childrenThroughSdt(tr, "w:tc", ctx.themeFonts)) cells.push(parseTableCell(node, ctx, sdtRunProps));
274
274
  return {
275
275
  properties,
276
276
  cells
@@ -353,6 +353,9 @@ function parseCellProperties(tcPr) {
353
353
  }
354
354
  const vAlign = poVal(poFirstChild(tcPr, "w:vAlign"));
355
355
  if (vAlign === "center" || vAlign === "bottom" || vAlign === "top") out.verticalAlign = vAlign;
356
+ const dir = poVal(poFirstChild(tcPr, "w:textDirection"));
357
+ if (dir === "btLr" || dir === "tbLr") out.textDirection = "vert270";
358
+ else if (dir === "tbRl") out.textDirection = "vert";
356
359
  if (poFirstChild(tcPr, "w:hideMark")) out.hideMark = true;
357
360
  return {
358
361
  properties: out,
@@ -0,0 +1,10 @@
1
+ import { ThemeFonts } from '../core/drawingml/theme-parser.js';
2
+ /**
3
+ * Resolve a `w:rFonts` theme attribute to the typeface it stands for.
4
+ *
5
+ * @param value The attribute as written (`minorHAnsi`, `majorBidi`, …).
6
+ * @param fonts The theme's font scheme, when the part was read.
7
+ * @returns The typeface, or `undefined` for an unknown slot, a missing theme,
8
+ * or a slot the theme leaves empty.
9
+ */
10
+ export declare function resolveWordThemeFont(value: string | undefined, fonts: ThemeFonts | undefined): string | undefined;
@@ -0,0 +1,28 @@
1
+ //#region src/word/theme-fonts.ts
2
+ var THEME_SLOTS = new Map([
3
+ ["majorascii", ["major", "latin"]],
4
+ ["majorhansi", ["major", "latin"]],
5
+ ["majoreastasia", ["major", "ea"]],
6
+ ["majorbidi", ["major", "cs"]],
7
+ ["minorascii", ["minor", "latin"]],
8
+ ["minorhansi", ["minor", "latin"]],
9
+ ["minoreastasia", ["minor", "ea"]],
10
+ ["minorbidi", ["minor", "cs"]]
11
+ ]);
12
+ /**
13
+ * Resolve a `w:rFonts` theme attribute to the typeface it stands for.
14
+ *
15
+ * @param value The attribute as written (`minorHAnsi`, `majorBidi`, …).
16
+ * @param fonts The theme's font scheme, when the part was read.
17
+ * @returns The typeface, or `undefined` for an unknown slot, a missing theme,
18
+ * or a slot the theme leaves empty.
19
+ */
20
+ function resolveWordThemeFont(value, fonts) {
21
+ if (value === void 0 || !fonts) return void 0;
22
+ const slot = THEME_SLOTS.get(value.trim().toLowerCase());
23
+ if (!slot) return void 0;
24
+ const [which, script] = slot;
25
+ return fonts[which][script];
26
+ }
27
+ //#endregion
28
+ export { resolveWordThemeFont };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reamkit",
3
- "version": "1.22.0",
3
+ "version": "1.24.0",
4
4
  "description": "Ream — convert DOCX, XLSX, PPTX and PDF to PDF, SVG, HTML, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
5
5
  "license": "MIT",
6
6
  "author": "Alex Krassavin <info@reamkit.dev>",
File without changes