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
@@ -19,7 +19,9 @@ var DEFAULT_BORDER_PT = 1;
19
19
  function drawnAppearance(file, annot) {
20
20
  const subtype = file.get(annot, "Subtype");
21
21
  if (!(subtype instanceof PdfName)) return void 0;
22
- if (subtype.value === "Widget") return typedValue(file, annot);
22
+ if (subtype.value === "Widget") return typedValue(file, annot) ?? checkedBox(file, annot);
23
+ const markup = markupShape(file, annot, subtype.value);
24
+ if (markup) return markup;
23
25
  const pen = borderWidth(file, annot);
24
26
  const drawing = pathFor(file, annot, subtype.value, pen);
25
27
  if (!drawing || drawing.ops.length === 0) return void 0;
@@ -37,6 +39,117 @@ function drawnAppearance(file, annot) {
37
39
  return new PdfStream(/* @__PURE__ */ new Map(), new TextEncoder().encode(body));
38
40
  }
39
41
  /**
42
+ * §12.7.4.2 — a check box or radio button whose appearance was never generated.
43
+ *
44
+ * Its state is `/AS`, or `/V` where the widget states none, and `/Off` means
45
+ * exactly that: nothing is drawn. Anything else is the ON state, and what a
46
+ * viewer draws for it is the caption `/MK /CA` — one character of ZapfDingbats,
47
+ * `4` (a check) by default, `l` (a filled circle) for the radio buttons that
48
+ * ask for it.
49
+ *
50
+ * The border and background come from `/MK`, and where the file gives none
51
+ * neither is drawn: checkbox_no_appearance.pdf states no `/MK` at all, and
52
+ * poppler draws its ticked box as a bare check mark on the paper.
53
+ */
54
+ function checkedBox(file, annot) {
55
+ if (inherited(file, annot, "FT") !== "Btn") return void 0;
56
+ const as = file.get(annot, "AS");
57
+ const state = as instanceof PdfName ? as.value : inherited(file, annot, "V");
58
+ const rect = rectangle(file.get(annot, "Rect"));
59
+ if (!rect) return void 0;
60
+ const [x0, y0, x1, y1] = rect;
61
+ const w = x1 - x0;
62
+ const h = y1 - y0;
63
+ if (!(w > 0) || !(h > 0)) return void 0;
64
+ const mk = file.get(annot, "MK");
65
+ const border = mk instanceof Map ? colorOf(file.get(mk, "BC")) : void 0;
66
+ const ground = mk instanceof Map ? colorOf(file.get(mk, "BG")) : void 0;
67
+ const pen = borderWidth(file, annot);
68
+ const ops = ["q"];
69
+ if (ground !== void 0) ops.push(`${ground} rg`, `${num(x0)} ${num(y0)} ${num(w)} ${num(h)} re`, "f");
70
+ if (border !== void 0 && pen > 0) ops.push(`${border} RG`, `${num(pen)} w`, `${num(x0 + pen / 2)} ${num(y0 + pen / 2)} ${num(w - pen)} ${num(h - pen)} re`, "S");
71
+ if (state !== void 0 && state !== "Off") {
72
+ const stated = mk instanceof Map ? file.get(mk, "CA") : void 0;
73
+ const caption = typeof stated === "string" && stated.length > 0 ? stated[0] : "4";
74
+ const ink = defaultAppearance(file, annot).color;
75
+ const side = Math.min(w, h) * CAPTION_EM;
76
+ const cx = x0 + w / 2;
77
+ const cy = y0 + h / 2;
78
+ if (caption === "l" || caption === "n") {
79
+ ops.push(`${ink} rg`);
80
+ ops.push(...caption === "n" ? [`${num(cx - side / 2)} ${num(cy - side / 2)} ${num(side)} ${num(side)} re`] : circleOps(cx, cy, side / 2), "f");
81
+ } else {
82
+ const pen = Math.max(.6, side * CHECK_PEN_EM);
83
+ ops.push(`${ink} RG`, `${num(pen)} w`, "1 J", "1 j", `${num(cx - side * .4)} ${num(cy + side * .05)} m`, `${num(cx - side * .12)} ${num(cy - side * .32)} l`, `${num(cx + side * .42)} ${num(cy + side * .36)} l`, "S");
84
+ }
85
+ }
86
+ ops.push("Q");
87
+ if (ops.length <= 2) return void 0;
88
+ return new PdfStream(/* @__PURE__ */ new Map(), new TextEncoder().encode(ops.join("\n")));
89
+ }
90
+ /** How much of the box the mark fills, and how thick the check's pen is. */
91
+ var CAPTION_EM = .8;
92
+ var CHECK_PEN_EM = .13;
93
+ /** A circle of `r` about `(cx, cy)`, as the four Bézier arcs that draw one. */
94
+ function circleOps(cx, cy, r) {
95
+ const k = r * .5523;
96
+ return [
97
+ `${num(cx - r)} ${num(cy)} m`,
98
+ `${num(cx - r)} ${num(cy + k)} ${num(cx - k)} ${num(cy + r)} ${num(cx)} ${num(cy + r)} c`,
99
+ `${num(cx + k)} ${num(cy + r)} ${num(cx + r)} ${num(cy + k)} ${num(cx + r)} ${num(cy)} c`,
100
+ `${num(cx + r)} ${num(cy - k)} ${num(cx + k)} ${num(cy - r)} ${num(cx)} ${num(cy - r)} c`,
101
+ `${num(cx - k)} ${num(cy - r)} ${num(cx - r)} ${num(cy - k)} ${num(cx - r)} ${num(cy)} c`
102
+ ];
103
+ }
104
+ /**
105
+ * §12.5.6.10 — a text markup drawn as a MARK on the paper.
106
+ *
107
+ * The usual reading puts it on the runs it covers, which is right for a page
108
+ * with words on it. bug1538111.pdf has none: four markup annotations over an
109
+ * empty page, and read as marks about text that is not there they came back as
110
+ * nothing at all. Drawn, each is what its subtype says over its own quads.
111
+ */
112
+ function markupShape(file, annot, kind) {
113
+ const markup = textMarkupOf(file, annot);
114
+ if (!markup) return void 0;
115
+ const rgb = colorOf(file.get(annot, "C")) ?? "0 0 0";
116
+ const ops = [
117
+ "q",
118
+ `${rgb} rg`,
119
+ `${rgb} RG`
120
+ ];
121
+ for (const q of markup.quads) {
122
+ const left = q.x0;
123
+ const right = q.x1;
124
+ const bottom = q.y0;
125
+ const h = q.h;
126
+ if (!(right > left) || !(h > 0)) continue;
127
+ if (kind === "Highlight") {
128
+ ops.push(`${num(left)} ${num(bottom)} ${num(right - left)} ${num(h)} re`, "f");
129
+ continue;
130
+ }
131
+ const pen = Math.max(.5, h * MARK_PEN_EM);
132
+ if (kind === "Squiggly") {
133
+ const amp = Math.max(.75, h * SQUIGGLE_AMP_EM);
134
+ const step = amp * 2;
135
+ ops.push(`${num(pen)} w`, `${num(left)} ${num(bottom + amp)} m`);
136
+ let up = true;
137
+ for (let x = left + step; x < right; x += step, up = !up) ops.push(`${num(x)} ${num(bottom + (up ? amp * 2 : 0))} l`);
138
+ ops.push("S");
139
+ continue;
140
+ }
141
+ const y = kind === "StrikeOut" ? bottom + h / 2 : bottom + pen;
142
+ ops.push(`${num(pen)} w`, `${num(left)} ${num(y)} m`, `${num(right)} ${num(y)} l`, "S");
143
+ }
144
+ if (ops.length <= 3) return void 0;
145
+ ops.push("Q");
146
+ return new PdfStream(/* @__PURE__ */ new Map(), new TextEncoder().encode(ops.join("\n")));
147
+ }
148
+ /** How thick a drawn underline or strike is, as a share of the line's height. */
149
+ var MARK_PEN_EM = .05;
150
+ /** How far a squiggle rises above its baseline, likewise. */
151
+ var SQUIGGLE_AMP_EM = .07;
152
+ /**
40
153
  * §12.7.2 `/DR` — the resources a generated field appearance draws with.
41
154
  *
42
155
  * The `/DA` string names a font (`/Helv 12 Tf`) and that name means nothing
@@ -9,18 +9,4 @@ export interface Appearance {
9
9
  /** The appearance's `/Resources`, when it states its own. */
10
10
  readonly resources: PdfDict | undefined;
11
11
  }
