reamkit 1.27.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 (65) hide show
  1. package/README.md +6 -5
  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.js +114 -1
  17. package/dist/esm/pdf-reader/annots.d.ts +0 -14
  18. package/dist/esm/pdf-reader/annots.js +13 -1
  19. package/dist/esm/pdf-reader/ccitt.d.ts +2 -3
  20. package/dist/esm/pdf-reader/ccitt.js +32 -4
  21. package/dist/esm/pdf-reader/cff-outline.d.ts +36 -0
  22. package/dist/esm/pdf-reader/cff-outline.js +1122 -0
  23. package/dist/esm/pdf-reader/cmap.js +5 -2
  24. package/dist/esm/pdf-reader/content.d.ts +76 -0
  25. package/dist/esm/pdf-reader/content.js +142 -59
  26. package/dist/esm/pdf-reader/dingbats.d.ts +11 -0
  27. package/dist/esm/pdf-reader/dingbats.js +1033 -0
  28. package/dist/esm/pdf-reader/display.js +41 -1
  29. package/dist/esm/pdf-reader/document.js +26 -9
  30. package/dist/esm/pdf-reader/embedded-fonts.d.ts +11 -0
  31. package/dist/esm/pdf-reader/embedded-fonts.js +14 -1
  32. package/dist/esm/pdf-reader/encodings.d.ts +25 -0
  33. package/dist/esm/pdf-reader/encodings.js +110 -0
  34. package/dist/esm/pdf-reader/flow-build.d.ts +9 -3
  35. package/dist/esm/pdf-reader/flow-build.js +13 -7
  36. package/dist/esm/pdf-reader/font.js +329 -8
  37. package/dist/esm/pdf-reader/glyf-outline.d.ts +43 -0
  38. package/dist/esm/pdf-reader/glyf-outline.js +351 -0
  39. package/dist/esm/pdf-reader/glyph-names.js +20 -0
  40. package/dist/esm/pdf-reader/icc.d.ts +10 -0
  41. package/dist/esm/pdf-reader/icc.js +210 -0
  42. package/dist/esm/pdf-reader/image-decode.d.ts +4 -3
  43. package/dist/esm/pdf-reader/image-decode.js +85 -64
  44. package/dist/esm/pdf-reader/images.d.ts +6 -0
  45. package/dist/esm/pdf-reader/images.js +50 -7
  46. package/dist/esm/pdf-reader/jbig2.js +104 -19
  47. package/dist/esm/pdf-reader/layout.js +1148 -45
  48. package/dist/esm/pdf-reader/math-rows.d.ts +23 -0
  49. package/dist/esm/pdf-reader/math-rows.js +198 -0
  50. package/dist/esm/pdf-reader/predefined-cmap.d.ts +21 -0
  51. package/dist/esm/pdf-reader/predefined-cmap.js +102 -0
  52. package/dist/esm/pdf-reader/reader.d.ts +6 -9
  53. package/dist/esm/pdf-reader/reader.js +34 -21
  54. package/dist/esm/pdf-reader/shading.d.ts +81 -2
  55. package/dist/esm/pdf-reader/shading.js +191 -25
  56. package/dist/esm/pdf-reader/stream-filters.d.ts +6 -0
  57. package/dist/esm/pdf-reader/stream-filters.js +67 -0
  58. package/dist/esm/pdf-reader/text-rules.js +83 -10
  59. package/dist/esm/pdf-reader/text.js +82 -3
  60. package/dist/esm/pdf-reader/type1-outline.d.ts +21 -0
  61. package/dist/esm/pdf-reader/type1-outline.js +576 -0
  62. package/dist/esm/pdf-reader/vector.js +43 -4
  63. package/dist/esm/word/document-parser.js +4 -1
  64. package/dist/esm/word/docx-writer.js +1 -0
  65. package/package.json +1 -1
@@ -66,7 +66,47 @@ function placeRuns(runs, d) {
66
66
  endY: end.y,
67
67
  ...Math.abs(angle) > .5 ? { angleDeg: angle } : {}
68
68
  };
