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
@@ -74,8 +74,11 @@ function utf16be(bytes) {
74
74
  }
75
75
  function incString(base, i) {
76
76
  if (i === 0) return base;
77
- if (base.length === 1) return String.fromCharCode(base.charCodeAt(0) + i);
78
- return base;
77
+ const chars = [...base];
78
+ if (chars.length === 0) return base;
79
+ const last = chars[chars.length - 1].codePointAt(0) + i;
80
+ if (last > 1114111 || last >= 55296 && last <= 57343) return base;
81
+ return chars.slice(0, -1).join("") + String.fromCodePoint(last);
79
82
  }
80
83
  //#endregion
81
84
  export { parseToUnicodeCMap };
@@ -11,10 +11,25 @@ import { PdfDict, PdfStream } from '../pdf/objects.js';
11
11
  export interface ContentFont {
12
12
  /** Bytes per character code: simple fonts read 1 byte/code, Type0 reads 2. */
13
13
  readonly bytesPerCode: 1 | 2;
14
+ /**
15
+ * §9.7.6.2 — how a shown string breaks into codes, where the CMap is not
16
+ * fixed-width. A named CMap like `90ms-RKSJ-H` mixes one-byte and two-byte
17
+ * codes, and split down the middle a Japanese line came apart into nonsense.
18
+ * Absent means the fixed width above.
19
+ */
20
+ readonly splitCodes?: (bytes: Uint8Array) => Array<number>;
14
21
  /** Decode a sequence of character codes to a Unicode string. */
15
22
  decode: (codes: ReadonlyArray<number>) => string;
16
23
  /** Glyph advance for one code, in 1000-unit text space. */
17
24
  width: (code: number) => number;
25
+ /**
26
+ * §9.4.4 / §9.7.4.3 — the face sets its text DOWN the page, not across, and
27
+ * the pen advances by the vertical displacement `w1` rather than by `w0`.
28
+ * A `…-V` CMap asks for this; `/DW2`'s default `[880 -1000]` is one em down.
29
+ * The number here is that displacement in 1000-unit text space, and it is
30
+ * negative because the page's y runs up.
31
+ */
32
+ readonly verticalAdvance?: (code: number) => number;
18
33
  /** §9.6.2 — the face's own `/BaseFont` name, for a document that embeds it. */
19
34
  readonly name?: string;
20
35
  /** §9.8.1 — the face is a bold one (weight, the ForceBold flag, or its name). */
@@ -27,6 +42,19 @@ export interface ContentFont {
27
42
  * procedure paints, in the resources the font states.
28
43
  */
29
44
  readonly type3?: Type3Face;
45
+ /**
46
+ * §9.6.6 — the OUTLINE a code draws, for a code that stands for no
47
+ * character. A face that can say what its characters are never has one:
48
+ * this is the last resort before a blank page.
49
+ */
50
+ readonly outline?: GlyphOutline;
51
+ }
52
+ /** §9.6.6 — the outlines of a face read by glyph index, and their glyph space. */
53
+ export interface GlyphOutline {
54
+ /** Glyph space to text space, as a Type 3 font's `/FontMatrix` is. */
55
+ readonly matrix: Matrix;
56
+ /** The contours one code draws, or `undefined` where it draws none. */
57
+ readonly path: (code: number) => Array<PathSeg> | undefined;
30
58
  }
31
59
  /** §9.6.5 — the parts of a Type 3 font a caller needs to run its glyphs. */
32
60
  export interface Type3Face {
@@ -94,6 +122,12 @@ export interface TextRun {
94
122
  * fill colour still standing from before is not what the page shows.
95
123
  */
96
124
  readonly fillPatternName?: string;
125
+ /**
126
+ * §8.7.4.5 — the glyphs are filled with a SHADING pattern: a sweep from one
127
+ * colour to another, of which the run carries the middle. The colour is not
128
+ * lost, the shape of it is.
129
+ */
130
+ readonly gradientFill?: boolean;
97
131
  /**
98
132
  * §9.3.6 — the page painted these glyphs NOWHERE: mode 3 shows nothing and
99
133
  * mode 7 only adds to the clip. A scanned page carries its recognised words
@@ -157,6 +191,8 @@ export interface ImagePlacement {
157
191
  */
158
192
  readonly fillHex: string;
159
193
  readonly mcid?: number;
194
+ /** §11.6.4.4 `/ca` — how opaque the picture is drawn, when the page asked for less. */
195
+ readonly alpha?: number;
160
196
  /** §11.3.5 `/BM` — a blend the page asked for that nothing here performs. */
161
197
  readonly blend?: string;
162
198
  /** §11.6.5 `/SMask` — the paint faded from place to place; nothing here does. */
@@ -222,6 +258,13 @@ export interface VectorPlacement {
222
258
  readonly blend?: string;
223
259
  /** §11.6.5 `/SMask` — the paint faded from place to place; nothing here does. */
224
260
  readonly masked?: boolean;
261
+ /**
262
+ * §9.6.6 — this path is a GLYPH, traced from the face because its code stands
263
+ * for no character. It is type, not artwork, so the de-cluttering a page's
264
+ * paths go through does not apply: a full stop is a mark one point across and
265
+ * every filter there would throw it out.
266
+ */
267
+ readonly glyph?: boolean;
225
268
  /**
226
269
  * §8.7.3 — the TILING pattern resource name the path is filled with. Its
227
270
  * content is a stream of its own, so what the fill actually shows is only
@@ -241,11 +284,44 @@ export interface InterpretResult {
241
284
  readonly vectors: Array<VectorPlacement>;
242
285
  /** §9.6.5 — every Type 3 glyph the stream showed, with where to run it. */
243
286
  readonly glyphs: Array<Type3Call>;
287
+ /**
288
+ * §8.7.4.3 — every region the stream painted with a bare `sh`, which fills
289
+ * the CLIP rather than a path. What a caller can do with one depends on the
290
+ * shading's own type, so the placement is carried rather than counted.
291
+ */
292
+ readonly shadings: Array<ShadingPaint>;
293
+ /**
294
+ * §9.6.6 — every glyph the stream showed that stands for NO character, as
295
+ * the path it draws in page space. There is nothing to write for one, and
296
+ * there is something to draw.
297
+ */
298
+ readonly outlines: Array<VectorPlacement>;
244
299
  }
245
300
  /**
246
301
  * §9.6.5 — one showing of a Type 3 glyph: which procedure, and the matrix that
247
302
  * puts glyph space on the page.
248
303
  */
304
+ /** §8.7.4.3 — one `sh`: which shading, where the CTM put it, what bounded it. */
305
+ export interface ShadingPaint {
306
+ /** The `/Shading` resource name (no leading slash). */
307
+ readonly name: string;
308
+ /** The CTM in force, which maps the shading's own space onto the page. */
309
+ readonly ctm: Matrix;
310
+ /** §8.5.4 — the clip the paint was bounded by, which is its whole extent. */
311
+ readonly clip?: ClipRegion;
312
+ /**
313
+ * §11.6.5 `/SMask` — the paint was faded from place to place. For a `sh` that
314
+ * is not a detail: the mask is the SHAPE, and the clip is only its outer
315
+ * bound.
316
+ */
317
+ readonly masked?: boolean;
318
+ /** §11.6.4.4 `/ca` — how opaque the paint is, when the page asked for less. */
319
+ readonly alpha?: number;
320
+ /** §11.3.5 `/BM` — the paint only DARKENS what it covers. */
321
+ readonly darkens?: boolean;
322
+ /** Where it fell in the painting order (§8.5.3). */
323
+ readonly order: number;
324
+ }
249
325
  export interface Type3Call {
250
326
  readonly stream: PdfStream;
251
327
  readonly resources: PdfDict | undefined;
@@ -1,6 +1,6 @@
1
1
  import { PDF_NULL, PdfHexString, PdfName } from "../pdf/objects.js";
2
2
  import { Lexer } from "./lexer.js";
3
- import { cieToSrgb } from "./cie-color.js";
3
+ import { cmykHex, grayHex, rgbHex, spaceColor } from "./shading.js";
4
4
  //#region src/pdf-reader/content.ts
5
5
  /**
6
6
  * A painted path emitted by the path-painting operators (§8.5.3), captured in
@@ -136,39 +136,42 @@ function spaceOf(operands, spaces) {
136
136
  }
137
137
  }
138
138
  /**
139
- * §8.6.8 — the colour a run of `sc` / `scn` components comes to.
140
- *
141
- * The space in force decides, and where it was not read the COUNT is the next
142
- * best witness: three numbers are RGB and four are CMYK on every device space
143
- * there is. One number is the ambiguous case — grey in a device space, but the
144
- * strength of a colorant in a Separation, where 1 is the ink at full and reads
145
- * dark — so a lone component is only taken where the space said what it means.
139
+ * §8.7.4.5 — one colour for a whole sweep: the stop at its middle, or the mean
140
+ * of the two it falls between. A gradient is a shape a run cannot carry, and
141
+ * the end it starts at is no more the colour of the words than the end it
142
+ * finishes at.
146
143
  */
147
- function componentColor(operands, space) {
148
- const nums = operands.filter((o) => typeof o === "number");
149
- if (nums.length === 0) return void 0;
150
- if (space?.cie) {
151
- const [r, g, b] = cieToSrgb(space.cie, nums);
152
- return rgbHex(r, g, b);
153
- }
154
- switch (space?.kind ?? (nums.length === 3 ? "rgb" : nums.length === 4 ? "cmyk" : void 0)) {
155
- case "rgb": return nums.length >= 3 ? rgbHex(nums[0], nums[1], nums[2]) : void 0;
156
- case "cmyk": return nums.length >= 4 ? cmykHex(nums[0], nums[1], nums[2], nums[3]) : void 0;
157
- case "gray": return grayHex(nums[0]);
158
- case "tint":
159
- if (space?.tint) {
160
- const hex = componentColor(space.tint.transform(nums), space.tint.alternate);
161
- if (hex !== void 0) return hex;
162
- }
163
- return grayHex(1 - Math.max(...nums));
164
- default: return;
165
- }
144
+ function midGradient(gradient) {
145
+ const stops = [...gradient.stops].sort((a, b) => a.offset - b.offset);
146
+ if (stops.length === 0) return "000000";
147
+ const exact = stops.find((s) => Math.abs(s.offset - .5) < 1e-6);
148
+ if (exact) return exact.colorHex;
149
+ const before = [...stops].reverse().find((s) => s.offset <= .5) ?? stops[0];
150
+ const after = stops.find((s) => s.offset >= .5) ?? stops[stops.length - 1];
151
+ const span = after.offset - before.offset;
152
+ const t = span > 0 ? (.5 - before.offset) / span : 0;
153
+ const mix = (at) => {
154
+ const a = parseInt(before.colorHex.slice(at, at + 2), 16);
155
+ const b = parseInt(after.colorHex.slice(at, at + 2), 16);
156
+ return Number.isFinite(a) && Number.isFinite(b) ? Math.round(a + (b - a) * t) : 0;
157
+ };
158
+ return [
159
+ mix(0),
160
+ mix(2),
161
+ mix(4)
162
+ ].map((c) => Math.max(0, Math.min(255, c)).toString(16).padStart(2, "0")).join("").toUpperCase();
163
+ }
164
+ /** §8.6.8 — the colour a run of `sc` / `scn` operands comes to (see `spaceColor`). */
165
+ function colorOfOperands(operands, space) {
166
+ return spaceColor(operands.filter((o) => typeof o === "number"), space);
166
167
  }
167
168
  function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__PURE__ */ new Map(), alphas = /* @__PURE__ */ new Map(), spaces = /* @__PURE__ */ new Map(), hiddenOc = /* @__PURE__ */ new Set()) {
168
169
  const runs = [];
169
170
  const images = [];
170
171
  const vectors = [];
171
172
  const glyphs = [];
173
+ const painted = [];
174
+ const outlines = [];
172
175
  const lexer = new Lexer(bytes);
173
176
  const stack = [];
174
177
  let state = initialState();
@@ -285,12 +288,41 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
285
288
  });
286
289
  }
287
290
  }
288
- const w0 = state.font.width(code) / 1e3;
291
+ const outline = state.font.outline;
292
+ if (outline && visible() && state.renderMode !== 3 && state.renderMode !== 7) {
293
+ const segs = outline.path(code);
294
+ if (segs) {
295
+ const scale = [
296
+ state.fontSize * state.hScale,
297
+ 0,
298
+ 0,
299
+ state.fontSize,
300
+ 0,
301
+ state.rise
302
+ ];
303
+ const place = multiply(outline.matrix, multiply(scale, multiply(tm, state.ctm)));
304
+ outlines.push({
305
+ order: paintOrder++,
306
+ segs: segs.map((seg) => mapSeg(seg, place)),
307
+ ...state.clip ? { clip: state.clip } : {},
308
+ fillHex: state.fillColor,
309
+ ...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
310
+ glyph: true
311
+ });
312
+ }
313
+ }
289
314
  const isSpace = state.font.bytesPerCode === 1 && code === 32;
290
- tm = multiply(translation((w0 * state.fontSize + state.charSpacing + (isSpace ? state.wordSpacing : 0)) * state.hScale, 0), tm);
315
+ const spacing = state.charSpacing + (isSpace ? state.wordSpacing : 0);
316
+ const down = state.font.verticalAdvance;
317
+ if (down) {
318
+ tm = multiply(translation(0, down(code) / 1e3 * state.fontSize - spacing), tm);
319
+ return;
320
+ }
321
+ tm = multiply(translation((state.font.width(code) / 1e3 * state.fontSize + spacing) * state.hScale, 0), tm);
291
322
  };