12
- /**
13
- * Every annotation appearance the page shows, in `/Annots` order — which is
14
- * the order they paint in, over the page's own content.
15
- *
16
- * A `Popup` is a note's window and is never part of the page. An annotation
17
- * flagged Hidden or NoView paints nothing. An `/AP` `/N` may be a stream or a
18
- * dictionary of states, in which case `/AS` names the one in force. An
19
- * annotation with no appearance at all gets one written for it from its own
20
- * geometry, where its subtype says exactly what that is ({@link drawnAppearance}).
21
- *
22
- * @param file The owning file, for resolving references.
23
- * @param page The page whose annotations are wanted.
24
- * @returns The appearances, each with the matrix that places it on the page.
25
- */
26
12
  export declare function collectPageAppearances(file: PdfFile, page: PdfPage): Array<Appearance>;
@@ -19,6 +19,18 @@ var FLAG_NOVIEW = 32;
19
19
  * @param page The page whose annotations are wanted.
20
20
  * @returns The appearances, each with the matrix that places it on the page.
21
21
  */
22
+ /** Whether the page's own content stream shows any glyphs at all. */
23
+ function pageHasText(file, page) {
24
+ const had = textful.get(page.dict);
25
+ if (had !== void 0) return had;
26
+ const content = file.pageContent(page);
27
+ let found = false;
28
+ for (let i = 0; i + 1 < content.length && !found; i++) found = content[i] === 66 && content[i + 1] === 84;
29
+ textful.set(page.dict, found);
30
+ return found;
31
+ }
32
+ /** One answer per page: the collector is called from three passes. */
33
+ var textful = /* @__PURE__ */ new WeakMap();
22
34
  function collectPageAppearances(file, page) {
23
35
  const annots = file.get(page.dict, "Annots");
24
36
  if (!Array.isArray(annots)) return [];
@@ -28,7 +40,7 @@ function collectPageAppearances(file, page) {
28
40
  if (!(annot instanceof Map)) continue;
29
41
  const subtype = file.get(annot, "Subtype");
30
42
  if (subtype instanceof PdfName && subtype.value === "Popup") continue;
31
- if (textMarkupOf(file, annot)) continue;
43
+ if (textMarkupOf(file, annot) && pageHasText(file, page)) continue;
32
44
  const flags = file.get(annot, "F");
33
45
  if (typeof flags === "number" && (flags & FLAG_HIDDEN || flags & FLAG_NOVIEW)) continue;
34
46
  const stream = normalAppearance(file, annot);
@@ -3,7 +3,7 @@
3
3
  * §7.4.6), pulled from the filter's `/DecodeParms`.
4
4
  */
5
5
  export interface CcittParams {
6
- /** `/K` — `<0` Group 4, `0` Group 3 1-D, `>0` Group 3 2-D (unsupported). */
6
+ /** `/K` — `<0` Group 4, `0` Group 3 1-D, `>0` Group 3 mixed 1-D/2-D. */
7
7
  readonly k: number;
8
8
  /** `/Columns` (pixels per row). */
9
9
  readonly columns: number;
@@ -19,8 +19,7 @@ export interface CcittParams {
19
19
  * @param data The raw fax codestream (any wrapping filters already stripped).
20
20
  * @param params The `/CCITTFaxDecode` parameters.
21
21
  * @returns The packed bitmap (`rowBytes × rows`, bit 1 = black, MSB first), or
22
- * `undefined` when the stream cannot be decoded (e.g. Group 3 2-D, or nothing
23
- * decoded at all).
22
+ * `undefined` when nothing could be decoded at all.
24
23
  */
25
24
  export declare function decodeCcitt(data: Uint8Array, params: CcittParams): Uint8Array | undefined;
26
25
  /**
@@ -6,8 +6,7 @@
6
6
  * @param data The raw fax codestream (any wrapping filters already stripped).
7
7
  * @param params The `/CCITTFaxDecode` parameters.
8
8
  * @returns The packed bitmap (`rowBytes × rows`, bit 1 = black, MSB first), or
9
- * `undefined` when the stream cannot be decoded (e.g. Group 3 2-D, or nothing
10
- * decoded at all).
9
+ * `undefined` when nothing could be decoded at all.
11
10
  */
12
11
  function decodeCcitt(data, params) {
13
12
  return decodeInto(new BitReader(data), params);
@@ -48,14 +47,18 @@ function decodeCcittPlanes(data, columns, rows, count) {
48
47
  }
49
48
  function decodeInto(reader, params) {
50
49
  const { k, columns, rows, byteAlign } = params;
51
- if (k > 0) return void 0;
52
50
  if (columns <= 0 || rows <= 0 || columns > 1 << 20) return void 0;
53
51
  const rowBytes = columns + 7 >> 3;
54
52
  const out = new Uint8Array(rowBytes * rows);
55
53
  let ref = [columns, columns];
56
54
  for (let y = 0; y < rows; y++) {
57
55
  if (byteAlign && y > 0) reader.align();
58
- const cur = k < 0 ? decode2D(reader, ref, columns) : decode1D(reader, columns);
56
+ let twoDimensional = k < 0;
57
+ if (k > 0) {
58
+ reader.skipEol();
59
+ twoDimensional = reader.readBit() === 0;
60
+ } else if (k === 0) reader.skipEol();
61
+ const cur = twoDimensional ? decode2D(reader, ref, columns) : decode1D(reader, columns);
59
62
  if (!cur) {
60
63
  if (y === 0) return void 0;
61
64
  break;
@@ -182,6 +185,29 @@ var BitReader = class {
182
185
  }
183
186
  }
184
187
  /**
188
+ * T.4 §4.1.2 — step over an end-of-line, which is eleven zeroes and a one.
189
+ * A stream that carries none is left exactly where it stands.
190
+ */
191
+ skipEol() {
192
+ const at = {
193
+ byte: this.bytePos,
194
+ bit: this.bitPos
195
+ };
196
+ let zeros = 0;
197
+ for (;;) {
198
+ const b = this.readBit();
199
+ if (b < 0 || b === 0 && zeros > MAX_EOL_FILL) break;
200
+ if (b === 0) {
201
+ zeros++;
202
+ continue;
203
+ }
204
+ if (zeros >= 11) return;
205
+ break;
206
+ }
207
+ this.bytePos = at.byte;
208
+ this.bitPos = at.bit;
209
+ }
210
+ /**
185
211
  * Step over the end-of-facsimile-block that closes an MMR plane: two EOLs,
186
212
  * each eleven zeroes and a one. Anything else is left where it stands.
187
213
  */
@@ -214,6 +240,8 @@ var BitReader = class {
214
240
  }
215
241
  }
216
242
  };
243
+ /** How much fill an end-of-line may carry before this stops looking for one. */
244
+ var MAX_EOL_FILL = 64;
217
245
  /**
218
246
  * T.4 white-run modified-Huffman codes as `[run, bit-string]` (terminating runs
219
247
  * 0..63, make-up runs multiples of 64). Exported so the test can build an
@@ -0,0 +1,36 @@
1
+ import { OutlineSource } from './glyf-outline.js';
2
+ /**
3
+ * Prepare an embedded CFF program for outline reading.
4
+ *
5
+ * @param program The raw `/FontFile3` bytes (bare CFF, or the `CFF ` table of
6
+ * an OpenType wrapper — the caller unwraps that).
7
+ * @returns A reader keyed by GLYPH INDEX, or `undefined` where the program
8
+ * cannot be read.
9
+ */
10
+ export declare function cffOutlineSource(program: Uint8Array): OutlineSource | undefined;
11
+ /**
12
+ * TN 5176 §13 — the NAME a CFF gives each glyph, inverted.
13
+ *
14
+ * A simple font selects its glyphs by name, not by index: `/Differences` says
15
+ * code 2 is `g18`, and only the program's charset says which glyph `g18` is.
16
+ * TAMReview.pdf sets most of its body in a Cambria subset named that way.
17
+ *
18
+ * @param program The raw CFF bytes.
19
+ * @returns Glyph name → glyph index, or `undefined` for a CID-keyed program
20
+ * (which names nothing) or one that cannot be read.
21
+ */
22
+ export declare function cffNameToGid(program: Uint8Array): Map<string, number> | undefined;
23
+ /**
24
+ * TN 5176 §10 — the CID a CID-keyed CFF gives each glyph, inverted.
25
+ *
26
+ * A `CIDFontType0C` program is charset-ordered by CID, not by glyph index, so a
27
+ * composite font's code (its CID) is not the index into `CharStrings`. Where the
28
+ * program is not CID-keyed the two are the same and this gives nothing.
29
+ *
30
+ * @param program The raw CFF bytes.
31
+ * @returns CID → glyph index, or `undefined` for a program that is not
32
+ * CID-keyed or cannot be read.
33
+ */
34
+ export declare function cffCidToGid(program: Uint8Array): Map<number, number> | undefined;
35
+ /** The `CFF ` table of an OpenType wrapper, where the program is one. */
36
+ export declare function openTypeCff(program: Uint8Array): Uint8Array | undefined;