69
- }).filter((r) => shows(d, Math.min(r.x, r.endX), Math.min(r.y, r.endY) - r.fontSizePt * .25, Math.max(r.x, r.endX), Math.max(r.y, r.endY) + r.fontSizePt * .85));
69
+ }).filter((r) => shows(d, Math.min(r.x, r.endX), Math.min(r.y, r.endY) - r.fontSizePt * .25, Math.max(r.x, r.endX), Math.max(r.y, r.endY) + r.fontSizePt * .85)).map((r) => cropped(r, d));
70
+ }
71
+ /**
72
+ * §14.11.2 — a run the crop's edge cuts through, as the letters it shows.
73
+ *
74
+ * A run that reaches into the shown page was kept whole, which is right where
75
+ * the crop trims a hair and wrong where it trims a line: endchar.pdf is one
76
+ * line of a poster, "LE HOLD-UP PLANÉTAIRE", cropped to the fourteen points
77
+ * that hold its É. Every viewer shows that one letter. Reflowed, the whole
78
+ * line was re-set into a column fourteen points wide and came back as four
79
+ * pages of one letter each.
80
+ *
81
+ * A letter is kept where any part of it is inside, so a crop that shaves an
82
+ * edge takes nothing. Where in the run each letter falls is estimated from the
83
+ * run's own width, which is exact for a face set solid and near enough for one
84
+ * that is not — the answer is a letter either way.
85
+ *
86
+ * @param run The run, already placed on the shown page.
87
+ * @param d The page's shown geometry.
88
+ * @returns The run, or the part of it the page shows.
89
+ */
90
+ function cropped(run, d) {
91
+ const from = Math.min(run.x, run.endX);
92
+ const to = Math.max(run.x, run.endX);
93
+ const chars = [...run.text];
94
+ if (from >= 0 && to <= d.width) return run;
95
+ if (run.angleDeg !== void 0 || chars.length < 2 || !(to > from)) return run;
96
+ const step = (to - from) / chars.length;
97
+ const first = Math.max(0, Math.floor((0 - from) / step));
98
+ const last = Math.min(chars.length - 1, Math.ceil((d.width - from) / step) - 1);
99
+ if (first > last) return run;
100
+ if (first === 0 && last === chars.length - 1) return run;
101
+ const backwards = run.endX < run.x;
102
+ const startX = from + first * step;
103
+ const endX = from + (last + 1) * step;
104
+ return {
105
+ ...run,
106
+ text: chars.slice(first, last + 1).join(""),
107
+ x: backwards ? endX : startX,
108
+ endX: backwards ? startX : endX
109
+ };
70
110
  }