292
323
  const consume = (operand) => {
293
- const codes = splitCodes(toBytes(operand), state.font.bytesPerCode);
324
+ const bytes = toBytes(operand);
325
+ const codes = state.font.splitCodes ? state.font.splitCodes(bytes) : splitCodes(bytes, state.font.bytesPerCode);
294
326
  for (const code of codes) advanceGlyph(code);
295
327
  return state.font.decode(codes);
296
328
  };
@@ -316,13 +348,14 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
316
348
  ...state.font.type3 ? { type3: true } : {},
317
349
  ...state.renderMode === 3 || state.renderMode === 7 ? { invisible: true } : {},
318
350
  ...state.fillPattern !== void 0 ? { fillPatternName: state.fillPattern } : {},
351
+ ...state.fillGradient ? { gradientFill: true } : {},
319
352
  ...strokesText(state.renderMode) ? {
320
353
  outlineHex: state.strokeColor,
321
354
  outlineWidthPt: ctmLineWidth()
322
355
  } : {},
323
356
  ...state.font.bold ? { bold: true } : {},
324
357
  ...state.font.italic ? { italic: true } : {},
325
- colorHex: state.fillColor,
358
+ colorHex: state.fillGradient ? midGradient(state.fillGradient) : state.fillColor,
326
359
  ...mcid !== void 0 ? { mcid } : {}
