reamkit 1.26.0 → 1.28.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 (85) hide show
  1. package/README.md +14 -8
  2. package/dist/esm/core/converter/ream.d.ts +0 -9
  3. package/dist/esm/core/converter/ream.js +0 -1
  4. package/dist/esm/core/document-model/types.d.ts +5 -3
  5. package/dist/esm/core/font/index.d.ts +1 -0
  6. package/dist/esm/core/font/ligatures.d.ts +17 -0
  7. package/dist/esm/core/font/ligatures.js +49 -0
  8. package/dist/esm/core/font/ttf-parser.d.ts +2 -1
  9. package/dist/esm/core/font/ttf-parser.js +11 -2
  10. package/dist/esm/core/fonts/remote-fonts.d.ts +1 -1
  11. package/dist/esm/core/fonts/remote-fonts.js +47 -2
  12. package/dist/esm/core/fonts/scripts.js +10 -5
  13. package/dist/esm/excel/header-footer.js +53 -8
  14. package/dist/esm/layout/styled-layout.js +53 -3
  15. package/dist/esm/pdf/cid-font.js +35 -8
  16. package/dist/esm/pdf-reader/annot-draw.d.ts +65 -0
  17. package/dist/esm/pdf-reader/annot-draw.js +487 -0
  18. package/dist/esm/pdf-reader/annots.d.ts +0 -12
  19. package/dist/esm/pdf-reader/annots.js +30 -4
  20. package/dist/esm/pdf-reader/ccitt.d.ts +20 -3
  21. package/dist/esm/pdf-reader/ccitt.js +102 -6
  22. package/dist/esm/pdf-reader/cff-outline.d.ts +36 -0
  23. package/dist/esm/pdf-reader/cff-outline.js +1122 -0
  24. package/dist/esm/pdf-reader/cie-color.d.ts +33 -0
  25. package/dist/esm/pdf-reader/cie-color.js +112 -0
  26. package/dist/esm/pdf-reader/cmap.js +5 -2
  27. package/dist/esm/pdf-reader/content.d.ts +123 -3
  28. package/dist/esm/pdf-reader/content.js +232 -54
  29. package/dist/esm/pdf-reader/dingbats.d.ts +11 -0
  30. package/dist/esm/pdf-reader/dingbats.js +1033 -0
  31. package/dist/esm/pdf-reader/display.d.ts +1 -1
  32. package/dist/esm/pdf-reader/display.js +61 -6
  33. package/dist/esm/pdf-reader/document.d.ts +6 -0
  34. package/dist/esm/pdf-reader/document.js +55 -10
  35. package/dist/esm/pdf-reader/embedded-fonts.d.ts +23 -3
  36. package/dist/esm/pdf-reader/embedded-fonts.js +36 -4
  37. package/dist/esm/pdf-reader/encodings.d.ts +25 -0
  38. package/dist/esm/pdf-reader/encodings.js +110 -0
  39. package/dist/esm/pdf-reader/flow-build.d.ts +19 -5
  40. package/dist/esm/pdf-reader/flow-build.js +111 -11
  41. package/dist/esm/pdf-reader/font.js +403 -21
  42. package/dist/esm/pdf-reader/function.d.ts +16 -0
  43. package/dist/esm/pdf-reader/function.js +414 -0
  44. package/dist/esm/pdf-reader/glyf-outline.d.ts +43 -0
  45. package/dist/esm/pdf-reader/glyf-outline.js +351 -0
  46. package/dist/esm/pdf-reader/glyph-names.js +20 -0
  47. package/dist/esm/pdf-reader/icc.d.ts +10 -0
  48. package/dist/esm/pdf-reader/icc.js +210 -0
  49. package/dist/esm/pdf-reader/image-decode.d.ts +9 -4
  50. package/dist/esm/pdf-reader/image-decode.js +274 -72
  51. package/dist/esm/pdf-reader/images.d.ts +18 -0
  52. package/dist/esm/pdf-reader/images.js +154 -11
  53. package/dist/esm/pdf-reader/jbig2.d.ts +23 -0
  54. package/dist/esm/pdf-reader/jbig2.js +126 -32
  55. package/dist/esm/pdf-reader/layout.d.ts +32 -0
  56. package/dist/esm/pdf-reader/layout.js +1316 -64
  57. package/dist/esm/pdf-reader/lexer.d.ts +2 -0
  58. package/dist/esm/pdf-reader/lexer.js +4 -0
  59. package/dist/esm/pdf-reader/math-rows.d.ts +23 -0
  60. package/dist/esm/pdf-reader/math-rows.js +198 -0
  61. package/dist/esm/pdf-reader/optional-content.d.ts +36 -0
  62. package/dist/esm/pdf-reader/optional-content.js +93 -0
  63. package/dist/esm/pdf-reader/predefined-cmap.d.ts +21 -0
  64. package/dist/esm/pdf-reader/predefined-cmap.js +102 -0
  65. package/dist/esm/pdf-reader/reader.d.ts +6 -6
  66. package/dist/esm/pdf-reader/reader.js +102 -16
  67. package/dist/esm/pdf-reader/shading.d.ts +139 -8
  68. package/dist/esm/pdf-reader/shading.js +309 -39
  69. package/dist/esm/pdf-reader/standard-metrics.d.ts +8 -0
  70. package/dist/esm/pdf-reader/standard-metrics.js +18 -0
  71. package/dist/esm/pdf-reader/standard-widths.d.ts +20 -0
  72. package/dist/esm/pdf-reader/standard-widths.js +62 -0
  73. package/dist/esm/pdf-reader/stream-filters.d.ts +6 -0
  74. package/dist/esm/pdf-reader/stream-filters.js +67 -0
  75. package/dist/esm/pdf-reader/tagged.js +204 -32
  76. package/dist/esm/pdf-reader/text-rules.d.ts +16 -0
  77. package/dist/esm/pdf-reader/text-rules.js +185 -0
  78. package/dist/esm/pdf-reader/text.js +157 -4
  79. package/dist/esm/pdf-reader/type1-outline.d.ts +21 -0
  80. package/dist/esm/pdf-reader/type1-outline.js +576 -0
  81. package/dist/esm/pdf-reader/vector.d.ts +5 -0
  82. package/dist/esm/pdf-reader/vector.js +79 -27
  83. package/dist/esm/word/document-parser.js +4 -1
  84. package/dist/esm/word/docx-writer.js +74 -11
  85. package/package.json +1 -1