71
111
  /**
72
112
  * §14.11.2 — whether a box falls inside the region the page SHOWS.
@@ -1,8 +1,10 @@
1
1
  import { PDF_NULL, PdfName, PdfRef, PdfStream } from "../pdf/objects.js";
2
+ import { lzwDecodeMsb } from "../core/lzw.js";
2
3
  import { buildDecryptor } from "./decrypt.js";
3
4
  import { Lexer } from "./lexer.js";
4
5
  import { parseIndirectObject, parseObject } from "./parser.js";
5
6
  import { reversePredictor } from "./predictor.js";
7
+ import { ascii85Decode, asciiHexDecode, runLengthDecode } from "./stream-filters.js";
6
8
  import { unzlibSync } from "fflate";
7
9
  //#region src/pdf-reader/document.ts
8
10
  var DEFAULT_MEDIA_BOX = [
@@ -219,7 +221,19 @@ var PdfFile = class PdfFile {
219
221
  data = unzlibSync(data);
220
222
  flate = true;
221
223
  } catch {}
222
- else if (this.filters[f.value]) {
224
+ else if (GENERAL_FILTERS[f.value]) {
225
+ data = GENERAL_FILTERS[f.value](data);
226
+ flate = true;
227
+ } else if (f.value === "LZWDecode" || f.value === "LZW") {
228
+ const parms = this.resolve(stream.dict.get("DecodeParms") ?? PDF_NULL);
229
+ const p = Array.isArray(parms) ? this.resolve(parms[0] ?? PDF_NULL) : parms;
230
+ const early = p instanceof Map ? this.resolve(p.get("EarlyChange") ?? PDF_NULL) : void 0;
231
+ data = lzwDecodeMsb(data, {
232
+ earlyChange: early === 0 ? 0 : 1,
233
+ limit: MAX_LZW_OUT
234
+ });
235
+ flate = true;
236
+ } else if (this.filters[f.value]) {
223
237
  const decoded = runFilter(this.filters[f.value], data);
224
238
  if (decoded) data = decoded;
225
239
  else this.unknownFilters.add(f.value);
@@ -240,15 +254,18 @@ function runFilter(filter, data) {
240
254
  return;
241
255
  }
242
256
  }
257
+ /** A decompressed LZW stream larger than this is a bomb, not a document. */
258
+ var MAX_LZW_OUT = 1 << 28;
259
+ /** §7.4.2–7.4.5 — the filters that are transport, whatever the stream holds. */
260
+ var GENERAL_FILTERS = {
261
+ ASCIIHexDecode: asciiHexDecode,
262
+ AHx: asciiHexDecode,
263
+ ASCII85Decode: ascii85Decode,
264
+ A85: ascii85Decode,
265
+ RunLengthDecode: runLengthDecode,
266
+ RL: runLengthDecode
267
+ };
243
268
  var PASSTHROUGH_FILTERS = new Set([
244
- "LZWDecode",
245
- "LZW",
246
- "RunLengthDecode",
247
- "RL",
248
- "ASCII85Decode",
249
- "A85",
250
- "ASCIIHexDecode",
251
- "AHx",
252
269
  "DCTDecode",
253
270
  "DCT",
254
271
  "JPXDecode",
@@ -38,3 +38,14 @@ export declare function collectEmbeddedFonts(file: PdfFile, pages: ReadonlyArray
38
38
  * @returns The name, or `undefined` when the font states none.
39
39
  */
40
40
  export declare function embeddedFontName(file: PdfFile, fontDict: PdfDict): string | undefined;
41
+ /**
42
+ * Whether this font carries a program this pipeline can set the page in.
43
+ *
44
+ * Only `/FontFile2` is liftable, and a run in such a face is filed under the
45
+ * face's own name — so that name must be left exactly as it is. Every other
46
+ * face is SUBSTITUTED, and its name is free to say what it is.
47
+ *
48
+ * @param file The document.
49
+ * @param fontDict The font dictionary.
50
+ */
51
+ export declare function hasLiftableProgram(file: PdfFile, fontDict: PdfDict): boolean;
@@ -92,6 +92,19 @@ function embeddedFontName(file, fontDict) {
92
92
  const name = base.value.replace(/^[A-Z]{6}\+/u, "").trim();
93
93
  return name.length > 0 ? name.toLowerCase() : void 0;
94
94
  }
95
+ /**
96
+ * Whether this font carries a program this pipeline can set the page in.
97
+ *
98
+ * Only `/FontFile2` is liftable, and a run in such a face is filed under the
99
+ * face's own name — so that name must be left exactly as it is. Every other
100
+ * face is SUBSTITUTED, and its name is free to say what it is.
101
+ *
102
+ * @param file The document.
103
+ * @param fontDict The font dictionary.
104
+ */
105
+ function hasLiftableProgram(file, fontDict) {
106
+ return fontProgram(file, fontDict) !== void 0;
107
+ }
95
108
  /** §9.9 `/FontFile2` — the TrueType program, off the font or its descendant. */
96
109
  function fontProgram(file, fontDict) {
97
110
  const owner = descendant(file, fontDict) ?? fontDict;
@@ -110,4 +123,4 @@ function descendant(file, fontDict) {
110
123
  return first instanceof Map ? first : void 0;
111
124
  }
112
125
  //#endregion
113
- export { collectEmbeddedFonts, embeddedFontName };
126
+ export { collectEmbeddedFonts, embeddedFontName, hasLiftableProgram };
@@ -0,0 +1,25 @@
1
+ /** One of the base encodings this reader has a table for (Annex D.2). */
2
+ export type BaseEncodingName = 'StandardEncoding' | 'WinAnsiEncoding' | 'MacRomanEncoding';
3
+ /**
4
+ * The glyph names of a base encoding, or `undefined` for a name this has no
5
+ * table for — `/MacExpertEncoding`, whose repertory no reader here can set.
6
+ *
7
+ * @param name The `/Encoding` or `/BaseEncoding` name, without the slash.
8
+ */
9
+ export declare function baseEncodingTable(name: string): ReadonlyMap<number, string> | undefined;
10
+ /** The encoding built into the standard Latin text faces (§9.6.2.2). */
11
+ export declare function standardEncodingTable(): ReadonlyMap<number, string>;
12
+ /**
13
+ * The name a `post` table's glyph-name index below 258 stands for.
14
+ *
15
+ * @param index The index as the table states it.
16
+ * @returns The name, or `undefined` for an index outside the standard order.
17
+ */
18
+ export declare function macGlyphName(index: number): string | undefined;
19
+ /**
20
+ * Whether a `/BaseFont` names one of the standard Latin faces, whose built-in
21
+ * encoding is StandardEncoding.
22
+ *
23
+ * @param baseFont The name as the font dictionary states it.
24
+ */
25
+ export declare function isStandardLatinFace(baseFont: string): boolean;
@@ -0,0 +1,110 @@
1
+ //#region src/pdf-reader/encodings.ts
2
+ /**
3
+ * Code → glyph name, from names read in code order. `.` marks a code the
4
+ * encoding leaves unused, and the rows are the spec's own — sixteen to a line,
5
+ * so a row can be checked against Annex D at a glance.
6
+ */
7
+ function table(start, ...rows) {
8
+ const out = /* @__PURE__ */ new Map();
9
+ let code = start;
10
+ for (const row of rows) for (const name of row.split(/\s+/u).filter(Boolean)) {
11
+ if (name !== ".") out.set(code, name);
12
+ code++;
13
+ }
14
+ return out;
15
+ }
16
+ var ASCII = table(32, "space exclam quotedbl numbersign dollar percent ampersand quotesingle parenleft parenright asterisk plus comma hyphen period slash", "zero one two three four five six seven eight nine colon semicolon less equal greater question", "at A B C D E F G H I J K L M N O", "P Q R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore", "grave a b c d e f g h i j k l m n o", "p q r s t u v w x y z braceleft bar braceright asciitilde .");
17
+ /** Annex D.2 STD — the built-in encoding of the standard Latin text faces. */
18
+ var STANDARD = new Map([
19
+ ...ASCII,
20
+ ...table(39, "quoteright"),
21
+ ...table(96, "quoteleft"),
22
+ ...table(160, ". exclamdown cent sterling fraction yen florin section currency quotesingle quotedblleft guillemotleft guilsinglleft guilsinglright fi fl", ". endash dagger daggerdbl periodcentered . paragraph bullet quotesinglbase quotedblbase quotedblright guillemotright ellipsis perthousand . questiondown", ". grave acute circumflex tilde macron breve dotaccent dieresis . ring cedilla . hungarumlaut ogonek caron", "emdash . . . . . . . . . . . . . . .", ". AE . ordfeminine . . . . Lslash Oslash OE ordmasculine . . . .", ". ae . . . dotlessi . . lslash oslash oe germandbls . . . .")
23
+ ]);
24
+ var TABLES = {
25
+ StandardEncoding: STANDARD,
26
+ WinAnsiEncoding: new Map([...ASCII, ...table(128, "Euro . quotesinglbase florin quotedblbase ellipsis dagger daggerdbl circumflex perthousand Scaron guilsinglleft OE . Zcaron .", ". quoteleft quoteright quotedblleft quotedblright bullet endash emdash tilde trademark scaron guilsinglright oe . zcaron Ydieresis")]),
27
+ MacRomanEncoding: new Map([...ASCII, ...table(128, "Adieresis Aring Ccedilla Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute egrave", "ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave ucircumflex udieresis", "dagger degree cent sterling section bullet paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash", "infinity plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine ordmasculine Omega ae oslash", "questiondown exclamdown logicalnot radical florin approxequal Delta guillemotleft guillemotright ellipsis space Agrave Atilde Otilde OE oe", "endash emdash quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright fi fl", "daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex", ". Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent ring cedilla hungarumlaut ogonek caron")])
28
+ };
29
+ /**
30
+ * The glyph names of a base encoding, or `undefined` for a name this has no
31
+ * table for — `/MacExpertEncoding`, whose repertory no reader here can set.
32
+ *
33
+ * @param name The `/Encoding` or `/BaseEncoding` name, without the slash.
34
+ */
35
+ function baseEncodingTable(name) {
36
+ return name in TABLES ? TABLES[name] : void 0;
37
+ }
38
+ /** The encoding built into the standard Latin text faces (§9.6.2.2). */
39
+ function standardEncodingTable() {
40
+ return STANDARD;
41
+ }
42
+ var STANDARD_LATIN_FACES = new Set([
43
+ "courier",
44
+ "courier-bold",
45
+ "courier-oblique",
46
+ "courier-boldoblique",
47
+ "helvetica",
48
+ "helvetica-bold",
49
+ "helvetica-oblique",
50
+ "helvetica-boldoblique",
51
+ "times-roman",
52
+ "times-bold",
53
+ "times-italic",
54
+ "times-bolditalic"
55
+ ]);
56
+ var MAC_ORDER = `
57
+ .notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar
58
+ percent ampersand quotesingle parenleft parenright asterisk plus comma
59
+ hyphen period slash zero one two three four
60
+ five six seven eight nine colon semicolon less
61
+ equal greater question at A B C D
62
+ E F G H I J K L
63
+ M N O P Q R S T
64
+ U V W X Y Z bracketleft backslash
65
+ bracketright asciicircum underscore grave a b c d
66
+ e f g h i j k l
67
+ m n o p q r s t
68
+ u v w x y z braceleft bar
69
+ braceright asciitilde Adieresis Aring Ccedilla Eacute Ntilde Odieresis
70
+ Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla
71
+ eacute egrave ecircumflex edieresis iacute igrave icircumflex idieresis
72
+ ntilde oacute ograve ocircumflex odieresis otilde uacute ugrave
73
+ ucircumflex udieresis dagger degree cent sterling section bullet
74
+ paragraph germandbls registered copyright trademark acute dieresis notequal
75
+ AE Oslash infinity plusminus lessequal greaterequal yen mu
76
+ partialdiff summation product pi integral ordfeminine ordmasculine Omega
77
+ ae oslash questiondown exclamdown logicalnot radical florin approxequal
78
+ Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde
79
+ OE oe endash emdash quotedblleft quotedblright quoteleft quoteright
80
+ divide lozenge ydieresis Ydieresis fraction currency guilsinglleft guilsinglright
81
+ fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand Acircumflex
82
+ Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave
83
+ Oacute Ocircumflex apple Ograve Uacute Ucircumflex Ugrave dotlessi
84
+ circumflex tilde macron breve dotaccent ring cedilla hungarumlaut
85
+ ogonek caron Lslash lslash Scaron scaron Zcaron zcaron
86
+ brokenbar Eth eth Yacute yacute Thorn thorn minus
87
+ multiply onesuperior twosuperior threesuperior onehalf onequarter threequarters franc
88
+ Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron
89
+ ccaron dcroat
90
+ `.split(/\s+/u).filter(Boolean);
91
+ /**
92
+ * The name a `post` table's glyph-name index below 258 stands for.
93
+ *
94
+ * @param index The index as the table states it.
95
+ * @returns The name, or `undefined` for an index outside the standard order.
96
+ */
97
+ function macGlyphName(index) {
98
+ return MAC_ORDER[index];
99
+ }
100
+ /**
101
+ * Whether a `/BaseFont` names one of the standard Latin faces, whose built-in
102
+ * encoding is StandardEncoding.
103
+ *
104
+ * @param baseFont The name as the font dictionary states it.
105
+ */
106
+ function isStandardLatinFace(baseFont) {
107
+ return STANDARD_LATIN_FACES.has(baseFont.trim().replace(/^[A-Za-z]{6}\+/u, "").toLowerCase());
108
+ }
109
+ //#endregion
110
+ export { baseEncodingTable, isStandardLatinFace, macGlyphName, standardEncodingTable };
@@ -1,4 +1,4 @@
1
- import { BodyElement, ParagraphProperties, SectionProperties, TextOutline } from '../core/document-model/index.js';
1
+ import { BodyElement, ParagraphProperties, Section, SectionProperties, TextOutline } from '../core/document-model/index.js';
2
2
  import { FlowDoc } from '../core/ir/flow.js';
3
3
  import { FontRegistry } from '../core/font/index.js';
4
4
  import { Loss, ResourceStore } from '../core/ir/index.js';
@@ -51,6 +51,12 @@ export interface TextSpan {
51
51
  readonly bold?: boolean;
52
52
  /** §9.8.1 — the face was a slanted one. */
53
53
  readonly italic?: boolean;
54
+ /**
55
+ * §17.3.2.42 — the glyphs stood OFF the baseline the line is set on, and
56
+ * smaller: a footnote mark, an exponent, an index. The page states it by
57
+ * placement, and a document by the property.
58
+ */
59
+ readonly script?: 'superscript' | 'subscript';
54
60
  /** §12.5.6.10 — a text-markup annotation marks these words. */
55
61
  readonly markup?: TextMarkup;
56
62
  }
@@ -60,7 +66,7 @@ export interface TextSpan {
60
66
  * survives as its own run) and squashing whitespace. With no hrefs this
61
67
  * collapses to a single run — the same shape {@link paragraphBlock} produces.
62
68
  */
63
- export declare function paragraphFromRuns(spans: ReadonlyArray<TextSpan>, outlineLevel?: number, placement?: Pick<ParagraphProperties, 'alignment' | 'spacingBefore'>): BodyElement;
69
+ export declare function paragraphFromRuns(spans: ReadonlyArray<TextSpan>, outlineLevel?: number, placement?: Pick<ParagraphProperties, 'alignment' | 'spacingBefore' | 'indentLeft' | 'indentFirstLine'>): BodyElement;
64
70
  /**
65
71
  * Store a {@link PdfImage}'s bytes (content-addressed dedup) and build the image
66
72
  * {@link BodyElement} that references them, sized in points from the placement
@@ -128,4 +134,4 @@ export declare function withMeasuredMargins(section: SectionProperties | undefin
128
134
  * both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
129
135
  * path EP4).
130
136
  */
131
- export declare function buildFlowDoc(body: ReadonlyArray<BodyElement>, resources?: ResourceStore, section?: SectionProperties, embeddedFonts?: ReadonlyMap<string, FontRegistry>): FlowDoc;
137
+ export declare function buildFlowDoc(body: ReadonlyArray<BodyElement>, resources?: ResourceStore, section?: SectionProperties, embeddedFonts?: ReadonlyMap<string, FontRegistry>, sections?: ReadonlyArray<Section>, headersFooters?: ReadonlyMap<string, ReadonlyArray<BodyElement>>): FlowDoc;
@@ -31,7 +31,7 @@ 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 && sameMarkup(last.markup, s.markup)) 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 } : {},
@@ -41,12 +41,13 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
41
41
  ...s.outline !== void 0 ? { outline: s.outline } : {},
42
42
  ...s.bold !== void 0 ? { bold: s.bold } : {},
43
43
  ...s.italic !== void 0 ? { italic: s.italic } : {},
44
+ ...s.script !== void 0 ? { script: s.script } : {},
44
45
  ...s.markup !== void 0 ? { markup: s.markup } : {}
45
46
  });
