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
@@ -1,4 +1,8 @@
1
+ import { decodeBmp, isBmp } from "../../core/bmp.js";
2
+ import { encodePng } from "../../core/png-encode.js";
3
+ import { fromSymbolFont } from "../../core/metafile/symbol-fonts.js";
1
4
  import { isCfb, openCfb } from "../../core/ole/cfb.js";
5
+ import { readEscherBlip } from "../../core/ole/escher-blip.js";
2
6
  //#region src/pptx/ppt/ppt-text.ts
3
7
  var RT_DOCUMENT = 1e3;
4
8
  var RT_DOCUMENT_ATOM = 1001;
@@ -12,8 +16,13 @@ var RT_TEXT_HEADER_ATOM = 3999;
12
16
  var RT_TEXT_CHARS_ATOM = 4e3;
13
17
  var RT_STYLE_TEXT_PROP_ATOM = 4001;
14
18
  var RT_TEXT_BYTES_ATOM = 4008;
19
+ var RT_OUTLINE_TEXT_REF_ATOM = 3998;
20
+ var RT_TEXT_MASTER_STYLE_ATOM = 4003;
15
21
  var RT_SLIDE_ATOM = 1007;
16
22
  var RT_MAIN_MASTER = 1016;
23
+ var RT_ENVIRONMENT = 1010;
24
+ var RT_FONT_COLLECTION = 2005;
25
+ var RT_FONT_ENTITY_ATOM = 4023;
17
26
  var RT_COLOR_SCHEME_ATOM = 2032;
18
27
  var FBT_BSTORE_CONTAINER = 61441;
19
28
  var FBT_BSE = 61447;
@@ -22,9 +31,48 @@ var FBT_FSP = 61450;
22
31
  var FBT_OPT = 61451;
23
32
  var FBT_CLIENT_TEXTBOX = 61453;
24
33
  var FBT_CLIENT_ANCHOR = 61456;
34
+ var FBT_CLIENT_DATA = 61457;
35
+ var FBT_SPGR_CONTAINER = 61443;
36
+ var FBT_SPGR = 61449;
37
+ var FBT_CHILD_ANCHOR = 61455;
38
+ var RT_PLACEHOLDER_ATOM = 3011;
39
+ var RT_HEADERS_FOOTERS = 4057;
40
+ var RT_HEADERS_FOOTERS_ATOM = 4058;
41
+ var RT_CSTRING = 4026;
42
+ var HF_INSTANCE_PER_SLIDE = 0;
43
+ var HF_INSTANCE_SLIDES = 3;
44
+ var HF_HAS_DATE = 1;
45
+ var HF_HAS_USER_DATE = 4;
46
+ var HF_HAS_SLIDE_NUMBER = 8;
47
+ var HF_HAS_FOOTER = 32;
48
+ var PLACEHOLDER_DATE = 7;
49
+ var PLACEHOLDER_SLIDE_NUMBER = 8;
50
+ var PLACEHOLDER_FOOTER = 9;
51
+ var SCHEME_TEXT_AND_LINES = 1;
25
52
  var PROP_PIB = 260;
53
+ var PROP_CROP_TOP = 256;
54
+ var PROP_CROP_BOTTOM = 257;
55
+ var PROP_CROP_LEFT = 258;
56
+ var PROP_CROP_RIGHT = 259;
57
+ var PROP_PICTURE_TRANSPARENT = 263;
58
+ var PICTURE_TRANSPARENT_NONE = 4294967295;
59
+ var PROP_FILL_TYPE = 384;
26
60
  var PROP_FILL_COLOR = 385;
61
+ var PROP_FILL_BACK_COLOR = 387;
62
+ var PROP_FILL_ANGLE = 395;
63
+ var PROP_FILL_FOCUS = 396;
64
+ var PROP_FILL_BLIP = 390;
65
+ var PROP_GTEXT_UNICODE = 192;
66
+ var PROP_GTEXT_SIZE = 195;
67
+ var PROP_GTEXT_FONT = 197;
68
+ var PROP_FILL_WIDTH = 393;
69
+ var PROP_FILL_HEIGHT = 394;
70
+ var EMU_PER_POINT = 12700;
27
71
  var PROP_LINE_COLOR = 448;
72
+ var PROP_FILL_BOOLS = 447;
73
+ var PROP_LINE_BOOLS = 511;
74
+ var FILL_F_FILLED = 16;
75
+ var LINE_F_LINE = 8;
28
76
  var PROP_GEO_LEFT = 320;
29
77
  var PROP_GEO_TOP = 321;
30
78
  var PROP_GEO_RIGHT = 322;
@@ -37,8 +85,10 @@ var COLORREF_SCHEME_INDEX = 8;
37
85
  var COLORREF_SYS_INDEX = 16;
38
86
  var FBSE_FODELAY_OFFSET = 28;
39
87
  var FSP_FLAG_PATRIARCH = 4;
88
+ var FSP_FLAG_BACKGROUND = 1024;
40
89
  var TOKEN_ENCRYPTED = 4090610911;
41
90
  var SLWT_INSTANCE_SLIDES = 0;
91
+ var SLWT_INSTANCE_MASTERS = 1;
42
92
  var MAX_EDITS = 4096;
43
93
  var MAX_DEPTH = 24;
44
94
  function recordAt(stream, off) {
@@ -127,19 +177,19 @@ function extractPptContent(bytes) {
127
177
  };
128
178
  }
129
179
  function slideHasContent(s) {
130
- return s.shapes.some((sh) => shapeHasText(sh) || sh.image !== void 0 || sh.autoShape !== void 0);
180
+ return s.background !== void 0 || s.shapes.some((sh) => shapeHasText(sh) || sh.image !== void 0 || sh.autoShape !== void 0);
131
181
  }
132
182
  function shapeHasText(sh) {
133
183
  return sh.paragraphs?.some((p) => paragraphText(p).length > 0) ?? false;
134
184
  }
