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
@@ -0,0 +1,576 @@
1
+ //#region src/pdf-reader/type1-outline.ts
2
+ /**
3
+ * Read an embedded Type 1 program.
4
+ *
5
+ * @param program The raw `/FontFile` bytes — the cleartext header, the
6
+ * `eexec`-encrypted body, and the trailing zeros.
7
+ * @returns A reader, or `undefined` where the program cannot be read.
8
+ */
9
+ function type1Font(program) {
10
+ let parsed;
11
+ try {
12
+ const read = parseType1(program);
13
+ if (!read) return void 0;
14
+ parsed = read;
15
+ } catch {
16
+ return;
17
+ }
18
+ const cache = /* @__PURE__ */ new Map();
19
+ return {
20
+ path: (name) => {
21
+ const had = cache.get(name);
22
+ if (had !== void 0 || cache.has(name)) return had;
23
+ let out;
24
+ try {
25
+ const charstring = parsed.charstrings.get(name);
26
+ out = charstring ? runGlyph(parsed, charstring, 0) : void 0;
27
+ } catch {
28
+ out = void 0;
29
+ }
30
+ cache.set(name, out);
31
+ return out;
32
+ },
33
+ has: (name) => parsed.charstrings.has(name),
34
+ ...parsed.encoding ? { encoding: parsed.encoding } : {}
35
+ };
36
+ }
37
+ function parseType1(program) {
38
+ const body = pfbSegments(program) ?? program;
39
+ const at = indexOf(body, "eexec");
40
+ if (at < 0) return void 0;
41
+ const clear = new TextDecoder("latin1").decode(body.subarray(0, at));
42
+ let from = at + 5;
43
+ while (from < body.length && isSpace(body[from])) from++;
44
+ const plain = eexec(looksHex(body, from) ? unhex(body, from) : body.subarray(from), EEXEC_R, 4);
45
+ const text = new TextDecoder("latin1").decode(plain);
46
+ const lenIV = readInt(text, "/lenIV") ?? 4;
47
+ const charstrings = readCharstrings(plain, text, lenIV);
48
+ if (charstrings.size === 0) return void 0;
49
+ const encoding = readEncoding(clear);
50
+ return {
51
+ charstrings,
52
+ subrs: readSubrs(plain, text, lenIV),
53
+ ...encoding ? { encoding } : {},
54
+ scale: readMatrixScale(clear) ?? .001
55
+ };
56
+ }
57
+ /** The `eexec` key (§7), and the one every charstring is encrypted with (§6.2). */
58
+ var EEXEC_R = 55665;
59
+ var CHARSTRING_R = 4330;
60
+ /** §7 — the decryption both layers use, less the leading random bytes. */
61
+ function eexec(data, key, skip) {
62
+ let r = key;
63
+ const out = new Uint8Array(Math.max(0, data.length - skip));
64
+ for (let i = 0; i < data.length; i++) {
65
+ const c = data[i];
66
+ const p = c ^ r >> 8;
67
+ r = (c + r) * 52845 + 22719 & 65535;
68
+ if (i >= skip) out[i - skip] = p & 255;
69
+ }
70
+ return out;
71
+ }
72
+ /**
73
+ * A PFB wrapper: 0x80 0x01/0x02 then a four-byte little-endian length. The
74
+ * segments are the file with its lengths interleaved, so they are joined back.
75
+ */
76
+ function pfbSegments(program) {
77
+ if (program[0] !== 128) return void 0;
78
+ const parts = [];
79
+ let at = 0;
80
+ while (at + 6 <= program.length && program[at] === 128 && program[at + 1] !== 3) {
81
+ const len = program[at + 2] | program[at + 3] << 8 | program[at + 4] << 16 | program[at + 5] << 24;
82
+ const from = at + 6;
83
+ if (len < 0 || from + len > program.length) break;
84
+ parts.push(program.subarray(from, from + len));
85
+ at = from + len;
86
+ }
87
+ if (parts.length === 0) return void 0;
88
+ const out = new Uint8Array(parts.reduce((n, p) => n + p.length, 0));
89
+ let off = 0;
90
+ for (const p of parts) {
91
+ out.set(p, off);
92
+ off += p.length;
93
+ }
94
+ return out;
95
+ }
96
+ /** §10 — `/CharStrings n dict dup begin /name len RD <bytes> ND` for each glyph. */
97
+ function readCharstrings(plain, text, lenIV) {
98
+ const out = /* @__PURE__ */ new Map();
99
+ const start = text.indexOf("/CharStrings");
100
+ if (start < 0) return out;
101
+ const entry = /\/([^\s/{}()[\]<>]+)\s+(\d+)\s+(-\||RD|ND)[ ]/gu;
102
+ entry.lastIndex = start;
103
+ for (let m = entry.exec(text); m; m = entry.exec(text)) {
104
+ const length = Number(m[2]);
105
+ const from = m.index + m[0].length;
106
+ if (!Number.isFinite(length) || length <= 0 || from + length > plain.length) continue;
107
+ if (m[3] === "ND") continue;
108
+ if (!out.has(m[1])) out.set(m[1], eexec(plain.subarray(from, from + length), CHARSTRING_R, lenIV));
109
+ entry.lastIndex = from + length;
110
+ if (out.size >= MAX_GLYPHS) break;
111
+ }
112
+ return out;
113
+ }
114
+ /** How many glyphs one program may hold — a guard, not a format limit. */
115
+ var MAX_GLYPHS = 5e3;
116
+ /** §8 — `/Subrs n array dup i len RD <bytes> NP`, called by index. */
117
+ function readSubrs(plain, text, lenIV) {
118
+ const out = [];
119
+ const start = text.indexOf("/Subrs");
120
+ if (start < 0) return out;
121
+ const entry = /dup\s+(\d+)\s+(\d+)\s+(-\||RD)[ ]/gu;
122
+ entry.lastIndex = start;
123
+ for (let m = entry.exec(text); m; m = entry.exec(text)) {
124
+ const index = Number(m[1]);
125
+ const length = Number(m[2]);
126
+ const from = m.index + m[0].length;
127
+ if (!Number.isFinite(length) || from + length > plain.length) break;
128
+ if (index >= 0 && index < MAX_GLYPHS) out[index] = eexec(plain.subarray(from, from + length), CHARSTRING_R, lenIV);
129
+ entry.lastIndex = from + length;
130
+ if (text.startsWith("/CharStrings", entry.lastIndex)) break;
131
+ }
132
+ return out;
133
+ }
134
+ /**
135
+ * §5 — the program's own `/Encoding`: either `StandardEncoding` by name, or an
136
+ * array built up with `dup <code> /<name> put`.
137
+ */
138
+ function readEncoding(clear) {
139
+ const at = clear.indexOf("/Encoding");
140
+ if (at < 0) return void 0;
141
+ const out = /* @__PURE__ */ new Map();
142
+ const put = /dup\s+(\d+)\s*\/([^\s/{}()[\]<>]+)\s+put/gu;
143
+ put.lastIndex = at;
144
+ const end = clear.indexOf("readonly def", at);
145
+ for (let m = put.exec(clear); m; m = put.exec(clear)) {
146
+ if (end >= 0 && m.index > end) break;
147
+ const code = Number(m[1]);
148
+ if (Number.isFinite(code) && code >= 0 && code < 256) out.set(code, m[2]);
149
+ }
150
+ return out.size > 0 ? out : void 0;
151
+ }
152
+ /** §5 — `/FontMatrix [a b c d e f]`, whose `a` is the em this program states. */
153
+ function readMatrixScale(clear) {
154
+ const m = /\/FontMatrix\s*\[\s*([-\d.eE]+)/u.exec(clear);
155
+ const a = m ? Number(m[1]) : NaN;
156
+ return Number.isFinite(a) && a !== 0 ? a : void 0;
157
+ }
158
+ function readInt(text, key) {
159
+ const m = new RegExp(`${key}\\s+(-?\\d+)`, "u").exec(text);
160
+ const v = m ? Number(m[1]) : NaN;
161
+ return Number.isFinite(v) ? v : void 0;
162
+ }
163
+ function indexOf(data, needle) {
164
+ const bytes = [...needle].map((c) => c.charCodeAt(0));
165
+ outer: for (let i = 0; i + bytes.length <= data.length; i++) {
166
+ for (let k = 0; k < bytes.length; k++) if (data[i + k] !== bytes[k]) continue outer;
167
+ return i;
168
+ }
169
+ return -1;
170
+ }
171
+ function isSpace(b) {
172
+ return b === 32 || b === 10 || b === 13 || b === 9;
173
+ }
174
+ /** The ciphertext may be hexadecimal — four hex digits at the head give it away. */
175
+ function looksHex(data, from) {
176
+ const hex = (b) => b >= 48 && b <= 57 || b >= 65 && b <= 70 || b >= 97 && b <= 102;
177
+ return [
178
+ 0,
179
+ 1,
180
+ 2,
181
+ 3
182
+ ].every((k) => hex(data[from + k] ?? 0));
183
+ }
184
+ function unhex(data, from) {
185
+ const out = [];
186
+ let half = -1;
187
+ for (let i = from; i < data.length; i++) {
188
+ const b = data[i];
189
+ let v = -1;
190
+ if (b >= 48 && b <= 57) v = b - 48;
191
+ else if (b >= 65 && b <= 70) v = b - 55;
192
+ else if (b >= 97 && b <= 102) v = b - 87;
193
+ else if (isSpace(b)) continue;
194
+ else break;
195
+ if (half < 0) half = v;
196
+ else {
197
+ out.push(half << 4 | v);
198
+ half = -1;
199
+ }
200
+ }
201
+ return Uint8Array.from(out);
202
+ }
203
+ /** How deep a charstring may call, and how many operators it may run. */
204
+ var MAX_CALL_DEPTH = 10;
205
+ var MAX_STEPS = 65536;
206
+ function runGlyph(font, program, depth) {
207
+ const out = [];
208
+ const stack = [];
209
+ const ps = [];
210
+ const flex = [];
211
+ let inFlex = false;
212
+ let x = 0;
213
+ let y = 0;
214
+ let open = false;
215
+ let steps = 0;
216
+ const moveTo = () => {
217
+ if (inFlex) {
218
+ flex.push(x, y);
219
+ return;
220
+ }
221
+ if (open) out.push({ op: "close" });
222
+ out.push({
223
+ op: "move",
224
+ x,
225
+ y
226
+ });
227
+ open = true;
228
+ };
229
+ const curveTo = (x1, y1, x2, y2) => {
230
+ out.push({
231
+ op: "cubic",
232
+ x1,
233
+ y1,
234
+ x2,
235
+ y2,
236
+ x,
237
+ y
238
+ });
239
+ };
240
+ const run = (code, level) => {
241
+ for (let i = 0; i < code.length;) {
242
+ if (++steps > MAX_STEPS) return false;
243
+ const b = code[i++];
244
+ if (b >= 32) {
245
+ if (b <= 246) stack.push(b - 139);
246
+ else if (b <= 250) stack.push((b - 247) * 256 + (code[i++] ?? 0) + 108);
247
+ else if (b <= 254) stack.push(-(b - 251) * 256 - (code[i++] ?? 0) - 108);
248
+ else {
249
+ stack.push(code[i] << 24 | code[i + 1] << 16 | code[i + 2] << 8 | code[i + 3] | 0);
250
+ i += 4;
251
+ }
252
+ continue;
253
+ }
254
+ switch (b) {
255
+ case 13:
256
+ x = stack[0] ?? 0;
257
+ y = 0;
258
+ stack.length = 0;
259
+ break;
260
+ case 9:
261
+ if (open) out.push({ op: "close" });
262
+ open = false;
263
+ stack.length = 0;
264
+ break;
265
+ case 1:
266
+ case 3:
267
+ stack.length = 0;
268
+ break;
269
+ case 21:
270
+ x += stack[stack.length - 2] ?? 0;
271
+ y += stack[stack.length - 1] ?? 0;
272
+ moveTo();
273
+ stack.length = 0;
274
+ break;
275
+ case 22:
276
+ x += stack[stack.length - 1] ?? 0;
277
+ moveTo();
278
+ stack.length = 0;
279
+ break;
280
+ case 4:
281
+ y += stack[stack.length - 1] ?? 0;
282
+ moveTo();
283
+ stack.length = 0;
284
+ break;
285
+ case 5:
286
+ x += stack[0] ?? 0;
287
+ y += stack[1] ?? 0;
288
+ out.push({
289
+ op: "line",
290
+ x,
291
+ y
292
+ });
293
+ stack.length = 0;
294
+ break;
295
+ case 6:
296
+ x += stack[0] ?? 0;
297
+ out.push({
298
+ op: "line",
299
+ x,
300
+ y
301
+ });
302
+ stack.length = 0;
303
+ break;
304
+ case 7:
305
+ y += stack[0] ?? 0;
306
+ out.push({
307
+ op: "line",
308
+ x,
309
+ y
310
+ });
311
+ stack.length = 0;
312
+ break;
313
+ case 8: {
314
+ const x1 = x + (stack[0] ?? 0);
315
+ const y1 = y + (stack[1] ?? 0);
316
+ const x2 = x1 + (stack[2] ?? 0);
317
+ const y2 = y1 + (stack[3] ?? 0);
318
+ x = x2 + (stack[4] ?? 0);
319
+ y = y2 + (stack[5] ?? 0);
320
+ curveTo(x1, y1, x2, y2);
321
+ stack.length = 0;
322
+ break;
323
+ }
324
+ case 30: {
325
+ const x1 = x;
326
+ const y1 = y + (stack[0] ?? 0);
327
+ const x2 = x1 + (stack[1] ?? 0);
328
+ const y2 = y1 + (stack[2] ?? 0);
329
+ x = x2 + (stack[3] ?? 0);
330
+ y = y2;
331
+ curveTo(x1, y1, x2, y2);
332
+ stack.length = 0;
333
+ break;
334
+ }
335
+ case 31: {
336
+ const x1 = x + (stack[0] ?? 0);
337
+ const y1 = y;
338
+ const x2 = x1 + (stack[1] ?? 0);
339
+ const y2 = y1 + (stack[2] ?? 0);
340
+ x = x2;
341
+ y = y2 + (stack[3] ?? 0);
342
+ curveTo(x1, y1, x2, y2);
343
+ stack.length = 0;
344
+ break;
345
+ }
346
+ case 10: {
347
+ const index = stack.pop() ?? 0;
348
+ const sub = font.subrs[index];
349
+ if (sub && level < MAX_CALL_DEPTH && !run(sub, level + 1)) return false;
350
+ break;
351
+ }
352
+ case 11: return true;
353
+ case 14:
354
+ if (open) out.push({ op: "close" });
355
+ open = false;
356
+ return false;
357
+ case 12: {
358
+ const op2 = code[i++];
359
+ if (op2 === 12) {
360
+ const den = stack.pop() ?? 1;
361
+ const num = stack.pop() ?? 0;
362
+ stack.push(den === 0 ? 0 : num / den);
363
+ break;
364
+ }
365
+ if (op2 === 16) {
366
+ const which = stack.pop() ?? 0;
367
+ const count = stack.pop() ?? 0;
368
+ const args = stack.splice(Math.max(0, stack.length - count), count);
369
+ if (which === 1) {
370
+ inFlex = true;
371
+ flex.length = 0;
372
+ } else if (which === 0) {
373
+ inFlex = false;
374
+ if (flex.length >= 14) {
375
+ const p = flex.slice(2);
376
+ out.push({
377
+ op: "cubic",
378
+ x1: p[0],
379
+ y1: p[1],
380
+ x2: p[2],
381
+ y2: p[3],
382
+ x: p[4],
383
+ y: p[5]
384
+ });
385
+ out.push({
386
+ op: "cubic",
387
+ x1: p[6],
388
+ y1: p[7],
389
+ x2: p[8],
390
+ y2: p[9],
391
+ x: p[10],
392
+ y: p[11]
393
+ });
394
+ x = p[10];
395
+ y = p[11];
396
+ }
397
+ ps.push(y, x);
398
+ } else if (which === 3) ps.push(3);
399
+ else for (const a of args.reverse()) ps.push(a);
400
+ break;
401
+ }
402
+ if (op2 === 17) {
403
+ stack.push(ps.pop() ?? 0);
404
+ break;
405
+ }
406
+ if (op2 === 6) {
407
+ const base = STANDARD_ENCODING[stack[3] ?? 0];
408
+ const charstring = base !== void 0 ? font.charstrings.get(base) : void 0;
409
+ if (charstring && depth < 2) {
410
+ const drawn = runGlyph(font, charstring, depth + 1);
411
+ if (drawn) out.push(...drawn.map((seg) => unscale(seg, font.scale)));
412
+ }
413
+ stack.length = 0;
414
+ return false;
415
+ }
416
+ if (op2 === 7) {
417
+ x = stack[0] ?? 0;
418
+ y = stack[1] ?? 0;
419
+ stack.length = 0;
420
+ break;
421
+ }
422
+ if (op2 === 33) {
423
+ x = stack[0] ?? x;
424
+ y = stack[1] ?? y;
425
+ stack.length = 0;
426
+ break;
427
+ }
428
+ stack.length = 0;
429
+ break;
430
+ }
431
+ default:
432
+ stack.length = 0;
433
+ break;
434
+ }
435
+ }
436
+ return true;
437
+ };
438
+ run(program, 0);
439
+ if (out.length > 0 && out[out.length - 1]?.op !== "close") out.push({ op: "close" });
440
+ if (out.length === 0) return void 0;
441
+ return out.map((seg) => scaleSeg(seg, font.scale));
442
+ }
443
+ function scaleSeg(seg, k) {
444
+ if (seg.op === "close") return seg;
445
+ if (seg.op === "cubic") return {
446
+ op: "cubic",
447
+ x1: seg.x1 * k,
448
+ y1: seg.y1 * k,
449
+ x2: seg.x2 * k,
450
+ y2: seg.y2 * k,
451
+ x: seg.x * k,
452
+ y: seg.y * k
453
+ };
454
+ return {
455
+ op: seg.op,
456
+ x: seg.x * k,
457
+ y: seg.y * k
458
+ };
459
+ }
460
+ /** The base of a `seac` comes back already scaled; this puts it back in glyph space. */
461
+ function unscale(seg, k) {
462
+ return scaleSeg(seg, k === 0 ? 1 : 1 / k);
463
+ }
464
+ /** §C.1 — the names `seac` selects its two parts by, at the codes it states. */
465
+ var STANDARD_ENCODING = {
466
+ 32: "space",
467
+ 33: "exclam",
468
+ 34: "quotedbl",
469
+ 35: "numbersign",
470
+ 36: "dollar",
471
+ 37: "percent",
472
+ 38: "ampersand",
473
+ 39: "quoteright",
474
+ 40: "parenleft",
475
+ 41: "parenright",
476
+ 42: "asterisk",
477
+ 43: "plus",
478
+ 44: "comma",
479
+ 45: "hyphen",
480
+ 46: "period",
481
+ 47: "slash",
482
+ 48: "zero",
483
+ 49: "one",
484
+ 50: "two",
485
+ 51: "three",
486
+ 52: "four",
487
+ 53: "five",
488
+ 54: "six",
489
+ 55: "seven",
490
+ 56: "eight",
491
+ 57: "nine",
492
+ 58: "colon",
493
+ 59: "semicolon",
494
+ 60: "less",
495
+ 61: "equal",
496
+ 62: "greater",
497
+ 63: "question",
498
+ 64: "at",
499
+ 65: "A",
500
+ 66: "B",
501
+ 67: "C",
502
+ 68: "D",
503
+ 69: "E",
504
+ 70: "F",
505
+ 71: "G",
506
+ 72: "H",
507
+ 73: "I",
508
+ 74: "J",
509
+ 75: "K",
510
+ 76: "L",
511
+ 77: "M",
512
+ 78: "N",
513
+ 79: "O",
514
+ 80: "P",
515
+ 81: "Q",
516
+ 82: "R",
517
+ 83: "S",
518
+ 84: "T",
519
+ 85: "U",
520
+ 86: "V",
521
+ 87: "W",
522
+ 88: "X",
523
+ 89: "Y",
524
+ 90: "Z",
525
+ 91: "bracketleft",
526
+ 92: "backslash",
527
+ 93: "bracketright",
528
+ 94: "asciicircum",
529
+ 95: "underscore",
530
+ 96: "quoteleft",
531
+ 97: "a",
532
+ 98: "b",
533
+ 99: "c",
534
+ 100: "d",
535
+ 101: "e",
536
+ 102: "f",
537
+ 103: "g",
538
+ 104: "h",
539
+ 105: "i",
540
+ 106: "j",
541
+ 107: "k",
542
+ 108: "l",
543
+ 109: "m",
544
+ 110: "n",
545
+ 111: "o",
546
+ 112: "p",
547
+ 113: "q",
548
+ 114: "r",
549
+ 115: "s",
550
+ 116: "t",
551
+ 117: "u",
552
+ 118: "v",
553
+ 119: "w",
554
+ 120: "x",
555
+ 121: "y",
556
+ 122: "z",
557
+ 123: "braceleft",
558
+ 124: "bar",
559
+ 125: "braceright",
560
+ 126: "asciitilde",
561
+ 193: "grave",
562
+ 194: "acute",
563
+ 195: "circumflex",
564
+ 196: "tilde",
565
+ 197: "macron",
566
+ 198: "breve",
567
+ 199: "dotaccent",
568
+ 200: "dieresis",
569
+ 202: "ring",
570
+ 203: "cedilla",
571
+ 205: "hungarumlaut",
572
+ 206: "ogonek",
573
+ 207: "caron"
574
+ };
575
+ //#endregion
576
+ export { type1Font };
@@ -1,13 +1,14 @@
1
1
  import { PDF_NULL, PdfName, PdfStream } from "../pdf/objects.js";
2
2
  import { FEATURES } from "../core/ir/features.js";
3
+ import { buildAlphaMap, buildColorSpaceMap, buildShadingMap, gradientShading, shadingTypeOf } from "./shading.js";
3
4
  import { IDENTITY, interpretContent, multiply } from "./content.js";
4
- import { buildAlphaMap, buildColorSpaceMap, buildShadingMap } from "./shading.js";
5
5
  import { collectPageAppearances } from "./annots.js";
6
6
  import { hiddenProperties, hiddenXObject } from "./optional-content.js";
7
7
  import { buildFonts } from "./text.js";
8
8
  //#region src/pdf-reader/vector.ts
9
9
  function paintedVectors(file, page) {
10
10
  const out = [];
11
+ let bareShadings = 0;
11
12
  const visiting = /* @__PURE__ */ new Set();
12
13
  const stateCache = /* @__PURE__ */ new Map();
13
14
  const mapsOf = (resources) => {
@@ -27,11 +28,39 @@ function paintedVectors(file, page) {
27
28
  const xobjDict = xobjects instanceof Map ? xobjects : void 0;
28
29
  const maps = mapsOf(resources);
29
30
  const result = interpretContent(content, buildFonts(file, resources), baseCtm, maps.shadings, maps.alphas, maps.spaces, hiddenProperties(file, resources));
31
+ for (const paint of result.shadings) {
32
+ if (out.length >= MAX_VECTORS) break;
33
+ const dict = resources ? file.get(resources, "Shading") : PDF_NULL;
34
+ const found = dict instanceof Map ? file.resolve(dict.get(paint.name) ?? PDF_NULL) : PDF_NULL;
35
+ const sh = found instanceof PdfStream ? found.dict : found instanceof Map ? found : void 0;
36
+ if (sh && shadingTypeOf(file, sh) === 1) continue;
37
+ const gradient = sh ? gradientShading(file, sh) : void 0;
38
+ if (paint.masked) {
39
+ bareShadings++;
40
+ continue;
41
+ }
42
+ if (!sh || !gradient || !paint.clip) {
43
+ bareShadings++;
44
+ continue;
45
+ }
46
+ out.push({
47
+ order: paint.order,
48
+ segs: paint.clip.segs,
49
+ gradient,
50
+ ...paint.alpha !== void 0 ? { alpha: paint.alpha } : {},
51
+ ...paint.darkens ? { darkens: true } : {},
52
+ orderKey: [...prefix, paint.order]
53
+ });
54
+ }
30
55
  const events = [
31
56
  ...result.vectors.map((vector) => ({
32
57
  order: vector.order,
33
58
  vector
34
59
  })),
60
+ ...result.outlines.map((vector) => ({
61
+ order: vector.order,
62
+ vector
63
+ })),
35
64
  ...result.images.map((xobject) => ({
36
65
  order: xobject.order,
37
66
  xobject
@@ -75,7 +104,10 @@ function paintedVectors(file, page) {
75
104
  collectPageAppearances(file, page).forEach((appearance, index) => {
76
105
  walk(appearance.resources ?? page.resources, file.streamData(appearance.stream), appearance.ctm, 1, [Number.MAX_SAFE_INTEGER, index]);
77
106
  });
78
- return out;
107
+ return {
108
+ placements: out,
109
+ bareShadings
110
+ };
79
111
  }
80
112
  /** §8.10.2 `/Matrix` — the form's own space, composed onto the placement CTM. */
81
113
  function formMatrix(file, dict) {
@@ -123,8 +155,10 @@ function collectPageVectors(file, page, occupied = []) {
123
155
  const pageArea = Math.max(1, Math.abs((px1 - px0) * (py1 - py0)));
124
156
  const out = [];
125
157
  const painted = [...occupied];
126
- const raws = paintedVectors(file, page);
158
+ const lifted = paintedVectors(file, page);
159
+ const raws = lifted.placements;
127
160
  const losses = [];
161
+ const bareShadings = lifted.bareShadings;
128
162
  const asked = /* @__PURE__ */ new Set();
129
163
  for (const raw of raws) {
130
164
  if (raw.masked === true) asked.add("PDF soft mask (/SMask in the graphics state) is not applied; the shape is drawn at full opacity throughout");
@@ -150,7 +184,7 @@ function collectPageVectors(file, page, occupied = []) {
150
184
  const short = Math.min(w, h);
151
185
  const isBox = short >= MIN_SIDE && area >= MIN_AREA;
152
186
  const isRule = long >= MIN_RULE_LEN && short > 0;
153
- const filled = (v.gradient !== void 0 || solidFill) && (isBox || isRule);
187
+ const filled = (v.gradient !== void 0 || solidFill) && (isBox || isRule || v.glyph === true);
154
188
  const stroked = v.strokeHex !== void 0 && (v.strokeHex !== "FFFFFF" || painted.some((box) => overlaps(box, b))) && Math.max(w, h) >= MIN_STROKE_LEN && area <= .85 * pageArea;
155
189
  if (!filled && !stroked) continue;
156
190
  painted.push(b);
@@ -173,6 +207,11 @@ function collectPageVectors(file, page, occupied = []) {
173
207
  feature: FEATURES.shapes,
174
208
  detail: `page carries more than ${String(MAX_VECTORS)} painted paths; the rest were not read`
175
209
  });
210
+ if (bareShadings > 0) losses.push({
211
+ severity: "dropped",
212
+ feature: FEATURES.images,
213
+ detail: `${String(bareShadings)} bare-shading (sh) region${bareShadings === 1 ? "" : "s"} painted the clip rather than a path, and ${bareShadings === 1 ? "was" : "were"} not reconstructed`
214
+ });
176
215
  return {
177
216
  vectors: out,
178
217
  losses
@@ -262,7 +262,10 @@ function parseSectPrNode(sectPr) {
262
262
  const type = poAttr(child, "type") ?? "default";
263
263
  const pitch = poIntAttr(child, "linePitch");
264
264
  if ((type === "lines" || type === "linesAndChars") && pitch !== void 0 && pitch > 0) gridLinePitchPt = twipsToPt(pitch);
265
- } else if (poIs(child, "w:type")) sectionStart = poAttr(child, "val") === "continuous" ? "continuous" : "nextPage";
265
+ } else if (poIs(child, "w:type")) {
266
+ const val = poAttr(child, "val");
267
+ sectionStart = val === "continuous" || val === "oddPage" || val === "evenPage" ? val : "nextPage";
268
+ }
266
269
  return {
267
270
  pageSize,
268
271
  ...margins ? { margins } : {},
@@ -976,6 +976,7 @@ function sectPrXml(s, hf) {
976
976
  const parts = [];
977
977
  for (const h of hf.headers) parts.push(`<w:headerReference w:type="${h.type}" r:id="${h.relId}"/>`);
978
978
  for (const f of hf.footers) parts.push(`<w:footerReference w:type="${f.type}" r:id="${f.relId}"/>`);
979
+ if (s.sectionStart !== void 0 && s.sectionStart !== "nextPage") parts.push(`<w:type w:val="${s.sectionStart}"/>`);
979
980
  if (s.pageSize) {
980
981
  const orient = s.pageSize.orientation === "landscape" ? " w:orient=\"landscape\"" : "";
981
982
  parts.push(`<w:pgSz w:w="${twips(s.pageSize.width)}" w:h="${twips(s.pageSize.height)}"${orient}/>`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reamkit",
3
- "version": "1.27.0",
3
+ "version": "1.28.0",
4
4
  "description": "Ream — convert DOCX, XLSX, PPTX and PDF to PDF, SVG, HTML, DOCX and XLSX, built from scratch on the ECMA-376 and ISO 32000 specifications. Parse once, convert anywhere.",
5
5
  "license": "MIT",
6
6
  "author": "Alex Krassavin <info@reamkit.dev>",