46
47
  }
47
48
  const runs = merged.map((m) => ({
48
49
  ...m,
49
- text: m.text.replace(/\s+/g, " ")
50
+ text: m.text.replace(/[^\S\t]+/gu, " ")
50
51
  })).filter((m) => m.text.length > 0);
51
52
  if (runs.length > 0) {
52
53
  runs[0].text = runs[0].text.replace(/^ /, "");
@@ -68,6 +69,7 @@ function paragraphFromRuns(spans, outlineLevel, placement) {
68
69
  ...r.outline !== void 0 ? { textOutline: r.outline } : {},
69
70
  ...r.bold ? { bold: true } : {},
70
71
  ...r.italic ? { italic: true } : {},
72
+ ...r.script !== void 0 ? { verticalAlign: r.script } : {},
71
73
  ...r.markup?.highlightHex !== void 0 ? { shadingColorHex: r.markup.highlightHex } : {},
72
74
  ...r.markup?.underline !== void 0 ? { underline: r.markup.underline } : {},
73
75
  ...r.markup?.underlineHex !== void 0 ? { underlineColorHex: r.markup.underlineHex } : {},
@@ -111,6 +113,7 @@ function imageBlock(image, resources, alt, frame, zOrder, behind = false) {
111
113
  height: pt(image.heightPt),
112
114
  ...image.rotationDeg !== void 0 ? { rotation60k: Math.round(-image.rotationDeg * 6e4) } : {},
113
115
  ...image.crop ? { crop: image.crop } : {},
116
+ ...image.alpha !== void 0 ? { alpha: image.alpha } : {},
114
117
  paragraphProperties: {},
115
118
  ...alt ? { altText: alt } : {}
116
119
  }
@@ -324,6 +327,8 @@ function sectionFromPdfPages(pages) {
324
327
  */
325
328
  /** What the measure gives back, so the widest line still fits when re-set. */
326
329
  var SLACK = .01;
330
+ /** How much of the sheet a margin down the page may take. */
331
+ var DEEPEST_MARGIN = .5;
327
332
  /** How far a face's ascender stands above its baseline, as a fraction of the size. */
328
333
  var ASCENDER = .8;
329
334
  /** And its descender below — the two together are a little over one em. */
@@ -369,14 +374,14 @@ function withMeasuredMargins(section, shown, pageRuns) {
369
374
  const s = [...xs].sort((a, b) => a - b);
370
375
  return s[Math.floor(s.length / 2)] ?? 0;
371
376
  };
372
- const clamp = (v, span) => pt(Math.max(0, Math.min(v, span / 3)));
377
+ const clamp = (v, span, most = 1 / 3) => pt(Math.max(0, Math.min(v, span * most)));
373
378
  return {
374
379
  ...section,
375
380
  margins: {
376
381
  left: clamp(median(lefts), width),
377
382
  right: clamp(median(rights) - width * SLACK, width),
378
- top: clamp(median(tops), height),
379
- bottom: clamp(median(bottoms), height)
383
+ top: clamp(Math.min(...tops), height, DEEPEST_MARGIN),
384
+ bottom: clamp(Math.min(...bottoms) - height * SLACK, height, DEEPEST_MARGIN)
380
385
  }
381
386
  };
382
387
  }
@@ -387,11 +392,12 @@ function withMeasuredMargins(section, shown, pageRuns) {
387
392
  * both reconstruction paths (the tagged fast-path EP3 and the heuristic layout
388
393
  * path EP4).
389
394
  */
390
- function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts) {
395
+ function buildFlowDoc(body, resources = new ResourceStore(), section, embeddedFonts, sections = [], headersFooters) {
391
396
  return {
392
397
  kind: "flow",
393
398
  body: resolveBodyStyles([...body], EMPTY_STYLE_SHEET),
394
- sections: [],
399
+ sections,
400
+ ...headersFooters && headersFooters.size > 0 ? { headersFooters } : {},
395
401
  ...section ? { section } : {},
396
402
  ...embeddedFonts && embeddedFonts.size > 0 ? { embeddedFonts } : {},
397
403
  styles: EMPTY_STYLE_SHEET,