135
- function slideShapes(slideData, img, outline, scheme) {
136
- const shapes = collectShapes(slideData, img, scheme);
137
- if (!shapes.some(shapeHasText)) {
138
- const inline = collectParagraphs(slideData, 0);
139
- const text = inline.some((p) => paragraphText(p).length > 0) ? inline : outline;
140
- if (text.some((p) => paragraphText(p).length > 0)) shapes.push({ paragraphs: text });
185
+ function slideShapes(slideData, img, outline, env, defaults) {
186
+ const content = collectShapes(slideData, img, env, outline, defaults);
187
+ if (!content.shapes.some(shapeHasText)) {
188
+ const inline = collectParagraphs(slideData, 0, defaults, env);
189
+ const text = inline.some((p) => paragraphText(p).length > 0) ? inline : outline.flat();
190
+ if (text.some((p) => paragraphText(p).length > 0)) content.shapes.push({ paragraphs: text });
141
191
  }
142
- return shapes;
192
+ return content;
143
193
  }
144
194
  function buildPersistDirectory(stream, currentEditOffset) {
145
195
  const persist = /* @__PURE__ */ new Map();
@@ -178,42 +228,80 @@ function mergePersistDirectory(stream, offset, persist) {
178
228
  }
179
229
  }
180
230
  function readSlideList(stream, docData, persist, img) {
231
+ const fonts = parseFontCollection(docData);
181
232
  const slwt = findChild(docData, (r) => r.type === RT_SLIDE_LIST_WITH_TEXT && r.instance === SLWT_INSTANCE_SLIDES);
182
233
  if (!slwt) return [];
183
234
  const slides = [];
184
235
  let outline = [];
185
236
  let pendingRef;
237
+ const masters = {
238
+ persist,
239
+ stream,
240
+ byMasterId: buildMasterIdMap(docData),
241
+ cache: /* @__PURE__ */ new Map(),
242
+ documentStyles: parseDocumentTextStyles(docData, fonts)
243
+ };
244
+ const deckFurniture = headersFooters(docData, HF_INSTANCE_SLIDES);
186
245
  const flush = () => {
187
246
  if (pendingRef === void 0) return;
188
247
  const slideOff = persist.get(pendingRef);
189
248
  const slideRec = slideOff !== void 0 ? recordAt(stream, slideOff) : void 0;
190
- const shapes = slideRec !== void 0 && slideRec.type === RT_SLIDE ? slideShapes(slideRec.data, img, outline, resolveScheme(slideRec.data, persist, stream)) : outline.some((p) => paragraphText(p).length > 0) ? [{ paragraphs: outline }] : [];
191
- slides.push({ shapes });
249
+ const isSlide = slideRec !== void 0 && slideRec.type === RT_SLIDE;
250
+ const scheme = isSlide ? resolveScheme(slideRec.data, masters) : void 0;
251
+ const env = {
252
+ ...scheme ? { scheme } : {},
253
+ ...fonts.length > 0 ? { fonts } : {}
254
+ };
255
+ const defaults = isSlide ? masterChain(slideRec.data, masters, scheme, fonts) : void 0;
256
+ const texts = outline.map((e) => styledParagraphs(e.rec, e.style, levelStyles(defaults, e.textType), env));
257
+ const flat = texts.flat();
258
+ const content = isSlide ? slideShapes(slideRec.data, img, texts, env, defaults) : { shapes: flat.some((p) => paragraphText(p).length > 0) ? [{ paragraphs: flat }] : [] };
259
+ const background = isSlide ? masterBackground(slideRec.data, masters, img) ?? content.background : void 0;
260
+ const own = isSlide ? headersFooters(slideRec.data, HF_INSTANCE_PER_SLIDE) : void 0;
261
+ const furniture = own ?? deckFurniture ? {
262
+ ...own ?? deckFurniture,
263
+ number: slides.length + 1
264
+ } : void 0;
265
+ const decoration = isSlide ? masterShapes(slideRec.data, masters, img, furniture, defaults) : [];
266
+ slides.push({
267
+ shapes: [...decoration, ...content.shapes],
268
+ ...background ? { background } : {}
269
+ });
192
270
  outline = [];
193
271
  pendingRef = void 0;
194
272
  };
195
273
  const recs = [...records(slwt)];
274
+ let textType = TEXT_TYPE_OTHER;
196
275
  for (let i = 0; i < recs.length; i++) {
197
276
  const rec = recs[i];
198
277
  if (rec.type === RT_SLIDE_PERSIST_ATOM) {
199
278
  flush();
200
279
  pendingRef = rec.data.length >= 4 ? u32(rec.data, 0) : void 0;
201
- } else if (rec.type === RT_TEXT_CHARS_ATOM || rec.type === RT_TEXT_BYTES_ATOM) outline.push(...styledParagraphs(rec, findFollowingStyle(recs, i)));
280
+ } else if (rec.type === RT_TEXT_HEADER_ATOM) textType = rec.data.length >= 4 ? u32(rec.data, 0) : TEXT_TYPE_OTHER;
281
+ else if (rec.type === RT_TEXT_CHARS_ATOM || rec.type === RT_TEXT_BYTES_ATOM) outline.push({
282
+ textType,
283
+ rec,
284
+ style: findFollowingStyle(recs, i)
285
+ });
202
286
  }
203
287
  flush();
204
288
  return slides;
205
289
  }
206
- function collectParagraphs(d, depth) {
290
+ function collectParagraphs(d, depth, defaults, env) {
207
291
  if (depth > MAX_DEPTH) return [];
208
292
  const out = [];
209
293
  const recs = [...records(d)];
294
+ let textType = TEXT_TYPE_OTHER;
210
295
  for (let i = 0; i < recs.length; i++) {
211
296
  const rec = recs[i];
212
- if (rec.type === RT_TEXT_CHARS_ATOM || rec.type === RT_TEXT_BYTES_ATOM) out.push(...styledParagraphs(rec, findFollowingStyle(recs, i)));
213
- else if (rec.isContainer) out.push(...collectParagraphs(rec.data, depth + 1));
297
+ if (rec.type === RT_TEXT_HEADER_ATOM) textType = rec.data.length >= 4 ? u32(rec.data, 0) : TEXT_TYPE_OTHER;
298
+ else if (rec.type === RT_TEXT_CHARS_ATOM || rec.type === RT_TEXT_BYTES_ATOM) out.push(...styledParagraphs(rec, findFollowingStyle(recs, i), levelStyles(defaults, textType), env));
299
+ else if (rec.isContainer) out.push(...collectParagraphs(rec.data, depth + 1, defaults, env));
214
300
  }
215
301
  return out;
216
302
  }
303
+ var TEXT_TYPE_OTHER = 4;
304
+ var levelStyles = (defaults, textType) => defaults ? (level) => defaults(textType, level) : void 0;
217
305
  function findFollowingStyle(recs, i) {
218
306
  for (let j = i + 1; j < recs.length; j++) {
219
307
  const t = recs[j].type;
@@ -221,8 +309,8 @@ function findFollowingStyle(recs, i) {
221
309
  if (t === RT_TEXT_CHARS_ATOM || t === RT_TEXT_BYTES_ATOM || t === RT_TEXT_HEADER_ATOM) break;
222
310
  }
223
311
  }
224
- function styledParagraphs(textRec, styleData) {
225
- return buildStyledParagraphs(textRec.type === RT_TEXT_CHARS_ATOM ? decodeUtf16(textRec.data) : decodeCp1252(textRec.data), styleData);
312
+ function styledParagraphs(textRec, styleData, defaults, env) {
313
+ return buildStyledParagraphs(textRec.type === RT_TEXT_CHARS_ATOM ? decodeUtf16(textRec.data) : decodeCp1252(textRec.data), styleData, defaults, env);
226
314
  }
227
315
  function slidesByScan(stream, img) {
228
316
  const slides = [];
@@ -231,8 +319,14 @@ function slidesByScan(stream, img) {
231
319
  }
232
320
  function collectSlides(d, out, img, depth) {
233
321
  if (depth > MAX_DEPTH) return;
234
- for (const rec of records(d)) if (rec.type === RT_SLIDE) out.push({ shapes: slideShapes(rec.data, img, [], resolveScheme(rec.data)) });
235
- else if (rec.isContainer) collectSlides(rec.data, out, img, depth + 1);
322
+ for (const rec of records(d)) if (rec.type === RT_SLIDE) {
323
+ const scheme = resolveScheme(rec.data);
324
+ const content = slideShapes(rec.data, img, [], scheme ? { scheme } : {});
325
+ out.push({
326
+ shapes: content.shapes,
327
+ ...content.background ? { background: content.background } : {}
328
+ });
329
+ } else if (rec.isContainer) collectSlides(rec.data, out, img, depth + 1);
236
330
  }
237
331
  function findChild(d, pred) {
238
332
  for (const rec of records(d)) if (pred(rec)) return rec.data;
@@ -288,53 +382,500 @@ function findDescendantContainer(d, type, depth) {
288
382
  }
289
383
  }
290
384
  }
291
- function collectShapes(slideData, img, scheme) {
292
- const out = [];
293
- collectShapeContainers(slideData, img, out, 0, scheme);
385
+ function collectShapes(slideData, img, env, outline = [], defaults) {
386
+ const out = { shapes: [] };
387
+ collectShapeContainers(slideData, img, out, 0, env, outline, defaults);
294
388
  return out;
295
389
  }
296
- function collectShapeContainers(d, img, out, depth, scheme) {
390
+ function collectShapeContainers(d, img, out, depth, env, outline, defaults, group) {
391
+ const scheme = env.scheme;
297
392
  if (depth > MAX_DEPTH) return;
298
- for (const r of records(d)) if (r.type === FBT_SP_CONTAINER) {
299
- let rectPt;
300
- let paragraphs;
301
- let pib;
302
- let shapeType = 0;
303
- let fspFlags = 0;
304
- let fillColorHex;
305
- let lineColorHex;
306
- let geometry;
307
- for (const child of records(r.data)) if (child.type === FBT_FSP) {
308
- shapeType = child.instance;
309
- fspFlags = child.data.length >= 8 ? u32(child.data, 4) : 0;
310
- } else if (child.type === FBT_CLIENT_ANCHOR) rectPt = parseAnchor(child.data);
311
- else if (child.type === FBT_CLIENT_TEXTBOX) paragraphs = collectParagraphs(child.data, 0);
312
- else if (child.type === FBT_OPT) {
313
- pib = optProperty(child.data, child.instance, PROP_PIB);
314
- fillColorHex = optColor(child.data, child.instance, PROP_FILL_COLOR, scheme);
315
- lineColorHex = optColor(child.data, child.instance, PROP_LINE_COLOR, scheme);
316
- geometry = parseFreeformGeometry(child.data, child.instance);
393
+ for (const r of records(d)) {
394
+ if (r.type === FBT_SPGR_CONTAINER) {
395
+ collectShapeContainers(r.data, img, out, depth + 1, env, outline, defaults, groupFrame(r.data, group) ?? group);
396
+ continue;
317
397
  }
318
- let image;
319
- if (pib !== void 0 && pib >= 1 && pib <= img.foDelays.length) {
320
- const bytes = readBlipBytes(img.pictures, img.foDelays[pib - 1]);
321
- if (bytes) image = { bytes };
398
+ if (r.type === FBT_SP_CONTAINER) {
399
+ let rectPt;
400
+ let paragraphs;
401
+ let pib;
402
+ let shapeType = 0;
403
+ let fspFlags = 0;
404
+ let fillColorHex;
405
+ let backColorHex;
406
+ let lineColorHex;
407
+ let gradient;
408
+ let geometry;
409
+ let fillType;
410
+ let fillBlip;
411
+ let inlineFill;
412
+ let inlinePic;
413
+ let tileSizePt;
414
+ let gtext;
415
+ let placeholder = false;
416
+ let placeholderId;
417
+ let pictureCrop;
418
+ let pictureTransparentHex;
419
+ for (const child of records(r.data)) if (child.type === FBT_FSP) {
420
+ shapeType = child.instance;
421
+ fspFlags = child.data.length >= 8 ? u32(child.data, 4) : 0;
422
+ } else if (child.type === FBT_CLIENT_ANCHOR) rectPt = parseAnchor(child.data);
423
+ else if (child.type === FBT_CHILD_ANCHOR && group) rectPt = childRect(child.data, group);
424
+ else if (child.type === FBT_CLIENT_DATA) {
425
+ const ph = findChild(child.data, (c) => c.type === RT_PLACEHOLDER_ATOM);
426
+ placeholder = ph !== void 0;
427
+ placeholderId = ph !== void 0 && ph.length > 4 ? ph[4] : void 0;
428
+ } else if (child.type === FBT_CLIENT_TEXTBOX) paragraphs = clientTextboxParagraphs(child.data, outline, defaults, env);
429
+ else if (child.type === FBT_OPT) {
430
+ pib = optProperty(child.data, child.instance, PROP_PIB);
431
+ fillColorHex = stated(child.data, child.instance, PROP_FILL_BOOLS, FILL_F_FILLED) ? optColor(child.data, child.instance, PROP_FILL_COLOR, scheme) : void 0;
432
+ lineColorHex = stated(child.data, child.instance, PROP_LINE_BOOLS, LINE_F_LINE) ? optColor(child.data, child.instance, PROP_LINE_COLOR, scheme) : void 0;
433
+ gradient = parseFillGradient(child.data, child.instance, fillColorHex, scheme);
434
+ geometry = parseFreeformGeometry(child.data, child.instance);
435
+ fillType = optProperty(child.data, child.instance, PROP_FILL_TYPE);
436
+ fillBlip = optProperty(child.data, child.instance, PROP_FILL_BLIP);
437
+ backColorHex = optColor(child.data, child.instance, PROP_FILL_BACK_COLOR, scheme);
438
+ tileSizePt = parseTileSize(child.data, child.instance);
439
+ gtext = parseWordArt(child.data, child.instance, fillColorHex);
440
+ inlineFill = optComplex(child.data, child.instance, PROP_FILL_BLIP);
441
+ inlinePic = optComplex(child.data, child.instance, PROP_PIB);
442
+ pictureCrop = parsePictureCrop(child.data, child.instance);
443
+ const transparent = optProperty(child.data, child.instance, PROP_PICTURE_TRANSPARENT);
444
+ pictureTransparentHex = transparent !== void 0 && transparent !== PICTURE_TRANSPARENT_NONE ? optColor(child.data, child.instance, PROP_PICTURE_TRANSPARENT, scheme) : void 0;
445
+ }
446
+ const blip = (index) => {
447
+ if (index === void 0 || index < 1 || index > img.foDelays.length) return void 0;
448
+ const bytes = readBlipBytes(img.pictures, img.foDelays[index - 1]);
449
+ return bytes ? { bytes } : void 0;
450
+ };
451
+ const pattern = fillType === 1 ? patternFill(blip(fillBlip) ?? inlineBlip(inlineFill), fillColorHex, backColorHex) : void 0;
452
+ const tiled = fillType === 2 || pattern !== void 0;
453
+ const fillImage = pattern ?? (fillType === 2 || fillType === 3 ? blip(fillBlip) ?? inlineBlip(inlineFill) : void 0);
454
+ if (pattern) tileSizePt = PATTERN_TILE_PT;
455
+ if ((fspFlags & FSP_FLAG_BACKGROUND) !== 0) {
456
+ const bg = slideBackground(fillColorHex, gradient, fillType, fillImage, tiled);
457
+ if (bg && !out.background) out.background = bg;
458
+ continue;
459
+ }
460
+ const picture = blip(pib) ?? inlineBlip(inlinePic);
461
+ const image = picture ? {
462
+ ...picture,
463
+ ...pictureCrop ? { crop: pictureCrop } : {},
464
+ ...pictureTransparentHex !== void 0 ? { transparentHex: pictureTransparentHex } : {}
465
+ } : void 0;
466
+ const textParas = gtext ?? (paragraphs?.some((p) => paragraphText(p).length > 0) === true ? paragraphs : void 0) ? gtext ? [gtext] : paragraphs : void 0;
467
+ const decorative = (fspFlags & (FSP_FLAG_PATRIARCH | 1025)) === 0;
468
+ const autoShape = !gtext && !image && rectPt && (shapeType > 0 || geometry) && decorative && (fillColorHex || lineColorHex || fillImage) ? {
469
+ shapeType,
470
+ ...fillColorHex ? { fillColorHex } : {},
471
+ ...lineColorHex ? { lineColorHex } : {},
472
+ ...gradient ? { gradient } : {},
473
+ ...fillImage ? { image: fillImage } : {},
474
+ ...fillImage && tiled ? { imageTiled: true } : {},
475
+ ...fillImage && tiled && tileSizePt ? { tileSizePt } : {},
476
+ ...geometry ? { geometry } : {}
477
+ } : void 0;
478
+ if (textParas || image || autoShape || placeholderId === PLACEHOLDER_DATE || placeholderId === PLACEHOLDER_SLIDE_NUMBER || placeholderId === PLACEHOLDER_FOOTER) out.shapes.push({
479
+ ...rectPt ? { rectPt } : {},
480
+ ...gtext ? { wordArt: true } : {},
481
+ ...placeholder ? { placeholder: true } : {},
482
+ ...placeholderId !== void 0 ? { placeholderId } : {},
483
+ ...textParas ? { paragraphs: textParas } : {},
484
+ ...image ? { image } : {},
485
+ ...autoShape ? { autoShape } : {}
486
+ });
487
+ } else if (r.isContainer) collectShapeContainers(r.data, img, out, depth + 1, env, outline, defaults, group);
488
+ }
489
+ }
490
+ function parseFontCollection(docData) {
491
+ const out = [];
492
+ const coll = findDescendantContainer(docData, RT_FONT_COLLECTION, 0);
493
+ if (!coll) return out;
494
+ let ordinal = 0;
495
+ for (const rec of records(coll)) {
496
+ if (rec.type !== RT_FONT_ENTITY_ATOM || rec.data.length < 2) continue;
497
+ const index = rec.instance > 0 || ordinal === 0 ? rec.instance : ordinal;
498
+ let name = "";
499
+ for (let i = 0; i < 32 && i * 2 + 1 < rec.data.length; i++) {
500
+ const cu = u16(rec.data, i * 2);
501
+ if (cu === 0) break;
502
+ name += String.fromCharCode(cu);
322
503
  }
323
- const textParas = paragraphs && paragraphs.some((p) => paragraphText(p).length > 0) ? paragraphs : void 0;
324
- const decorative = (fspFlags & (FSP_FLAG_PATRIARCH | 1025)) === 0;
325
- const autoShape = !textParas && !image && rectPt && (shapeType > 0 || geometry) && decorative && (fillColorHex || lineColorHex) ? {
326
- shapeType,
327
- ...fillColorHex ? { fillColorHex } : {},
328
- ...lineColorHex ? { lineColorHex } : {},
329
- ...geometry ? { geometry } : {}
330
- } : void 0;
331
- if (textParas || image || autoShape) out.push({
332
- ...rectPt ? { rectPt } : {},
333
- ...textParas ? { paragraphs: textParas } : {},
334
- ...image ? { image } : {},
335
- ...autoShape ? { autoShape } : {}
504
+ out[index] = name;
505
+ ordinal++;
506
+ }
507
+ return out;
508
+ }
509
+ /**
510
+ * §2.9.3 — the DECK's own text styles, from the document's text info.
511
+ *
512
+ * A master states the styles its placeholders take; the style a TEXT BOX drawn
513
+ * on a slide takes — `Tx_TYPE_OTHER` — is stated once for the whole document
514
+ * and lives here instead. 38256.ppt's four captions are all of that kind, and
515
+ * without it they were set in the outline's 32pt Arial rather than the sizes
516
+ * and faces they were typed in.
517
+ *
518
+ * @param docData The DocumentContainer's body.
519
+ * @param fonts The deck's typefaces, by the index a run names.
520
+ * @returns The level styles, by text type — in practice the one for `other`.
521
+ */
522
+ function parseDocumentTextStyles(docData, fonts) {
523
+ const env = findDescendantContainer(docData, RT_ENVIRONMENT, 0);
524
+ return env ? parseMasterTextStyles(env, fonts) : /* @__PURE__ */ new Map();
525
+ }
526
+ function parseMasterTextStyles(masterData, fonts) {
527
+ const out = /* @__PURE__ */ new Map();
528
+ for (const rec of records(masterData)) {
529
+ if (rec.type !== RT_TEXT_MASTER_STYLE_ATOM || rec.data.length < 2) continue;
530
+ const levels = Math.min(u16(rec.data, 0), 5);
531
+ const first = readMasterLevels(rec.data, levels, rec.instance >= 4 ? 2 : 0, fonts);
532
+ const exact = (r) => r.styles.length === levels && r.off === rec.data.length;
533
+ let best = first;
534
+ if (!exact(first)) {
535
+ const other = readMasterLevels(rec.data, levels, rec.instance >= 4 ? 0 : 2, fonts);
536
+ if (exact(other)) best = other;
537
+ }
538
+ if (best.styles.length > 0) out.set(rec.instance, best.styles);
539
+ }
540
+ return out;
541
+ }
542
+ function readMasterLevels(d, levels, prefix, fonts) {
543
+ const styles = [];
544
+ let off = 2;
545
+ for (let i = 0; i < levels; i++) {
546
+ off += prefix;
547
+ if (off + 4 > d.length) break;
548
+ const pf = readPfException(d, off);
549
+ if (pf.off + 4 > d.length) break;
550
+ const cf = readCfException(d, pf.off, void 0, fonts);
551
+ if (cf.off > d.length) break;
552
+ off = cf.off;
553
+ styles.push({
554
+ ...cf.props,
555
+ ...pf.align !== void 0 ? { align: pf.align } : {},
556
+ ...pf.bullet !== void 0 ? { bullet: pf.bullet } : {},
557
+ ...pf.bulletOn !== void 0 ? { bulletOn: pf.bulletOn } : {},
558
+ ...pf.leftMarginPt !== void 0 ? { leftMarginPt: pf.leftMarginPt } : {},
559
+ ...pf.indentPt !== void 0 ? { indentPt: pf.indentPt } : {},
560
+ ...pf.lineSpacing !== void 0 ? { lineSpacing: pf.lineSpacing } : {},
561
+ ...pf.spaceBeforePt !== void 0 ? { spaceBeforePt: pf.spaceBeforePt } : {},
562
+ ...pf.spaceAfterPt !== void 0 ? { spaceAfterPt: pf.spaceAfterPt } : {}
336
563
  });
337
- } else if (r.isContainer) collectShapeContainers(r.data, img, out, depth + 1, scheme);
564
+ }
565
+ return {
566
+ styles,
567
+ off
568
+ };
569
+ }
570
+ var TEXT_TYPE_FALLBACK = new Map([
571
+ [5, 1],
572
+ [6, 0],
573
+ [7, 1],
574
+ [8, 1]
575
+ ]);
576
+ function masterDefaults(chain, scheme) {
577
+ return (textType, level) => {
578
+ const types = [textType, TEXT_TYPE_FALLBACK.get(textType)];
579
+ let merged;
580
+ for (const styles of chain) for (const t of types) {
581
+ const levels = t === void 0 ? void 0 : styles.get(t);
582
+ const at = levels?.[Math.min(level, levels.length - 1)];
583
+ if (!at) continue;
584
+ const { colorHex: _c, colorIndex: _i, bullet: _b, bulletOn: _o, spaceBeforePt: _sb, spaceAfterPt: _sa, lineSpacing: _ls, leftMarginPt: _lm, indentPt: _ip, ...metrics } = at;
585
+ merged = {
586
+ ...t === textType ? at : metrics,
587
+ ...merged
588
+ };
589
+ }
590
+ if (!merged || merged.colorHex !== void 0 || merged.colorIndex === void 0) return merged;
591
+ const slot = scheme?.[merged.colorIndex];
592
+ return slot === void 0 ? merged : {
593
+ ...merged,
594
+ colorHex: slot
595
+ };
596
+ };
597
+ }
598
+ function buildMasterIdMap(docData) {
599
+ const out = /* @__PURE__ */ new Map();
600
+ const slwt = findChild(docData, (r) => r.type === RT_SLIDE_LIST_WITH_TEXT && r.instance === SLWT_INSTANCE_MASTERS);
601
+ if (!slwt) return out;
602
+ for (const rec of records(slwt)) if (rec.type === RT_SLIDE_PERSIST_ATOM && rec.data.length >= 16) out.set(u32(rec.data, 12), u32(rec.data, 0));
603
+ return out;
604
+ }
605
+ var SLIDE_FLAG_MASTER_OBJECTS = 1;
606
+ var SLIDE_FLAG_MASTER_BACKGROUND = 4;
607
+ function masterOf(slideData, ctx) {
608
+ const slideAtom = findChild(slideData, (r) => r.type === RT_SLIDE_ATOM);
609
+ if (!slideAtom || slideAtom.length < 22) return void 0;
610
+ const id = u32(slideAtom, 12);
611
+ const off = ctx.persist.get(ctx.byMasterId.get(id) ?? id);
612
+ const rec = off !== void 0 ? recordAt(ctx.stream, off) : void 0;
613
+ return rec && (rec.type === RT_MAIN_MASTER || rec.type === RT_SLIDE) ? rec : void 0;
614
+ }
615
+ function slideFlag(slideData, flag) {
616
+ const slideAtom = findChild(slideData, (r) => r.type === RT_SLIDE_ATOM);
617
+ return slideAtom !== void 0 && slideAtom.length >= 22 && (u16(slideAtom, 20) & flag) !== 0;
618
+ }
619
+ function masterShapes(slideData, ctx, img, furniture, defaults) {
620
+ if (!slideFlag(slideData, SLIDE_FLAG_MASTER_OBJECTS)) return [];
621
+ const master = masterOf(slideData, ctx);
622
+ if (!master) return [];
623
+ const scheme = resolveScheme(master.data, ctx);
624
+ return collectShapes(master.data, img, scheme ? { scheme } : {}, [], defaults).shapes.filter((s) => s.rectPt !== void 0).flatMap((s) => {
625
+ if (s.placeholder !== true) return [s];
626
+ const text = furniture ? furnitureText(s.placeholderId, furniture) : void 0;
627
+ return text === void 0 ? [] : [{
628
+ ...s,
629
+ paragraphs: [furnitureParagraph(s, text, scheme?.[SCHEME_TEXT_AND_LINES])]
630
+ }];
631
+ });
632
+ }
633
+ /**
634
+ * §2.4.15/§2.4.16 — the string one furniture placeholder shows, or `undefined`
635
+ * when this deck does not show that one at all.
636
+ *
637
+ * A date box is only drawn when the deck states the date ITSELF: `fHasTodayDate`
638
+ * asks for the day the file is opened, and a converter that answered it would
639
+ * put a different date in the file every time it ran.
640
+ */
641
+ function furnitureText(id, hf) {
642
+ if (id === PLACEHOLDER_FOOTER) return (hf.mask & HF_HAS_FOOTER) !== 0 ? (hf.footer ?? "") || void 0 : void 0;
643
+ if (id === PLACEHOLDER_SLIDE_NUMBER) return (hf.mask & HF_HAS_SLIDE_NUMBER) !== 0 ? String(hf.number) : void 0;
644
+ if (id === PLACEHOLDER_DATE) return (hf.mask & HF_HAS_DATE) !== 0 && (hf.mask & HF_HAS_USER_DATE) !== 0 ? (hf.userDate ?? "") || void 0 : void 0;
645
+ }
646
+ /**
647
+ * The furniture's words, in the formatting the master's own box carries.
648
+ *
649
+ * A `.ppt` master keeps no prompt text in these boxes, so there is usually no
650
+ * run to copy from and the paragraph takes the master's defaults; where one IS
651
+ * there, its size, colour and alignment are what PowerPoint draws the footer in.
652
+ */
653
+ function furnitureParagraph(shape, text, textColorHex) {
654
+ const model = shape.paragraphs?.find((p) => p.runs.length > 0);
655
+ const first = model?.runs[0];
656
+ return {
657
+ ...model ? { ...model } : {},
658
+ runs: [{
659
+ ...textColorHex !== void 0 ? { colorHex: textColorHex } : {},
660
+ ...first ?? {},
661
+ text
662
+ }]
663
+ };
664
+ }
665
+ /**
666
+ * §2.4.15 `HeadersFootersContainer` — the strings a deck shows on every slide,
667
+ * and which of them it shows.
668
+ *
669
+ * They live nowhere near the boxes that draw them: the geometry is a
670
+ * placeholder on the MASTER and the words are here, so a reader that has one
671
+ * without the other draws an empty band. 37625.ppt's every slide is signed
672
+ * "Transport CDM Workshop" and dated "26 August 2004" this way.
673
+ *
674
+ * @param data A DocumentContainer's or SlideContainer's records.
675
+ * @param instance Which container to read — the deck's or the slide's own.
676
+ * @returns The mask and the strings, or `undefined` when there is no container.
677
+ */
678
+ function headersFooters(data, instance) {
679
+ for (const rec of records(data)) {
680
+ if (rec.type !== RT_HEADERS_FOOTERS || rec.instance !== instance) continue;
681
+ let mask = 0;
682
+ let userDate;
683
+ let footer;
684
+ for (const child of records(rec.data)) if (child.type === RT_HEADERS_FOOTERS_ATOM && child.data.length >= 4) mask = child.data[2] | child.data[3] << 8;
685
+ else if (child.type === RT_CSTRING) {
686
+ const s = utf16Property(child.data);
687
+ if (child.instance === 0) userDate = s;
688
+ else if (child.instance === 2) footer = s;
689
+ }
690
+ return {
691
+ mask,
692
+ ...userDate !== void 0 ? { userDate } : {},
693
+ ...footer !== void 0 ? { footer } : {}
694
+ };
695
+ }
696
+ }
697
+ function masterBackground(slideData, ctx, img) {
698
+ if (!slideFlag(slideData, SLIDE_FLAG_MASTER_BACKGROUND)) return void 0;
699
+ const master = masterOf(slideData, ctx);
700
+ if (!master) return void 0;
701
+ const scheme = resolveScheme(master.data, ctx);
702
+ return collectShapes(master.data, img, scheme ? { scheme } : {}).background;
703
+ }
704
+ function masterChain(slideData, ctx, scheme, fonts) {
705
+ const chain = [];
706
+ if (!ctx) return masterDefaults(chain, scheme);
707
+ const behind = ctx.documentStyles;
708
+ let data = slideData;
709
+ const seen = /* @__PURE__ */ new Set();
710
+ for (let hop = 0; hop < 4 && data; hop++) {
711
+ const slideAtom = findChild(data, (r) => r.type === RT_SLIDE_ATOM);
712
+ if (!slideAtom || slideAtom.length < 16) break;
713
+ const masterId = u32(slideAtom, 12);
714
+ if (seen.has(masterId)) break;
715
+ seen.add(masterId);
716
+ const cached = ctx.cache.get(masterId);
717
+ const off = ctx.persist.get(ctx.byMasterId.get(masterId) ?? masterId);
718
+ const rec = off !== void 0 ? recordAt(ctx.stream, off) : void 0;
719
+ if (!rec || rec.type !== RT_MAIN_MASTER && rec.type !== RT_SLIDE) break;
720
+ if (cached) chain.push(cached);
721
+ else {
722
+ const styles = parseMasterTextStyles(rec.data, fonts);
723
+ ctx.cache.set(masterId, styles);
724
+ chain.push(styles);
725
+ }
726
+ data = rec.type === RT_SLIDE ? rec.data : void 0;
727
+ }
728
+ if (behind.size > 0) chain.push(behind);
729
+ return masterDefaults(chain, scheme);
730
+ }
731
+ function groupFrame(spgrData, parent) {
732
+ const sp = [...records(spgrData)].find((r) => r.type === FBT_SP_CONTAINER);
733
+ if (!sp) return void 0;
734
+ let box;
735
+ let rect;
736
+ for (const child of records(sp.data)) if (child.type === FBT_SPGR && child.data.length >= 16) {
737
+ const x = i32(child.data, 0);
738
+ const y = i32(child.data, 4);
739
+ box = {
740
+ x,
741
+ y,
742
+ w: i32(child.data, 8) - x,
743
+ h: i32(child.data, 12) - y
744
+ };
745
+ } else if (child.type === FBT_CLIENT_ANCHOR) rect = parseAnchor(child.data);
746
+ else if (child.type === FBT_CHILD_ANCHOR && parent !== void 0 && rect === void 0) rect = childRect(child.data, parent);
747
+ if (!box || !rect || box.w <= 0 || box.h <= 0) return void 0;
748
+ return {
749
+ rect,
750
+ ...box
751
+ };
752
+ }
753
+ function childRect(d, g) {
754
+ if (d.length < 16) return void 0;
755
+ const x1 = g.rect.x + (i32(d, 0) - g.x) / g.w * g.rect.w;
756
+ const y1 = g.rect.y + (i32(d, 4) - g.y) / g.h * g.rect.h;
757
+ const x2 = g.rect.x + (i32(d, 8) - g.x) / g.w * g.rect.w;
758
+ const y2 = g.rect.y + (i32(d, 12) - g.y) / g.h * g.rect.h;
759
+ const w = x2 - x1;
760
+ const h = y2 - y1;
761
+ return (w > 0 || h > 0) && w >= 0 && h >= 0 && Math.abs(x1) < 5e3 && Math.abs(y1) < 5e3 ? {
762
+ x: x1,
763
+ y: y1,
764
+ w,
765
+ h
766
+ } : void 0;
767
+ }
768
+ function clientTextboxParagraphs(d, outline, defaults, env) {
769
+ const own = collectParagraphs(d, 0, defaults, env);
770
+ if (own.some((p) => paragraphText(p).length > 0)) return own;
771
+ const ref = findChild(d, (r) => r.type === RT_OUTLINE_TEXT_REF_ATOM);
772
+ if (!ref || ref.length < 4) return own;
773
+ return [...outline[u32(ref, 0)] ?? []];
774
+ }
775
+ function parseWordArt(d, count, colorHex) {
776
+ const text = utf16Property(optComplex(d, count, PROP_GTEXT_UNICODE));
777
+ if (text === void 0 || text.trim() === "") return void 0;
778
+ const raw = optProperty(d, count, PROP_GTEXT_SIZE);
779
+ const sizePt = raw === void 0 ? void 0 : Math.round(raw / 65536 * 10) / 10;
780
+ const font = utf16Property(optComplex(d, count, PROP_GTEXT_FONT));
781
+ return {
782
+ runs: [{
783
+ text,
784
+ ...sizePt !== void 0 && sizePt > 0 ? { sizePt } : {},
785
+ ...colorHex ? { colorHex } : {},
786
+ ...font ? { fontFamily: font } : {}
787
+ }],
788
+ align: 1
789
+ };
790
+ }
791
+ function utf16Property(blob) {
792
+ if (!blob || blob.length < 2) return void 0;
793
+ let out = "";
794
+ for (let i = 0; i * 2 + 1 < blob.length; i++) {
795
+ const cu = u16(blob, i * 2);
796
+ if (cu === 0) break;
797
+ out += String.fromCharCode(cu);
798
+ }
799
+ return out.length > 0 ? out : void 0;
800
+ }
801
+ function parseTileSize(d, count) {
802
+ const w = signedLong(optProperty(d, count, PROP_FILL_WIDTH));
803
+ const h = signedLong(optProperty(d, count, PROP_FILL_HEIGHT));
804
+ if (w === void 0 || h === void 0 || w <= 0 || h <= 0) return void 0;
805
+ return {
806
+ widthPt: w / EMU_PER_POINT,
807
+ heightPt: h / EMU_PER_POINT
808
+ };
809
+ }
810
+ function inlineBlip(blob) {
811
+ if (!blob || blob.length < 8) return void 0;
812
+ const bytes = readEscherBlip(u16(blob, 2), u16(blob, 0) >> 4, blob.subarray(8));
813
+ return bytes ? { bytes } : void 0;
814
+ }
815
+ var PATTERN_TILE_PT = {
816
+ widthPt: 576 / 96,
817
+ heightPt: 576 / 96
818
+ };
819
+ /**
820
+ * §2.3.7.1 MSOFILLTYPE 1 — the picture a PATTERN fill repeats.
821
+ *
822
+ * The pattern itself is a one-bit bitmap in the picture store, and it carries
823
+ * no colour of its own: its set bits are the shape's `fillColor` and its clear
824
+ * bits its `fillBackColor`. So it is not a picture to be drawn but a stencil to
825
+ * be painted through, and the two colours are recorded nowhere else. 37625.ppt
826
+ * rules its every slide with a pale blue grid this way, and unread the whole
827
+ * deck came out on white.
828
+ *
829
+ * The result is handed back as an ordinary tiled picture: the tile path is
830
+ * already there and already tested, and a pattern IS a tiled picture once its
831
+ * two colours are in it.
832
+ *
833
+ * @param mono The pattern bitmap from the store, when it resolves.
834
+ * @param fgHex The shape's `fillColor` — what the set bits are painted in.
835
+ * @param bgHex Its `fillBackColor`; white when the shape states none.
836
+ * @returns The recoloured tile as a PNG, or `undefined` when the blip is not a
837
+ * bitmap this can read.
838
+ */
839
+ function patternFill(mono, fgHex, bgHex) {
840
+ if (!mono || !isBmp(mono.bytes)) return void 0;
841
+ let decoded;
842
+ try {
843
+ decoded = decodeBmp(mono.bytes);
844
+ } catch {
845
+ return;
846
+ }
847
+ const fg = rgb(fgHex ?? "000000");
848
+ const bg = rgb(bgHex ?? "FFFFFF");
849
+ const { width, height, data } = decoded;
850
+ const out = new Uint8Array(width * height * 3);
851
+ for (let i = 0; i < width * height; i++) {
852
+ const c = data[i * 3] + data[i * 3 + 1] + data[i * 3 + 2] < 384 ? fg : bg;
853
+ out[i * 3] = c[0];
854
+ out[i * 3 + 1] = c[1];
855
+ out[i * 3 + 2] = c[2];
856
+ }
857
+ return { bytes: encodePng(width, height, "rgb", out) };
858
+ }
859
+ /** `RRGGBB` → its three bytes. */
860
+ function rgb(hex) {
861
+ const n = Number.parseInt(hex, 16);
862
+ return Number.isFinite(n) ? [
863
+ n >> 16 & 255,
864
+ n >> 8 & 255,
865
+ n & 255
866
+ ] : [
867
+ 0,
868
+ 0,
869
+ 0
870
+ ];
871
+ }
872
+ function slideBackground(fillColorHex, gradient, fillType, image, tiled) {
873
+ if (image) return {
874
+ image,
875
+ ...tiled ? { imageTiled: true } : {}
876
+ };
877
+ if (gradient) return { gradient };
878
+ if (fillColorHex) return { fillColorHex };
338
879
  }
339
880
  function parseAnchor(data) {
340
881
  let top;
@@ -364,6 +905,37 @@ function parseAnchor(data) {
364
905
  h
365
906
  };
366
907
  }
908
+ function stated(d, count, propId, flag) {
909
+ const bools = optProperty(d, count, propId);
910
+ if (bools === void 0) return true;
911
+ return (bools & flag << 16) !== 0 ? (bools & flag) !== 0 : true;
912
+ }
913
+ /**
914
+ * §2.3.23 `cropFrom*` — the four edge crops, as fractions of the source.
915
+ *
916
+ * Each is a SIGNED 16.16 fixed-point fraction, so a negative one extends the
917
+ * picture past its box rather than cutting into it. A crop that leaves nothing
918
+ * of an axis is not one — 23884's globe keeps a ninth of its width and a
919
+ * seventh of its height, but zero would divide the fitting by nothing.
920
+ *
921
+ * @param d The OPT record's body.
922
+ * @param count The number of fixed entries it declares.
923
+ * @returns The four fractions, or `undefined` when the shape states no crop.
924
+ */
925
+ function parsePictureCrop(d, count) {
926
+ const frac = (id) => {
927
+ const raw = optProperty(d, count, id);
928
+ return raw === void 0 ? 0 : (raw | 0) / 65536;
929
+ };
930
+ const crop = {
931
+ left: frac(PROP_CROP_LEFT),
932
+ top: frac(PROP_CROP_TOP),
933
+ right: frac(PROP_CROP_RIGHT),
934
+ bottom: frac(PROP_CROP_BOTTOM)
935
+ };
936
+ if (crop.left === 0 && crop.top === 0 && crop.right === 0 && crop.bottom === 0) return void 0;
937
+ return 1 - crop.left - crop.right > 0 && 1 - crop.top - crop.bottom > 0 ? crop : void 0;
938
+ }
367
939
  function optProperty(d, count, wantId) {
368
940
  for (let i = 0; i < count && i * 6 + 6 <= d.length; i++) {
369
941
  const id = u16(d, i * 6);
@@ -375,11 +947,29 @@ function optComplex(d, count, wantId) {
375
947
  for (let i = 0; i < count && i * 6 + 6 <= d.length; i++) {
376
948
  const id = u16(d, i * 6);
377
949
  if ((id & 32768) === 0) continue;
378
- const len = u32(d, i * 6 + 2);
950
+ const len = arrayBlobLength(d, offset, id & 16383, u32(d, i * 6 + 2));
379
951
  if ((id & 16383) === wantId) return offset + len <= d.length && len > 0 ? d.subarray(offset, offset + len) : void 0;
380
952
  offset += len;
381
953
  }
382
954
  }
955
+ var ARRAY_PROPS = new Set([
956
+ 325,
957
+ 326,
958
+ 327,
959
+ 329,
960
+ 330,
961
+ 337,
962
+ 338,
963
+ 339
964
+ ]);
965
+ function arrayBlobLength(d, offset, id, len) {
966
+ if (!ARRAY_PROPS.has(id) || offset + 6 > d.length) return len;
967
+ const nElems = u16(d, offset);
968
+ const raw = u16(d, offset + 4);
969
+ const signed = raw >= 32768 ? raw - 65536 : raw;
970
+ const size = signed < 0 ? -signed >> 2 : signed;
971
+ return size > 0 && nElems > 0 && nElems * size === len ? len + 6 : len;
972
+ }
383
973
  function arrayHeader(blob) {
384
974
  if (blob.length < 6) return void 0;
385
975
  const raw = u16(blob, 4);
@@ -501,6 +1091,33 @@ var SYS_COLORS = new Map([
501
1091
  [23, "000000"],
502
1092
  [24, "FFFFE1"]
503
1093
  ]);
1094
+ /**
1095
+ * MS-ODRAW §2.3.7.1 `fillType` — the sweep a shaded fill asks for, or
1096
+ * `undefined` when the shape is filled with one flat colour (type 0) or with
1097
+ * something this reader does not draw (a picture, a texture, a pattern).
1098
+ *
1099
+ * @param d The OPT record's data.
1100
+ * @param count Its entry count (the record's instance).
1101
+ * @param fromHex The resolved `fillColor` — one end of the sweep.
1102
+ * @param scheme The slide's colour scheme, for a scheme-relative far end.
1103
+ */
1104
+ function parseFillGradient(d, count, fromHex, scheme) {
1105
+ const type = optProperty(d, count, PROP_FILL_TYPE);
1106
+ if (type === void 0 || type < 4 || type > 8) return void 0;
1107
+ const toHex = optColor(d, count, PROP_FILL_BACK_COLOR, scheme) ?? "FFFFFF";
1108
+ if (fromHex === void 0) return void 0;
1109
+ const raw = optProperty(d, count, PROP_FILL_ANGLE);
1110
+ const angleDeg = raw === void 0 ? 90 : 90 - (raw | 0) / 65536;
1111
+ const focus = optProperty(d, count, PROP_FILL_FOCUS);
1112
+ const focusPct = focus === void 0 ? 0 : (focus | 0) << 16 >> 16;
1113
+ return {
1114
+ fromHex,
1115
+ toHex,
1116
+ angleDeg,
1117
+ radial: type === 5 || type === 6,
1118
+ ...focusPct !== 0 ? { focusPct } : {}
1119
+ };
1120
+ }
504
1121
  function optColor(d, count, wantId, scheme) {
505
1122
  const v = optProperty(d, count, wantId);
506
1123
  if (v === void 0) return void 0;
@@ -512,13 +1129,14 @@ function optColor(d, count, wantId, scheme) {
512
1129
  }
513
1130
  if (flags === COLORREF_SYS_INDEX) return SYS_COLORS.get(v & 65535);
514
1131
  }
515
- function resolveScheme(slideData, persist, stream) {
1132
+ function resolveScheme(slideData, ctx) {
516
1133
  let schemeData = findColorScheme(slideData);
517
1134
  const slideAtom = findChild(slideData, (r) => r.type === RT_SLIDE_ATOM);
518
- if (slideAtom && slideAtom.length >= 22 && persist && stream) {
1135
+ if (slideAtom && slideAtom.length >= 22 && ctx) {
519
1136
  if ((u16(slideAtom, 20) & SLIDE_FLAG_MASTER_SCHEME) !== 0) {
520
- const masterOff = persist.get(u32(slideAtom, 12));
521
- const masterRec = masterOff !== void 0 ? recordAt(stream, masterOff) : void 0;
1137
+ const id = u32(slideAtom, 12);
1138
+ const masterOff = ctx.persist.get(ctx.byMasterId.get(id) ?? id);
1139
+ const masterRec = masterOff !== void 0 ? recordAt(ctx.stream, masterOff) : void 0;
522
1140
  if (masterRec && masterRec.type === RT_MAIN_MASTER) {
523
1141
  const masterScheme = findColorScheme(masterRec.data);
524
1142
  if (masterScheme) schemeData = masterScheme;
@@ -541,59 +1159,61 @@ function parseColorScheme(d) {
541
1159
  }
542
1160
  function readBlipBytes(pictures, foDelay) {
543
1161
  if (foDelay < 0 || foDelay + 8 > pictures.length) return void 0;
1162
+ const verInstance = u16(pictures, foDelay);
1163
+ const type = u16(pictures, foDelay + 2);
544
1164
  const recLen = u32(pictures, foDelay + 4);
545
1165
  const start = foDelay + 8;
546
1166
  const blip = pictures.subarray(start, Math.min(pictures.length, start + recLen));
547
- const limit = Math.min(blip.length, 80);
548
- for (let off = 0; off < limit; off++) for (const magic of IMAGE_MAGICS) if (matchesMagic(blip, off, magic)) return blip.subarray(off);
549
- }
550
- var IMAGE_MAGICS = [[
551
- 137,
552
- 80,
553
- 78,
554
- 71
555
- ], [
556
- 255,
557
- 216,
558
- 255
559
- ]];
560
- function matchesMagic(d, off, magic) {
561
- if (off + magic.length > d.length) return false;
562
- for (let i = 0; i < magic.length; i++) if (d[off + i] !== magic[i]) return false;
563
- return true;
1167
+ return readEscherBlip(type, verInstance >> 4, blip);
564
1168
  }
565
1169
  /** The concatenated plain text of a paragraph's runs. */
566
1170
  function paragraphText(p) {
567
1171
  return p.runs.map((r) => r.text).join("");
568
1172
  }
569
- function buildStyledParagraphs(text, styleData) {
570
- const style = styleData ? parseStyleTextProp(styleData, text.length) : void 0;
1173
+ function buildStyledParagraphs(text, styleData, defaults, env) {
1174
+ const style = styleData ? parseStyleTextProp(styleData, text.length, env) : void 0;
571
1175
  const charProps = style ? expandCharProps(style.charRuns, text.length) : void 0;
572
- const paraRuns = style?.paraRuns ?? [];
1176
+ const paraProps = style ? expandParaProps(style.paraRuns, text.length) : void 0;
573
1177
  const paras = [];
574
1178
  let runs = [];
575
1179
  let cur = "";
576
1180
  let curProps;
577
- let paraIndex = 0;
1181
+ let paraStart = 0;
578
1182
  const pushRun = () => {
579
1183
  if (cur.length > 0) runs.push(toRun(cur, curProps));
580
1184
  cur = "";
581
1185
  };
582
- const endParagraph = () => {
1186
+ const endParagraph = (end) => {
583
1187
  pushRun();
584
- const meta = paraRuns[paraIndex];
1188
+ const meta = paraProps?.[paraStart];
1189
+ const lvl = defaults?.(meta?.level ?? 0);
1190
+ const align = meta?.align ?? lvl?.align;
1191
+ const on = meta?.bulletOn ?? lvl?.bulletOn;
1192
+ const char = meta?.bullet ?? lvl?.bullet;
1193
+ const bullet = on === false ? void 0 : on === true ? char ?? "•" : char;
1194
+ const leftMarginPt = meta?.leftMarginPt ?? lvl?.leftMarginPt;
1195
+ const indentPt = meta?.indentPt ?? lvl?.indentPt;
1196
+ const lineSpacing = meta?.lineSpacing ?? lvl?.lineSpacing;
1197
+ const spaceBeforePt = meta?.spaceBeforePt ?? lvl?.spaceBeforePt;
1198
+ const spaceAfterPt = meta?.spaceAfterPt ?? lvl?.spaceAfterPt;
585
1199
  paras.push({
586
- runs,
587
- ...meta?.align !== void 0 ? { align: meta.align } : {},
588
- ...meta?.level !== void 0 ? { level: meta.level } : {}
1200
+ runs: lvl ? runs.map((r) => inherit(r, lvl)) : runs,
1201
+ ...align !== void 0 ? { align } : {},
1202
+ ...meta?.level !== void 0 ? { level: meta.level } : {},
1203
+ ...bullet !== void 0 ? { bullet } : {},
1204
+ ...leftMarginPt !== void 0 ? { leftMarginPt } : {},
1205
+ ...indentPt !== void 0 ? { indentPt } : {},
1206
+ ...lineSpacing !== void 0 ? { lineSpacing } : {},
1207
+ ...spaceBeforePt !== void 0 ? { spaceBeforePt } : {},
1208
+ ...spaceAfterPt !== void 0 ? { spaceAfterPt } : {}
589
1209
  });
590
1210
  runs = [];
591
- paraIndex++;
1211
+ paraStart = end + 1;
592
1212
  };
593
1213
  for (let i = 0; i < text.length; i++) {
594
1214
  const c = text.charCodeAt(i);
595
1215
  if (c === 13) {
596
- endParagraph();
1216
+ endParagraph(i);
597
1217
  continue;
598
1218
  }
599
1219
  const props = charProps?.[i];
@@ -602,10 +1222,21 @@ function buildStyledParagraphs(text, styleData) {
602
1222
  if (c === 11 || c === 10 || c === 9) cur += " ";
603
1223
  else if (c !== 65279 && c >= 32) cur += text[i];
604
1224
  }
605
- endParagraph();
1225
+ endParagraph(text.length);
606
1226
  if (paras.length > 1 && paragraphText(paras[paras.length - 1]).length === 0) paras.pop();
607
1227
  return paras;
608
1228
  }
1229
+ function inherit(run, lvl) {
1230
+ const sizePt = run.sizePt ?? lvl.sizePt;
1231
+ const colorHex = run.colorHex ?? lvl.colorHex;
1232
+ const fontFamily = run.fontFamily ?? lvl.fontFamily;
1233
+ return {
1234
+ ...run,
1235
+ ...sizePt !== void 0 ? { sizePt } : {},
1236
+ ...colorHex !== void 0 ? { colorHex } : {},
1237
+ ...fontFamily !== void 0 ? { fontFamily } : {}
1238
+ };
1239
+ }
609
1240
  function toRun(text, props) {
610
1241
  if (!props) return { text };
611
1242
  return {
@@ -614,13 +1245,14 @@ function toRun(text, props) {
614
1245
  ...props.italic ? { italic: true } : {},
615
1246
  ...props.underline ? { underline: true } : {},
616
1247
  ...props.sizePt ? { sizePt: props.sizePt } : {},
617
- ...props.colorHex ? { colorHex: props.colorHex } : {}
1248
+ ...props.colorHex ? { colorHex: props.colorHex } : {},
1249
+ ...props.fontFamily ? { fontFamily: props.fontFamily } : {}
618
1250
  };
619
1251
  }
620
1252
  function sameProps(a, b) {
621
1253
  if (a === b) return true;
622
1254
  if (!a || !b) return false;
623
- return !!a.bold === !!b.bold && !!a.italic === !!b.italic && !!a.underline === !!b.underline && a.sizePt === b.sizePt && a.colorHex === b.colorHex;
1255
+ return !!a.bold === !!b.bold && !!a.italic === !!b.italic && !!a.underline === !!b.underline && a.sizePt === b.sizePt && a.colorHex === b.colorHex && a.fontFamily === b.fontFamily;
624
1256
  }
625
1257
  function expandCharProps(charRuns, textLen) {
626
1258
  const out = [];
@@ -628,7 +1260,14 @@ function expandCharProps(charRuns, textLen) {
628
1260
  while (out.length < textLen) out.push(charRuns[charRuns.length - 1] ?? { count: 0 });
629
1261
  return out;
630
1262
  }
631
- function parseStyleTextProp(data, textLen) {
1263
+ /** The same, for the paragraph runs: the run that covers each character. */
1264
+ function expandParaProps(paraRuns, textLen) {
1265
+ const out = [];
1266
+ for (const run of paraRuns) for (let i = 0; i < run.count && out.length < textLen; i++) out.push(run);
1267
+ while (out.length < textLen) out.push(paraRuns[paraRuns.length - 1]);
1268
+ return out;
1269
+ }
1270
+ function parseStyleTextProp(data, textLen, env) {
632
1271
  const target = textLen + 1;
633
1272
  let off = 0;
634
1273
  const paraRuns = [];
@@ -636,32 +1275,19 @@ function parseStyleTextProp(data, textLen) {
636
1275
  while (consumed < target && off + 10 <= data.length) {
637
1276
  const count = u32(data, off);
638
1277
  const level = u16(data, off + 4);
639
- const mask = u32(data, off + 6);
640
- off += 10;
641
- let align;
642
- if ((mask & 15) !== 0) off += 2;
643
- if ((mask & 128) !== 0) off += 2;
644
- if ((mask & 16) !== 0) off += 2;
645
- if ((mask & 64) !== 0) off += 2;
646
- if ((mask & 32) !== 0) off += 4;
647
- if ((mask & 2048) !== 0) {
648
- align = u16(data, off);
649
- off += 2;
650
- }
651
- if ((mask & 4096) !== 0) off += 2;
652
- if ((mask & 8192) !== 0) off += 2;
653
- if ((mask & 16384) !== 0) off += 2;
654
- if ((mask & 256) !== 0) off += 2;
655
- if ((mask & 1024) !== 0) off += 2;
656
- if ((mask & 32768) !== 0) off += 2;
657
- if ((mask & 1048576) !== 0) off += 2 + (off + 2 <= data.length ? u16(data, off) : 0) * 4;
658
- if ((mask & 65536) !== 0) off += 2;
659
- if ((mask & 917504) !== 0) off += 2;
660
- if ((mask & 2097152) !== 0) off += 2;
1278
+ const pf = readPfException(data, off + 6);
1279
+ off = pf.off;
661
1280
  paraRuns.push({
662
1281
  count,
663
1282
  level,
664
- ...align !== void 0 ? { align } : {}
1283
+ ...pf.align !== void 0 ? { align: pf.align } : {},
1284
+ ...pf.bullet !== void 0 ? { bullet: pf.bullet } : {},
1285
+ ...pf.bulletOn !== void 0 ? { bulletOn: pf.bulletOn } : {},
1286
+ ...pf.leftMarginPt !== void 0 ? { leftMarginPt: pf.leftMarginPt } : {},
1287
+ ...pf.indentPt !== void 0 ? { indentPt: pf.indentPt } : {},
1288
+ ...pf.lineSpacing !== void 0 ? { lineSpacing: pf.lineSpacing } : {},
1289
+ ...pf.spaceBeforePt !== void 0 ? { spaceBeforePt: pf.spaceBeforePt } : {},
1290
+ ...pf.spaceAfterPt !== void 0 ? { spaceAfterPt: pf.spaceAfterPt } : {}
665
1291
  });
666
1292
  consumed += count;
667
1293
  if (count <= 0) break;
@@ -670,31 +1296,12 @@ function parseStyleTextProp(data, textLen) {
670
1296
  consumed = 0;
671
1297
  while (consumed < target && off + 8 <= data.length) {
672
1298
  const count = u32(data, off);
673
- const mask = u32(data, off + 4);
674
- off += 8;
675
- const run = { count };
676
- if ((mask & 16055) !== 0) {
677
- const style = u16(data, off);
678
- off += 2;
679
- if ((mask & 1) !== 0 && (style & 1) !== 0) run.bold = true;
680
- if ((mask & 2) !== 0 && (style & 2) !== 0) run.italic = true;
681
- if ((mask & 4) !== 0 && (style & 4) !== 0) run.underline = true;
682
- }
683
- if ((mask & 65536) !== 0) off += 2;
684
- if ((mask & 2097152) !== 0) off += 2;
685
- if ((mask & 4194304) !== 0) off += 2;
686
- if ((mask & 8388608) !== 0) off += 2;
687
- if ((mask & 131072) !== 0) {
688
- const sz = u16(data, off);
689
- off += 2;
690
- if (sz > 0) run.sizePt = sz;
691
- }
692
- if ((mask & 262144) !== 0) {
693
- if (off + 4 <= data.length && data[off + 3] === 254) run.colorHex = hex2(data[off]) + hex2(data[off + 1]) + hex2(data[off + 2]);
694
- off += 4;
695
- }
696
- if ((mask & 524288) !== 0) off += 2;
697
- charRuns.push(run);
1299
+ const cf = readCfException(data, off + 4, env?.scheme, env?.fonts);
1300
+ off = cf.off;
1301
+ charRuns.push({
1302
+ count,
1303
+ ...cf.props
1304
+ });
698
1305
  consumed += count;
699
1306
  if (count <= 0) break;
700
1307
  }
@@ -703,6 +1310,128 @@ function parseStyleTextProp(data, textLen) {
703
1310
  charRuns
704
1311
  } : void 0;
705
1312
  }
1313
+ /**
1314
+ * §2.9.32 ParaSpacing → points, or `undefined` when the value is a percentage.
1315
+ *
1316
+ * Negative states a DISTANCE in master units, 576 to the inch. Positive states
1317
+ * a percentage of the line's height, which is not a distance this reader can
1318
+ * work out — the line has not been set yet — so it is left for the paragraph to
1319
+ * inherit nothing rather than guessed at.
1320
+ */
1321
+ function spacingPt(value) {
1322
+ return value < 0 ? -value / 8 : void 0;
1323
+ }
1324
+ function readPfException(data, start) {
1325
+ const mask = u32(data, start);
1326
+ let off = start + 4;
1327
+ let align;
1328
+ let bulletOn;
1329
+ let bullet;
1330
+ let leftMarginPt;
1331
+ let indentPt;
1332
+ let lineSpacing;
1333
+ let spaceBeforePt;
1334
+ let spaceAfterPt;
1335
+ if ((mask & 15) !== 0) {
1336
+ bulletOn = (u16(data, off) & 1) !== 0;
1337
+ off += 2;
1338
+ }
1339
+ if ((mask & 128) !== 0) {
1340
+ bullet = bulletCharacter(u16(data, off));
1341
+ off += 2;
1342
+ }
1343
+ if ((mask & 16) !== 0) off += 2;
1344
+ if ((mask & 64) !== 0) off += 2;
1345
+ if ((mask & 32) !== 0) off += 4;
1346
+ if ((mask & 2048) !== 0) {
1347
+ align = u16(data, off);
1348
+ off += 2;
1349
+ }
1350
+ if ((mask & 4096) !== 0) {
1351
+ lineSpacing = i16(data, off);
1352
+ off += 2;
1353
+ }
1354
+ if ((mask & 8192) !== 0) {
1355
+ spaceBeforePt = spacingPt(i16(data, off));
1356
+ off += 2;
1357
+ }
1358
+ if ((mask & 16384) !== 0) {
1359
+ spaceAfterPt = spacingPt(i16(data, off));
1360
+ off += 2;
1361
+ }
1362
+ if ((mask & 256) !== 0) {
1363
+ leftMarginPt = u16(data, off) / 8;
1364
+ off += 2;
1365
+ }
1366
+ if ((mask & 1024) !== 0) {
1367
+ indentPt = u16(data, off) / 8;
1368
+ off += 2;
1369
+ }
1370
+ if ((mask & 32768) !== 0) off += 2;
1371
+ if ((mask & 1048576) !== 0) off += 2 + (off + 2 <= data.length ? u16(data, off) : 0) * 4;
1372
+ if ((mask & 65536) !== 0) off += 2;
1373
+ if ((mask & 917504) !== 0) off += 2;
1374
+ if ((mask & 2097152) !== 0) off += 2;
1375
+ return {
1376
+ off,
1377
+ ...align !== void 0 ? { align } : {},
1378
+ ...bullet !== void 0 ? { bullet } : {},
1379
+ ...bulletOn !== void 0 ? { bulletOn } : {},
1380
+ ...leftMarginPt !== void 0 ? { leftMarginPt } : {},
1381
+ ...indentPt !== void 0 ? { indentPt } : {},
1382
+ ...lineSpacing !== void 0 ? { lineSpacing } : {},
1383
+ ...spaceBeforePt !== void 0 ? { spaceBeforePt } : {},
1384
+ ...spaceAfterPt !== void 0 ? { spaceAfterPt } : {}
1385
+ };
1386
+ }
1387
+ function bulletCharacter(code) {
1388
+ if (code === 0) return void 0;
1389
+ const ch = String.fromCharCode(code);
1390
+ return code < 8192 || code >= 61440 && code <= 61695 ? fromSymbolFont(ch, "Wingdings") : ch;
1391
+ }
1392
+ function readCfException(data, start, scheme, fonts) {
1393
+ const mask = u32(data, start);
1394
+ let off = start + 4;
1395
+ const props = {};
1396
+ if ((mask & 16055) !== 0) {
1397
+ const style = u16(data, off);
1398
+ off += 2;
1399
+ if ((mask & 1) !== 0 && (style & 1) !== 0) props.bold = true;
1400
+ if ((mask & 2) !== 0 && (style & 2) !== 0) props.italic = true;
1401
+ if ((mask & 4) !== 0 && (style & 4) !== 0) props.underline = true;
1402
+ }
1403
+ if ((mask & 65536) !== 0) {
1404
+ props.fontRef = u16(data, off);
1405
+ off += 2;
1406
+ }
1407
+ if ((mask & 2097152) !== 0) off += 2;
1408
+ if ((mask & 4194304) !== 0) off += 2;
1409
+ if ((mask & 8388608) !== 0) off += 2;
1410
+ if ((mask & 131072) !== 0) {
1411
+ const sz = u16(data, off);
1412
+ off += 2;
1413
+ if (sz > 0) props.sizePt = sz;
1414
+ }
1415
+ if ((mask & 262144) !== 0) {
1416
+ const index = off + 4 <= data.length ? data[off + 3] : void 0;
1417
+ if (index === 254) props.colorHex = hex2(data[off]) + hex2(data[off + 1]) + hex2(data[off + 2]);
1418
+ else if (index !== void 0 && index < 8) {
1419
+ props.colorIndex = index;
1420
+ const slot = scheme?.[index];
1421
+ if (slot !== void 0) props.colorHex = slot;
1422
+ }
1423
+ off += 4;
1424
+ }
1425
+ if ((mask & 524288) !== 0) off += 2;
1426
+ if (props.fontRef !== void 0) {
1427
+ const name = fonts?.[props.fontRef];
1428
+ if (name !== void 0 && name.length > 0) props.fontFamily = name;
1429
+ }
1430
+ return {
1431
+ off,
1432
+ props
1433
+ };
1434
+ }
706
1435
  function hex2(n) {
707
1436
  return n.toString(16).padStart(2, "0").toUpperCase();
708
1437
  }