327
360
  });
328
361
  };
@@ -438,7 +471,9 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
438
471
  ...state.clip ? { clip: state.clip } : {},
439
472
  fillHex: state.fillColor,
440
473
  ...mcid !== void 0 ? { mcid } : {},
441
- ...state.blendMode !== void 0 ? { blend: state.blendMode } : {}
474
+ ...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
475
+ ...state.blendMode !== void 0 ? { blend: state.blendMode } : {},
476
+ ...state.softMask ? { masked: true } : {}
442
477
  });
443
478
  }
444
479
  break;
@@ -473,7 +508,7 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
473
508
  state.fillPattern = state.fillGradient ? void 0 : named;
474
509
  break;
475
510
  }
476
- const hex = componentColor(operands, state.fillSpace);
511
+ const hex = colorOfOperands(operands, state.fillSpace);
477
512
  if (hex !== void 0) {
478
513
  state.fillColor = hex;
479
514
  state.fillGradient = void 0;
@@ -484,7 +519,7 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
484
519
  case "SCN":
485
520
  case "SC": {
486
521
  if (operands[operands.length - 1] instanceof PdfName) break;
487
- const hex = componentColor(operands, state.strokeSpace);
522
+ const hex = colorOfOperands(operands, state.strokeSpace);
488
523
  if (hex !== void 0) state.strokeColor = hex;
489
524
  break;
490
525
  }
@@ -536,17 +571,32 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
536
571
  path.push({ op: "close" });
537
572
  paintPath(true, true);
538
573
  break;
574
+ case "sh": {
575
+ const nm = operands[0];
576
+ if (nm instanceof PdfName && visible()) painted.push({
577
+ name: nm.value,
578
+ ctm: state.ctm,
579
+ ...state.clip ? { clip: state.clip } : {},
580
+ ...state.softMask ? { masked: true } : {},
581
+ ...state.fillAlpha < 1 ? { alpha: state.fillAlpha } : {},
582
+ ...state.fillDarkens ? { darkens: true } : {},
583
+ order: paintOrder++
584
+ });
585
+ break;
586
+ }
539
587
  case "n":
540
588
  paintPath(false, false);
541
589
  break;
542
590
  case "gs": {
543
591
  const nm = operands[operands.length - 1];
544
- if (nm instanceof PdfName) {
545
- const paint = alphas.get(nm.value);
546
- state.fillAlpha = paint?.alpha ?? 1;
547
- state.fillDarkens = paint?.darkens ?? false;
548
- state.blendMode = paint?.blend;
549
- state.softMask = paint?.masked ?? false;
592
+ const paint = nm instanceof PdfName ? alphas.get(nm.value) : void 0;
593
+ if (paint) {
594
+ if (paint.alpha !== void 0) state.fillAlpha = paint.alpha;
595
+ if (paint.statesBlend === true) {
596
+ state.fillDarkens = paint.darkens ?? false;
597
+ state.blendMode = paint.blend;
598
+ }
599
+ if (paint.masked !== void 0) state.softMask = paint.masked;
550
600
  }
551
601
  break;
552
602
  }
@@ -605,7 +655,34 @@ function interpretContent(bytes, fonts, initialCtm = IDENTITY, shadings = /* @__
605
655
  texts: runs,
606
656
  images,
607
657
  vectors,
608
- glyphs
658
+ glyphs,
659
+ shadings: painted,
660
+ outlines
661
+ };
662
+ }
663
+ /** One path segment through a matrix — the glyph's own space onto the page. */
664
+ function mapSeg(seg, m) {
665
+ const at = (x, y) => [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];
666
+ if (seg.op === "close") return seg;
667
+ if (seg.op === "cubic") {
668
+ const [x1, y1] = at(seg.x1, seg.y1);
669
+ const [x2, y2] = at(seg.x2, seg.y2);
670
+ const [x, y] = at(seg.x, seg.y);
671
+ return {
672
+ op: "cubic",
673
+ x1,
674
+ y1,
675
+ x2,
676
+ y2,
677
+ x,
678
+ y
679
+ };
680
+ }
681
+ const [x, y] = at(seg.x, seg.y);
682
+ return {
683
+ op: seg.op,
684
+ x,
685
+ y
609
686
  };
610
687
  }
611
688
  /** §9.3.6 — the rendering modes that put a line round the glyphs. */
@@ -657,21 +734,6 @@ function isRightToLeft(text) {
657
734
  function isRtl(cp) {
658
735
  return cp >= 1424 && cp <= 1535 || cp >= 1536 && cp <= 1791 || cp >= 1792 && cp <= 1871 || cp >= 1920 && cp <= 1983 || cp >= 2208 && cp <= 2303 || cp >= 64285 && cp <= 65023 || cp >= 65136 && cp <= 65279;
659
736
  }
660
- function clamp255(v) {
661
- return Math.max(0, Math.min(255, Math.round(v * 255)));
662
- }
663
- function hex2(v) {
664
- return clamp255(v).toString(16).padStart(2, "0");
665
- }
666
- function rgbHex(r, g, b) {
667
- return (hex2(r) + hex2(g) + hex2(b)).toUpperCase();
668
- }
669
- function grayHex(v) {
670
- return rgbHex(v, v, v);
671
- }
672
- function cmykHex(c, m, y, k) {
673
- return rgbHex((1 - c) * (1 - k), (1 - m) * (1 - k), (1 - y) * (1 - k));
674
- }
675
737
  function matrixFromOperands(operands) {
676
738
  const n = (i) => typeof operands[i] === "number" ? operands[i] : 0;
677
739
  return [
@@ -705,9 +767,30 @@ function readArray(lexer) {
705
767
  for (;;) {
706
768
  const tok = lexer.nextToken();
707
769
  if (tok.kind === "arrayClose" || tok.kind === "eof") break;
708
- if (tok.kind === "num") out.push(tok.value);
709
- else if (tok.kind === "str") out.push(tok.value);
710
- else if (tok.kind === "hexstr") out.push(new PdfHexString(tok.bytes));
770
+ switch (tok.kind) {
771
+ case "num":
772
+ out.push(tok.value);
773
+ break;
774
+ case "str":
775
+ out.push(tok.value);
776
+ break;
777
+ case "hexstr":
778
+ out.push(new PdfHexString(tok.bytes));
779
+ break;
780
+ case "name":
781
+ out.push(new PdfName(tok.value));
782
+ break;
783
+ case "arrayOpen":
784
+ out.push(readArray(lexer));
785
+ break;
786
+ case "dictOpen":
787
+ out.push(readDict(lexer));
788
+ break;
789
+ case "keyword":
790
+ if (tok.value === "true" || tok.value === "false") out.push(tok.value === "true");
791
+ break;
792
+ default: break;
793
+ }
711
794
  }
712
795
  return out;
713
796
  }
@@ -0,0 +1,11 @@
1
+ /** The character a ZapfDingbats code stands for, or `undefined` for an unused one. */
2
+ export declare function zapfDingbatsChar(code: number): string | undefined;
3
+ /**
4
+ * The character a dingbat's glyph NAME stands for — `a38` is ✫ — for a font
5
+ * that names its glyphs through `/Differences` (§9.6.6.1).
6
+ *
7
+ * @param name The glyph name.
8
+ */
9
+ export declare function dingbatChar(name: string): string | undefined;
10
+ /** Whether a base font names the ZapfDingbats face (§9.6.2.2 Table 109). */
11
+ export declare function isZapfDingbats(baseFont: string): boolean;