@@ -27,11 +27,11 @@ function paragraphBlock(text, outlineLevel) {
27
27
  * survives as its own run) and squashing whitespace. With no hrefs this
28
28
  * collapses to a single run — the same shape {@link paragraphBlock} produces.
29
29
  */
30
- function paragraphFromRuns(spans, outlineLevel) {
30
+ function paragraphFromRuns(spans, outlineLevel, placement) {
31
31
  const merged = [];
32
32
  for (const s of spans) {
33
33
  const last = merged[merged.length - 1];
34
- if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic) last.text += s.text;
34
+ if (last && last.href === s.href && last.sizePt === s.sizePt && last.colorHex === s.colorHex && last.fontName === s.fontName && last.outline?.colorHex === s.outline?.colorHex && last.outline?.widthPt === s.outline?.widthPt && last.bold === s.bold && last.italic === s.italic && last.script === s.script && sameMarkup(last.markup, s.markup)) last.text += s.text;
35
35
  else merged.push({
36
36
  text: s.text,
37
37
  ...s.href !== void 0 ? { href: s.href } : {},
@@ -40,12 +40,14 @@ function paragraphFromRuns(spans, outlineLevel) {
40
40
  ...s.fontName !== void 0 ? { fontName: s.fontName } : {},
41
41
  ...s.outline !== void 0 ? { outline: s.outline } : {},
42
42
  ...s.bold !== void 0 ? { bold: s.bold } : {},
43
- ...s.italic !== void 0 ? { italic: s.italic } : {}
43
+ ...s.italic !== void 0 ? { italic: s.italic } : {},
44
+ ...s.script !== void 0 ? { script: s.script } : {},
45
+ ...s.markup !== void 0 ? { markup: s.markup } : {}
44
46
  });
45
47
  }
46
48
  const runs = merged.map((m) => ({
47
49
  ...m,
48
- text: m.text.replace(/\s+/g, " ")
50
+ text: m.text.replace(/[^\S\t]+/gu, " ")
49
51
  })).filter((m) => m.text.length > 0);
50
52
  if (runs.length > 0) {
51
53
  runs[0].text = runs[0].text.replace(/^ /, "");
@@ -54,7 +56,10 @@ function paragraphFromRuns(spans, outlineLevel) {
54
56
  return {
55
57
  kind: "paragraph",
56
58
  paragraph: {
57
- properties: outlineLevel !== void 0 ? { outlineLevel } : {},
59
+ properties: {
60
+ ...outlineLevel !== void 0 ? { outlineLevel } : {},
61
+ ...placement
62
+ },
58
63
  runs: runs.filter((r) => r.text.length > 0).map((r) => ({
59
64
  text: r.text,
60
65
  properties: {
@@ -63,22 +68,32 @@ function paragraphFromRuns(spans, outlineLevel) {
63
68
  ...r.fontName !== void 0 ? { fontFamily: { ascii: r.fontName } } : {},
64
69
  ...r.outline !== void 0 ? { textOutline: r.outline } : {},
65
70
  ...r.bold ? { bold: true } : {},
66
- ...r.italic ? { italic: true } : {}
71
+ ...r.italic ? { italic: true } : {},
72
+ ...r.script !== void 0 ? { verticalAlign: r.script } : {},
73
+ ...r.markup?.highlightHex !== void 0 ? { shadingColorHex: r.markup.highlightHex } : {},
74
+ ...r.markup?.underline !== void 0 ? { underline: r.markup.underline } : {},
75
+ ...r.markup?.underlineHex !== void 0 ? { underlineColorHex: r.markup.underlineHex } : {},
76
+ ...r.markup?.strike === true ? { strike: true } : {}
67
77
  },
68
78
  ...r.href ? { href: r.href } : {}
69
79
  }))
70
80
  }
71
81
  };
72
82
  }
83
+ /** Whether two runs are marked the same way, so they may join into one. */
84
+ function sameMarkup(a, b) {
85
+ return a?.highlightHex === b?.highlightHex && a?.underline === b?.underline && a?.underlineHex === b?.underlineHex && a?.strike === b?.strike;
86
+ }
73
87
  /**
74
88
  * Store a {@link PdfImage}'s bytes (content-addressed dedup) and build the image
75
89
  * {@link BodyElement} that references them, sized in points from the placement
76
90
  * CTM. `alt` becomes the block's alt text when given.
77
91
  */
78
- function imageBlock(image, resources, alt, frame, zOrder) {
92
+ function imageBlock(image, resources, alt, frame, zOrder, behind = false) {
79
93
  const resource = resources.put(image.bytes);
80
94
  const float = frame !== void 0 ? {
81
95
  wrap: "none",
96
+ ...behind ? { behind: true } : {},
82
97
  ...zOrder !== void 0 ? { zOrder } : {},
83
98
  posH: {
84
99
  relativeFrom: "page",
@@ -96,6 +111,9 @@ function imageBlock(image, resources, alt, frame, zOrder) {
96
111
  resource,
97
112
  width: pt(image.widthPt),
98
113
  height: pt(image.heightPt),
114
+ ...image.rotationDeg !== void 0 ? { rotation60k: Math.round(-image.rotationDeg * 6e4) } : {},
115
+ ...image.crop ? { crop: image.crop } : {},
116
+ ...image.alpha !== void 0 ? { alpha: image.alpha } : {},
99
117
  paragraphProperties: {},
100
118
  ...alt ? { altText: alt } : {}
101
119
  }
@@ -172,7 +190,7 @@ function dedupeLosses(losses) {
172
190
  * a paragraph: 22060_A1_01_Plans.pdf is one A3 sheet of vectors, and stacking
173
191
  * its forty-nine paths one under another spilled it onto a second page.
174
192
  */
175
- function shapeBlock(v, frame, zOrder) {
193
+ function shapeBlock(v, frame, zOrder, behind = false) {
176
194
  const w = v.maxX - v.minX;
177
195
  const h = v.maxY - v.minY;
178
196
  const fx = (x) => x - v.minX;
@@ -222,6 +240,7 @@ function shapeBlock(v, frame, zOrder) {
222
240
  } : void 0;
223
241
  const float = frame !== void 0 ? {
224
242
  wrap: "none",
243
+ ...behind || v.darkens === true ? { behind: true } : {},
225
244
  ...zOrder !== void 0 ? { zOrder } : {},
226
245
  posH: {
227
246
  relativeFrom: "page",
@@ -287,17 +306,98 @@ function sectionFromPdfPages(pages) {
287
306
  };
288
307
  }
289
308
  /**
309
+ * The margins the SOURCE used, measured off where its words actually sit.
310
+ *
311
+ * A PDF states none — text is placed anywhere on the MediaBox — so the reader
312
+ * used to leave them at zero rather than invent an inch. But the words
313
+ * themselves say where the margin was: the leftmost glyph on the page is the
314
+ * left margin, and reflowing inside it keeps the measure the author set instead
315
+ * of running the text from edge to edge.
316
+ *
317
+ * Measured on the MEDIAN page rather than the extreme one, so a single full-
318
+ * bleed rule or a page number in the corner does not collapse the margin for
319
+ * the whole document, and clamped so a strange page cannot leave no text area
320
+ * at all.
321
+ *
322
+ * @param section The section the page box gave, or `undefined`.
323
+ * @param shown Each page as it is shown, for its own width and height.
324
+ * @param pageRuns Each page's runs, already placed on the shown page.
325
+ * @returns The section with measured margins, or `section` when nothing is
326
+ * measurable.
327
+ */
328
+ /** What the measure gives back, so the widest line still fits when re-set. */
329
+ var SLACK = .01;
330
+ /** How much of the sheet a margin down the page may take. */
331
+ var DEEPEST_MARGIN = .5;
332
+ /** How far a face's ascender stands above its baseline, as a fraction of the size. */
333
+ var ASCENDER = .8;
334
+ /** And its descender below — the two together are a little over one em. */
335
+ var DESCENDER = .22;
336
+ function withMeasuredMargins(section, shown, pageRuns) {
337
+ if (!section?.pageSize) return section;
338
+ const width = section.pageSize.width;
339
+ const height = section.pageSize.height;
340
+ const lefts = [];
341
+ const rights = [];
342
+ const tops = [];
343
+ const bottoms = [];
344
+ pageRuns.forEach((runs, i) => {
345
+ const page = shown[i];
346
+ if (!page || runs.length === 0) return;
347
+ let minX = Infinity;
348
+ let maxX = -Infinity;
349
+ let minY = Infinity;
350
+ let maxY = -Infinity;
351
+ let topSize = 0;
352
+ let bottomSize = 0;
353
+ for (const r of runs) {
354
+ if (!Number.isFinite(r.x) || !Number.isFinite(r.y)) continue;
355
+ minX = Math.min(minX, r.x);
356
+ maxX = Math.max(maxX, r.endX);
357
+ if (r.y < minY) {
358
+ minY = r.y;
359
+ bottomSize = r.fontSizePt;
360
+ }
361
+ if (r.y > maxY) {
362
+ maxY = r.y;
363
+ topSize = r.fontSizePt;
364
+ }
365
+ }
366
+ if (!Number.isFinite(minX) || !Number.isFinite(minY)) return;
367
+ lefts.push(minX);
368
+ rights.push(page.width - maxX);
369
+ tops.push(page.height - maxY - topSize * ASCENDER);
370
+ bottoms.push(minY - bottomSize * DESCENDER);
371
+ });
372
+ if (lefts.length === 0) return section;
373
+ const median = (xs) => {
374
+ const s = [...xs].sort((a, b) => a - b);
375
+ return s[Math.floor(s.length / 2)] ?? 0;
376
+ };
377
+ const clamp = (v, span, most = 1 / 3) => pt(Math.max(0, Math.min(v, span * most)));
378
+ return {
379
+ ...section,
380
+ margins: {
381
+ left: clamp(median(lefts), width),
382
+ right: clamp(median(rights) - width * SLACK, width),
383
+ top: clamp(Math.min(...tops), height, DEEPEST_MARGIN),
384
+ bottom: clamp(Math.min(...bottoms) - height * SLACK, height, DEEPEST_MARGIN)
385
+ }
386
+ };
387
+ }
388
+ /**
290
389
  * Assemble the final {@link FlowDoc} for a reconstruction: the body elements
291
390
  * with their styles resolved against the empty style sheet, the lifted-image
292
391
  * resource store, and the optional page {@link SectionProperties}. Shared by
293
392
  * both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
294
393
  * path EP4).
295
394
  */
296
- function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts) {
395
+ function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts, sections = [], headersFooters) {
297
396
  return {
298
397
  kind: "flow",
299
398
  body: resolveBodyStyles([...body], EMPTY_STYLE_SHEET),
300
- sections: [],
399
+ sections,
400
+ ...headersFooters && headersFooters.size > 0 ? { headersFooters } : {},
301
401
  ...section ? { section } : {},
302
402
  ...embeddedFonts && embeddedFonts.size > 0 ? { embeddedFonts } : {},
303
403
  styles: EMPTY_STYLE_SHEET,
@@ -305,4 +405,4 @@ function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFo
305
405
  };
306
406
  }
307
407
  //#endregion
308
- export { buildFlowDoc, dedupeLosses, imageBlock, paragraphBlock, paragraphFromRuns, positionedText, sectionFromPdfPages, shapeBlock };
408
+ export { buildFlowDoc, dedupeLosses, imageBlock, paragraphBlock, paragraphFromRuns, positionedText, sectionFromPdfPages, shapeBlock, withMeasuredMargins };