@libpdf/core 0.1.0 → 0.2.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.
package/dist/index.mjs CHANGED
@@ -9,7 +9,7 @@ import { createCMSECDSASignature } from "pkijs";
9
9
  import { base64 } from "@scure/base";
10
10
 
11
11
  //#region package.json
12
- var version = "0.1.0";
12
+ var version = "0.2.0";
13
13
 
14
14
  //#endregion
15
15
  //#region src/objects/pdf-array.ts
@@ -44,9 +44,12 @@ var PdfArray = class PdfArray {
44
44
  }
45
45
  /**
46
46
  * Get item at index. Returns undefined if out of bounds.
47
+ * If resolver is provided, resolves indirect references.
47
48
  */
48
- at(index) {
49
- return this.items.at(index);
49
+ at(index, resolver) {
50
+ const value = this.items.at(index);
51
+ if (resolver && value?.type === "ref") return resolver(value) ?? void 0;
52
+ return value;
50
53
  }
51
54
  /**
52
55
  * Set item at index. Extends array if needed.
@@ -403,6 +406,69 @@ var PdfName = class PdfName {
403
406
  }
404
407
  };
405
408
 
409
+ //#endregion
410
+ //#region src/objects/pdf-ref.ts
411
+ /**
412
+ * Default cache size for PdfRef interning.
413
+ * Object references tend to be more numerous than names in typical PDFs.
414
+ */
415
+ const DEFAULT_REF_CACHE_SIZE = 2e4;
416
+ /**
417
+ * PDF indirect reference (interned).
418
+ *
419
+ * In PDF: `1 0 R`, `42 0 R`
420
+ *
421
+ * References are interned using an LRU cache to prevent unbounded memory growth.
422
+ * `PdfRef.of(1, 0) === PdfRef.of(1, 0)` as long as both are in cache.
423
+ * Use `.of()` to get or create instances.
424
+ */
425
+ var PdfRef = class PdfRef {
426
+ get type() {
427
+ return "ref";
428
+ }
429
+ static cache = new LRUCache(DEFAULT_REF_CACHE_SIZE);
430
+ constructor(objectNumber, generation) {
431
+ this.objectNumber = objectNumber;
432
+ this.generation = generation;
433
+ }
434
+ /**
435
+ * Get or create an interned PdfRef for the given object/generation pair.
436
+ */
437
+ static of(objectNumber, generation = 0) {
438
+ const key$1 = `${objectNumber} ${generation}`;
439
+ let cached = PdfRef.cache.get(key$1);
440
+ if (!cached) {
441
+ cached = new PdfRef(objectNumber, generation);
442
+ PdfRef.cache.set(key$1, cached);
443
+ }
444
+ return cached;
445
+ }
446
+ /**
447
+ * Clear the reference cache.
448
+ *
449
+ * Useful for long-running applications that process many PDFs
450
+ * and want to reclaim memory between documents.
451
+ */
452
+ static clearCache() {
453
+ PdfRef.cache.clear();
454
+ }
455
+ /**
456
+ * Get the current size of the LRU cache.
457
+ */
458
+ static get cacheSize() {
459
+ return PdfRef.cache.size;
460
+ }
461
+ /**
462
+ * Returns the PDF syntax representation: "1 0 R"
463
+ */
464
+ toString() {
465
+ return `${this.objectNumber} ${this.generation} R`;
466
+ }
467
+ toBytes(writer) {
468
+ writer.writeAscii(`${this.objectNumber} ${this.generation} R`);
469
+ }
470
+ };
471
+
406
472
  //#endregion
407
473
  //#region src/objects/pdf-dict.ts
408
474
  /**
@@ -441,9 +507,11 @@ var PdfDict = class PdfDict {
441
507
  /**
442
508
  * Get value for key. Key can be string or PdfName.
443
509
  */
444
- get(key$1) {
510
+ get(key$1, resolver) {
445
511
  const name = typeof key$1 === "string" ? PdfName.of(key$1) : key$1;
446
- return this.entries.get(name);
512
+ const value = this.entries.get(name);
513
+ if (resolver && value?.type === "ref") return resolver(value) ?? void 0;
514
+ return value;
447
515
  }
448
516
  /**
449
517
  * Set value for key. Key can be string or PdfName.
@@ -482,34 +550,38 @@ var PdfDict = class PdfDict {
482
550
  yield* this.entries;
483
551
  }
484
552
  /**
485
- * Typed getters
553
+ * Typed getters.
554
+ *
555
+ * All typed getters accept an optional resolver function. When provided,
556
+ * if the value is a PdfRef, it will be automatically dereferenced.
557
+ * This prevents the common bug of forgetting to handle indirect references.
486
558
  */
487
- getName(key$1) {
488
- const value = this.get(key$1);
559
+ getName(key$1, resolver) {
560
+ const value = this.get(key$1, resolver);
489
561
  return value?.type === "name" ? value : void 0;
490
562
  }
491
- getNumber(key$1) {
492
- const value = this.get(key$1);
563
+ getNumber(key$1, resolver) {
564
+ const value = this.get(key$1, resolver);
493
565
  return value?.type === "number" ? value : void 0;
494
566
  }
495
- getString(key$1) {
496
- const value = this.get(key$1);
567
+ getString(key$1, resolver) {
568
+ const value = this.get(key$1, resolver);
497
569
  return value?.type === "string" ? value : void 0;
498
570
  }
499
- getArray(key$1) {
500
- const value = this.get(key$1);
571
+ getArray(key$1, resolver) {
572
+ const value = this.get(key$1, resolver);
501
573
  return value?.type === "array" ? value : void 0;
502
574
  }
503
- getDict(key$1) {
504
- const value = this.get(key$1);
575
+ getDict(key$1, resolver) {
576
+ const value = this.get(key$1, resolver);
505
577
  return value?.type === "dict" ? value : void 0;
506
578
  }
507
579
  getRef(key$1) {
508
580
  const value = this.get(key$1);
509
581
  return value?.type === "ref" ? value : void 0;
510
582
  }
511
- getBool(key$1) {
512
- const value = this.get(key$1);
583
+ getBool(key$1, resolver) {
584
+ const value = this.get(key$1, resolver);
513
585
  return value?.type === "bool" ? value : void 0;
514
586
  }
515
587
  /**
@@ -2589,69 +2661,6 @@ const drawXObject = (name) => Operator.of(Op.DrawXObject, name);
2589
2661
  const beginMarkedContent = (tag) => Operator.of(Op.BeginMarkedContent, tag);
2590
2662
  const endMarkedContent = () => Operator.of(Op.EndMarkedContent);
2591
2663
 
2592
- //#endregion
2593
- //#region src/objects/pdf-ref.ts
2594
- /**
2595
- * Default cache size for PdfRef interning.
2596
- * Object references tend to be more numerous than names in typical PDFs.
2597
- */
2598
- const DEFAULT_REF_CACHE_SIZE = 2e4;
2599
- /**
2600
- * PDF indirect reference (interned).
2601
- *
2602
- * In PDF: `1 0 R`, `42 0 R`
2603
- *
2604
- * References are interned using an LRU cache to prevent unbounded memory growth.
2605
- * `PdfRef.of(1, 0) === PdfRef.of(1, 0)` as long as both are in cache.
2606
- * Use `.of()` to get or create instances.
2607
- */
2608
- var PdfRef = class PdfRef {
2609
- get type() {
2610
- return "ref";
2611
- }
2612
- static cache = new LRUCache(DEFAULT_REF_CACHE_SIZE);
2613
- constructor(objectNumber, generation) {
2614
- this.objectNumber = objectNumber;
2615
- this.generation = generation;
2616
- }
2617
- /**
2618
- * Get or create an interned PdfRef for the given object/generation pair.
2619
- */
2620
- static of(objectNumber, generation = 0) {
2621
- const key$1 = `${objectNumber} ${generation}`;
2622
- let cached = PdfRef.cache.get(key$1);
2623
- if (!cached) {
2624
- cached = new PdfRef(objectNumber, generation);
2625
- PdfRef.cache.set(key$1, cached);
2626
- }
2627
- return cached;
2628
- }
2629
- /**
2630
- * Clear the reference cache.
2631
- *
2632
- * Useful for long-running applications that process many PDFs
2633
- * and want to reclaim memory between documents.
2634
- */
2635
- static clearCache() {
2636
- PdfRef.cache.clear();
2637
- }
2638
- /**
2639
- * Get the current size of the LRU cache.
2640
- */
2641
- static get cacheSize() {
2642
- return PdfRef.cache.size;
2643
- }
2644
- /**
2645
- * Returns the PDF syntax representation: "1 0 R"
2646
- */
2647
- toString() {
2648
- return `${this.objectNumber} ${this.generation} R`;
2649
- }
2650
- toBytes(writer) {
2651
- writer.writeAscii(`${this.objectNumber} ${this.generation} R`);
2652
- }
2653
- };
2654
-
2655
2664
  //#endregion
2656
2665
  //#region src/helpers/colors.ts
2657
2666
  /**
@@ -3478,14 +3487,14 @@ var PDFAnnotation = class {
3478
3487
  * Annotation subtype (e.g., "Text", "Highlight", "Link").
3479
3488
  */
3480
3489
  get type() {
3481
- const subtype = this.dict.getName("Subtype")?.value;
3490
+ const subtype = this.dict.getName("Subtype", this.registry.resolve.bind(this.registry))?.value;
3482
3491
  return isAnnotationSubtype(subtype) ? subtype : "Text";
3483
3492
  }
3484
3493
  /**
3485
3494
  * Annotation rectangle in page coordinates.
3486
3495
  */
3487
3496
  get rect() {
3488
- const arr = this.dict.getArray("Rect");
3497
+ const arr = this.dict.getArray("Rect", this.registry.resolve.bind(this.registry));
3489
3498
  if (!arr || arr.length < 4) return {
3490
3499
  x: 0,
3491
3500
  y: 0,
@@ -3504,7 +3513,7 @@ var PDFAnnotation = class {
3504
3513
  * Set the annotation rectangle.
3505
3514
  */
3506
3515
  setRect(rect) {
3507
- const arr = this.dict.getArray("Rect");
3516
+ const arr = this.dict.getArray("Rect", this.registry.resolve.bind(this.registry));
3508
3517
  if (arr && arr.length >= 4) {
3509
3518
  arr.set(0, PdfNumber.of(rect.x));
3510
3519
  arr.set(1, PdfNumber.of(rect.y));
@@ -3522,7 +3531,7 @@ var PDFAnnotation = class {
3522
3531
  * Text content or description of the annotation.
3523
3532
  */
3524
3533
  get contents() {
3525
- return this.dict.getString("Contents")?.asString() ?? null;
3534
+ return this.dict.getString("Contents", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3526
3535
  }
3527
3536
  /**
3528
3537
  * Set the annotation contents.
@@ -3535,7 +3544,7 @@ var PDFAnnotation = class {
3535
3544
  * Annotation name (unique identifier within page).
3536
3545
  */
3537
3546
  get name() {
3538
- return this.dict.getString("NM")?.asString() ?? null;
3547
+ return this.dict.getString("NM", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3539
3548
  }
3540
3549
  /**
3541
3550
  * Set the annotation name.
@@ -3548,7 +3557,7 @@ var PDFAnnotation = class {
3548
3557
  * Modification date.
3549
3558
  */
3550
3559
  get modificationDate() {
3551
- return this.dict.getString("M")?.asString() ?? null;
3560
+ return this.dict.getString("M", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3552
3561
  }
3553
3562
  /**
3554
3563
  * Set the modification date (PDF date format).
@@ -3561,7 +3570,7 @@ var PDFAnnotation = class {
3561
3570
  * Annotation flags.
3562
3571
  */
3563
3572
  get flags() {
3564
- return this.dict.getNumber("F")?.value ?? 0;
3573
+ return this.dict.getNumber("F", this.registry.resolve.bind(this.registry))?.value ?? 0;
3565
3574
  }
3566
3575
  /**
3567
3576
  * Check if the annotation has a specific flag set.
@@ -3607,7 +3616,7 @@ var PDFAnnotation = class {
3607
3616
  * Annotation color.
3608
3617
  */
3609
3618
  get color() {
3610
- return parseColorArray(this.dict.getArray("C"));
3619
+ return parseColorArray(this.dict.getArray("C", this.registry.resolve.bind(this.registry)));
3611
3620
  }
3612
3621
  /**
3613
3622
  * Set the annotation color.
@@ -3621,13 +3630,13 @@ var PDFAnnotation = class {
3621
3630
  * Get the border style.
3622
3631
  */
3623
3632
  getBorderStyle() {
3624
- const bs = this.dict.getDict("BS");
3633
+ const bs = this.dict.getDict("BS", this.registry.resolve.bind(this.registry));
3625
3634
  if (!bs) return null;
3626
3635
  const result = {
3627
- width: bs.getNumber("W")?.value ?? 1,
3628
- style: BORDER_STYLE_MAP[bs.getName("S")?.value ?? "S"] ?? "solid"
3636
+ width: bs.getNumber("W", this.registry.resolve.bind(this.registry))?.value ?? 1,
3637
+ style: BORDER_STYLE_MAP[bs.getName("S", this.registry.resolve.bind(this.registry))?.value ?? "S"] ?? "solid"
3629
3638
  };
3630
- const dashArr = bs.getArray("D");
3639
+ const dashArr = bs.getArray("D", this.registry.resolve.bind(this.registry));
3631
3640
  if (dashArr) {
3632
3641
  result.dashArray = [];
3633
3642
  for (let i = 0; i < dashArr.length; i++) {
@@ -3652,9 +3661,8 @@ var PDFAnnotation = class {
3652
3661
  * Check if the annotation has a normal appearance stream.
3653
3662
  */
3654
3663
  hasNormalAppearance() {
3655
- let ap = this.dict.get("AP");
3656
- if (ap instanceof PdfRef) ap = this.registry.resolve(ap) ?? void 0;
3657
- if (ap instanceof PdfDict) return ap.has("N");
3664
+ const ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
3665
+ if (ap) return ap.has("N");
3658
3666
  return false;
3659
3667
  }
3660
3668
  /**
@@ -3697,12 +3705,9 @@ var PDFAnnotation = class {
3697
3705
  * Get an appearance stream by type.
3698
3706
  */
3699
3707
  getAppearance(type) {
3700
- let ap = this.dict.get("AP");
3701
- if (ap instanceof PdfRef) ap = this.registry.resolve(ap) ?? void 0;
3702
- if (!(ap instanceof PdfDict)) return null;
3703
- let entry = ap.get(type);
3704
- if (!entry) return null;
3705
- if (entry instanceof PdfRef) entry = this.registry.resolve(entry) ?? void 0;
3708
+ let ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
3709
+ if (!ap) return null;
3710
+ let entry = ap.get(type, this.registry.resolve.bind(this.registry));
3706
3711
  if (entry instanceof PdfStream) return entry;
3707
3712
  return null;
3708
3713
  }
@@ -3710,8 +3715,7 @@ var PDFAnnotation = class {
3710
3715
  * Set an appearance stream by type.
3711
3716
  */
3712
3717
  setAppearance(type, stream) {
3713
- let ap = this.dict.get("AP");
3714
- if (ap instanceof PdfRef) ap = this.registry.resolve(ap) ?? void 0;
3718
+ let ap = this.dict.getDict("AP", this.registry.resolve.bind(this.registry));
3715
3719
  if (ap instanceof PdfDict) {
3716
3720
  const streamRef = this.registry.register(stream);
3717
3721
  ap.set(type, streamRef);
@@ -3823,7 +3827,7 @@ var PDFMarkupAnnotation = class extends PDFAnnotation {
3823
3827
  * Text label for the annotation (often the author name).
3824
3828
  */
3825
3829
  get title() {
3826
- return this.dict.getString("T")?.asString() ?? null;
3830
+ return this.dict.getString("T", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3827
3831
  }
3828
3832
  /**
3829
3833
  * Set the title/author.
@@ -3837,7 +3841,7 @@ var PDFMarkupAnnotation = class extends PDFAnnotation {
3837
3841
  * Range 0-1, where 0 is fully transparent and 1 is fully opaque.
3838
3842
  */
3839
3843
  get opacity() {
3840
- return this.dict.getNumber("CA")?.value ?? 1;
3844
+ return this.dict.getNumber("CA", this.registry.resolve.bind(this.registry))?.value ?? 1;
3841
3845
  }
3842
3846
  /**
3843
3847
  * Set the opacity.
@@ -3851,7 +3855,7 @@ var PDFMarkupAnnotation = class extends PDFAnnotation {
3851
3855
  * Creation date (CreationDate).
3852
3856
  */
3853
3857
  get creationDate() {
3854
- return this.dict.getString("CreationDate")?.asString() ?? null;
3858
+ return this.dict.getString("CreationDate", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3855
3859
  }
3856
3860
  /**
3857
3861
  * Set the creation date.
@@ -3864,7 +3868,7 @@ var PDFMarkupAnnotation = class extends PDFAnnotation {
3864
3868
  * Subject - the subject of the annotation.
3865
3869
  */
3866
3870
  get subject() {
3867
- return this.dict.getString("Subj")?.asString() ?? null;
3871
+ return this.dict.getString("Subj", this.registry.resolve.bind(this.registry))?.asString() ?? null;
3868
3872
  }
3869
3873
  /**
3870
3874
  * Set the subject.
@@ -3929,7 +3933,7 @@ var PDFMarkupAnnotation = class extends PDFAnnotation {
3929
3933
  * Intent (IT) - the intent of the markup annotation.
3930
3934
  */
3931
3935
  get intent() {
3932
- return this.dict.getName("IT")?.value ?? null;
3936
+ return this.dict.getName("IT", this.registry.resolve.bind(this.registry))?.value ?? null;
3933
3937
  }
3934
3938
  };
3935
3939
 
@@ -3952,7 +3956,7 @@ var PDFCaretAnnotation = class extends PDFMarkupAnnotation {
3952
3956
  * "P" = paragraph symbol, "None" = no symbol.
3953
3957
  */
3954
3958
  get symbol() {
3955
- if (this.dict.getName("Sy")?.value === "P") return "P";
3959
+ if (this.dict.getName("Sy", this.registry.resolve.bind(this.registry))?.value === "P") return "P";
3956
3960
  return "None";
3957
3961
  }
3958
3962
  /**
@@ -3974,7 +3978,7 @@ var PDFFileAttachmentAnnotation = class extends PDFMarkupAnnotation {
3974
3978
  * Icon to display.
3975
3979
  */
3976
3980
  get icon() {
3977
- const name = this.dict.getName("Name");
3981
+ const name = this.dict.getName("Name", this.registry.resolve.bind(this.registry));
3978
3982
  if (!name) return "PushPin";
3979
3983
  if (isFileAttachmentIcon(name.value)) return name.value;
3980
3984
  return "PushPin";
@@ -3997,11 +4001,7 @@ var PDFFileAttachmentAnnotation = class extends PDFMarkupAnnotation {
3997
4001
  * Get the file specification dictionary.
3998
4002
  */
3999
4003
  getFileSpec() {
4000
- const fsRef = this.fileSpecRef;
4001
- if (!fsRef) return this.dict.getDict("FS") ?? null;
4002
- const resolved = this.registry.resolve(fsRef);
4003
- if (resolved && resolved.type === "dict") return resolved;
4004
- return null;
4004
+ return this.dict.getDict("FS", this.registry.resolve.bind(this.registry)) ?? null;
4005
4005
  }
4006
4006
  /**
4007
4007
  * Get the file name from the file specification.
@@ -4009,9 +4009,9 @@ var PDFFileAttachmentAnnotation = class extends PDFMarkupAnnotation {
4009
4009
  getFileName() {
4010
4010
  const fs = this.getFileSpec();
4011
4011
  if (!fs) return null;
4012
- const uf = fs.getString("UF");
4012
+ const uf = fs.getString("UF", this.registry.resolve.bind(this.registry));
4013
4013
  if (uf) return uf.asString();
4014
- const f = fs.getString("F");
4014
+ const f = fs.getString("F", this.registry.resolve.bind(this.registry));
4015
4015
  if (f) return f.asString();
4016
4016
  return null;
4017
4017
  }
@@ -4036,7 +4036,7 @@ var PDFFreeTextAnnotation = class extends PDFMarkupAnnotation {
4036
4036
  * Contains font and color operators.
4037
4037
  */
4038
4038
  get defaultAppearance() {
4039
- return this.dict.getString("DA")?.asString() ?? null;
4039
+ return this.dict.getString("DA", this.registry.resolve.bind(this.registry))?.asString() ?? null;
4040
4040
  }
4041
4041
  /**
4042
4042
  * Set the default appearance.
@@ -4049,7 +4049,7 @@ var PDFFreeTextAnnotation = class extends PDFMarkupAnnotation {
4049
4049
  * Text justification: 0=left, 1=center, 2=right.
4050
4050
  */
4051
4051
  get justification() {
4052
- switch (this.dict.getNumber("Q")?.value ?? 0) {
4052
+ switch (this.dict.getNumber("Q", this.registry.resolve.bind(this.registry))?.value ?? 0) {
4053
4053
  case 1: return "center";
4054
4054
  case 2: return "right";
4055
4055
  default: return "left";
@@ -4070,7 +4070,7 @@ var PDFFreeTextAnnotation = class extends PDFMarkupAnnotation {
4070
4070
  * Contains CSS-style formatting.
4071
4071
  */
4072
4072
  get defaultStyle() {
4073
- return this.dict.getString("DS")?.asString() ?? null;
4073
+ return this.dict.getString("DS", this.registry.resolve.bind(this.registry))?.asString() ?? null;
4074
4074
  }
4075
4075
  /**
4076
4076
  * Set the default style.
@@ -4084,7 +4084,7 @@ var PDFFreeTextAnnotation = class extends PDFMarkupAnnotation {
4084
4084
  * Can be "FreeText", "FreeTextCallout", or "FreeTextTypeWriter".
4085
4085
  */
4086
4086
  get freeTextIntent() {
4087
- return this.dict.getName("IT")?.value ?? null;
4087
+ return this.dict.getName("IT", this.registry.resolve.bind(this.registry))?.value ?? null;
4088
4088
  }
4089
4089
  /**
4090
4090
  * Set the intent.
@@ -4161,7 +4161,7 @@ var PDFInkAnnotation = class extends PDFMarkupAnnotation {
4161
4161
  * Each path is an array of points.
4162
4162
  */
4163
4163
  get inkPaths() {
4164
- const inkList = this.dict.getArray("InkList");
4164
+ const inkList = this.dict.getArray("InkList", this.registry.resolve.bind(this.registry));
4165
4165
  if (!inkList) return [];
4166
4166
  const paths = [];
4167
4167
  for (let i = 0; i < inkList.length; i++) {
@@ -4266,7 +4266,7 @@ var PDFLineAnnotation = class extends PDFMarkupAnnotation {
4266
4266
  * Get the line endpoints.
4267
4267
  */
4268
4268
  get lineEndpoints() {
4269
- const l = this.dict.getArray("L");
4269
+ const l = this.dict.getArray("L", this.registry.resolve.bind(this.registry));
4270
4270
  if (!l || l.length < 4) return {
4271
4271
  start: {
4272
4272
  x: 0,
@@ -4293,7 +4293,7 @@ var PDFLineAnnotation = class extends PDFMarkupAnnotation {
4293
4293
  * Set the line endpoints.
4294
4294
  */
4295
4295
  setLineEndpoints(start, end) {
4296
- const arr = this.dict.getArray("L");
4296
+ const arr = this.dict.getArray("L", this.registry.resolve.bind(this.registry));
4297
4297
  if (arr && arr.length >= 4) {
4298
4298
  arr.set(0, PdfNumber.of(start.x));
4299
4299
  arr.set(1, PdfNumber.of(start.y));
@@ -4323,7 +4323,7 @@ var PDFLineAnnotation = class extends PDFMarkupAnnotation {
4323
4323
  * Line ending styles [start, end].
4324
4324
  */
4325
4325
  get lineEndingStyles() {
4326
- const le = this.dict.getArray("LE");
4326
+ const le = this.dict.getArray("LE", this.registry.resolve.bind(this.registry));
4327
4327
  if (!le || le.length < 2) return ["None", "None"];
4328
4328
  const [startStyle, endStyle] = le.toArray().map((item) => item instanceof PdfName ? item.value : "None");
4329
4329
  return [startStyle ?? "None", endStyle ?? "None"];
@@ -4339,7 +4339,7 @@ var PDFLineAnnotation = class extends PDFMarkupAnnotation {
4339
4339
  * Interior color (fill color for closed arrow heads).
4340
4340
  */
4341
4341
  get interiorColor() {
4342
- return parseColorArray(this.dict.getArray("IC"));
4342
+ return parseColorArray(this.dict.getArray("IC", this.registry.resolve.bind(this.registry)));
4343
4343
  }
4344
4344
  /**
4345
4345
  * Set the interior color.
@@ -4353,19 +4353,19 @@ var PDFLineAnnotation = class extends PDFMarkupAnnotation {
4353
4353
  * Line leader length (for dimension lines).
4354
4354
  */
4355
4355
  get leaderLength() {
4356
- return this.dict.getNumber("LL")?.value ?? 0;
4356
+ return this.dict.getNumber("LL", this.registry.resolve.bind(this.registry))?.value ?? 0;
4357
4357
  }
4358
4358
  /**
4359
4359
  * Line leader line extension.
4360
4360
  */
4361
4361
  get leaderExtension() {
4362
- return this.dict.getNumber("LLE")?.value ?? 0;
4362
+ return this.dict.getNumber("LLE", this.registry.resolve.bind(this.registry))?.value ?? 0;
4363
4363
  }
4364
4364
  /**
4365
4365
  * Caption flag - whether to show caption with the line.
4366
4366
  */
4367
4367
  get hasCaption() {
4368
- return this.dict.getBool("Cap")?.value ?? false;
4368
+ return this.dict.getBool("Cap", this.registry.resolve.bind(this.registry))?.value ?? false;
4369
4369
  }
4370
4370
  /**
4371
4371
  * Line width from border style.
@@ -4872,240 +4872,6 @@ function rectsToQuadPoints(rects) {
4872
4872
  return rects.map(rectToQuadPoints);
4873
4873
  }
4874
4874
 
4875
- //#endregion
4876
- //#region src/helpers/unicode.ts
4877
- /**
4878
- * Unicode utilities for PDF text handling.
4879
- *
4880
- * Provides mappings between Unicode code points and PostScript glyph names.
4881
- */
4882
- /**
4883
- * Map Unicode code point to PostScript glyph name.
4884
- * Returns undefined if no mapping exists.
4885
- */
4886
- function unicodeToGlyphName(unicode) {
4887
- return UNICODE_TO_GLYPH.get(unicode);
4888
- }
4889
- /**
4890
- * Common Unicode to glyph name mappings.
4891
- * Covers ASCII and common Latin-1 extended characters.
4892
- *
4893
- * For a complete mapping, see the Adobe Glyph List:
4894
- * https://github.com/adobe-type-tools/agl-aglfn
4895
- */
4896
- const UNICODE_TO_GLYPH = new Map([
4897
- [32, "space"],
4898
- [33, "exclam"],
4899
- [34, "quotedbl"],
4900
- [35, "numbersign"],
4901
- [36, "dollar"],
4902
- [37, "percent"],
4903
- [38, "ampersand"],
4904
- [39, "quotesingle"],
4905
- [40, "parenleft"],
4906
- [41, "parenright"],
4907
- [42, "asterisk"],
4908
- [43, "plus"],
4909
- [44, "comma"],
4910
- [45, "hyphen"],
4911
- [46, "period"],
4912
- [47, "slash"],
4913
- [48, "zero"],
4914
- [49, "one"],
4915
- [50, "two"],
4916
- [51, "three"],
4917
- [52, "four"],
4918
- [53, "five"],
4919
- [54, "six"],
4920
- [55, "seven"],
4921
- [56, "eight"],
4922
- [57, "nine"],
4923
- [58, "colon"],
4924
- [59, "semicolon"],
4925
- [60, "less"],
4926
- [61, "equal"],
4927
- [62, "greater"],
4928
- [63, "question"],
4929
- [64, "at"],
4930
- [65, "A"],
4931
- [66, "B"],
4932
- [67, "C"],
4933
- [68, "D"],
4934
- [69, "E"],
4935
- [70, "F"],
4936
- [71, "G"],
4937
- [72, "H"],
4938
- [73, "I"],
4939
- [74, "J"],
4940
- [75, "K"],
4941
- [76, "L"],
4942
- [77, "M"],
4943
- [78, "N"],
4944
- [79, "O"],
4945
- [80, "P"],
4946
- [81, "Q"],
4947
- [82, "R"],
4948
- [83, "S"],
4949
- [84, "T"],
4950
- [85, "U"],
4951
- [86, "V"],
4952
- [87, "W"],
4953
- [88, "X"],
4954
- [89, "Y"],
4955
- [90, "Z"],
4956
- [91, "bracketleft"],
4957
- [92, "backslash"],
4958
- [93, "bracketright"],
4959
- [94, "asciicircum"],
4960
- [95, "underscore"],
4961
- [96, "grave"],
4962
- [97, "a"],
4963
- [98, "b"],
4964
- [99, "c"],
4965
- [100, "d"],
4966
- [101, "e"],
4967
- [102, "f"],
4968
- [103, "g"],
4969
- [104, "h"],
4970
- [105, "i"],
4971
- [106, "j"],
4972
- [107, "k"],
4973
- [108, "l"],
4974
- [109, "m"],
4975
- [110, "n"],
4976
- [111, "o"],
4977
- [112, "p"],
4978
- [113, "q"],
4979
- [114, "r"],
4980
- [115, "s"],
4981
- [116, "t"],
4982
- [117, "u"],
4983
- [118, "v"],
4984
- [119, "w"],
4985
- [120, "x"],
4986
- [121, "y"],
4987
- [122, "z"],
4988
- [123, "braceleft"],
4989
- [124, "bar"],
4990
- [125, "braceright"],
4991
- [126, "asciitilde"],
4992
- [160, "nbspace"],
4993
- [161, "exclamdown"],
4994
- [162, "cent"],
4995
- [163, "sterling"],
4996
- [164, "currency"],
4997
- [165, "yen"],
4998
- [166, "brokenbar"],
4999
- [167, "section"],
5000
- [168, "dieresis"],
5001
- [169, "copyright"],
5002
- [170, "ordfeminine"],
5003
- [171, "guillemotleft"],
5004
- [172, "logicalnot"],
5005
- [173, "softhyphen"],
5006
- [174, "registered"],
5007
- [175, "macron"],
5008
- [176, "degree"],
5009
- [177, "plusminus"],
5010
- [178, "twosuperior"],
5011
- [179, "threesuperior"],
5012
- [180, "acute"],
5013
- [181, "mu"],
5014
- [182, "paragraph"],
5015
- [183, "periodcentered"],
5016
- [184, "cedilla"],
5017
- [185, "onesuperior"],
5018
- [186, "ordmasculine"],
5019
- [187, "guillemotright"],
5020
- [188, "onequarter"],
5021
- [189, "onehalf"],
5022
- [190, "threequarters"],
5023
- [191, "questiondown"],
5024
- [192, "Agrave"],
5025
- [193, "Aacute"],
5026
- [194, "Acircumflex"],
5027
- [195, "Atilde"],
5028
- [196, "Adieresis"],
5029
- [197, "Aring"],
5030
- [198, "AE"],
5031
- [199, "Ccedilla"],
5032
- [200, "Egrave"],
5033
- [201, "Eacute"],
5034
- [202, "Ecircumflex"],
5035
- [203, "Edieresis"],
5036
- [204, "Igrave"],
5037
- [205, "Iacute"],
5038
- [206, "Icircumflex"],
5039
- [207, "Idieresis"],
5040
- [208, "Eth"],
5041
- [209, "Ntilde"],
5042
- [210, "Ograve"],
5043
- [211, "Oacute"],
5044
- [212, "Ocircumflex"],
5045
- [213, "Otilde"],
5046
- [214, "Odieresis"],
5047
- [215, "multiply"],
5048
- [216, "Oslash"],
5049
- [217, "Ugrave"],
5050
- [218, "Uacute"],
5051
- [219, "Ucircumflex"],
5052
- [220, "Udieresis"],
5053
- [221, "Yacute"],
5054
- [222, "Thorn"],
5055
- [223, "germandbls"],
5056
- [224, "agrave"],
5057
- [225, "aacute"],
5058
- [226, "acircumflex"],
5059
- [227, "atilde"],
5060
- [228, "adieresis"],
5061
- [229, "aring"],
5062
- [230, "ae"],
5063
- [231, "ccedilla"],
5064
- [232, "egrave"],
5065
- [233, "eacute"],
5066
- [234, "ecircumflex"],
5067
- [235, "edieresis"],
5068
- [236, "igrave"],
5069
- [237, "iacute"],
5070
- [238, "icircumflex"],
5071
- [239, "idieresis"],
5072
- [240, "eth"],
5073
- [241, "ntilde"],
5074
- [242, "ograve"],
5075
- [243, "oacute"],
5076
- [244, "ocircumflex"],
5077
- [245, "otilde"],
5078
- [246, "odieresis"],
5079
- [247, "divide"],
5080
- [248, "oslash"],
5081
- [249, "ugrave"],
5082
- [250, "uacute"],
5083
- [251, "ucircumflex"],
5084
- [252, "udieresis"],
5085
- [253, "yacute"],
5086
- [254, "thorn"],
5087
- [255, "ydieresis"],
5088
- [8211, "endash"],
5089
- [8212, "emdash"],
5090
- [8216, "quoteleft"],
5091
- [8217, "quoteright"],
5092
- [8218, "quotesinglbase"],
5093
- [8220, "quotedblleft"],
5094
- [8221, "quotedblright"],
5095
- [8222, "quotedblbase"],
5096
- [8224, "dagger"],
5097
- [8225, "daggerdbl"],
5098
- [8226, "bullet"],
5099
- [8230, "ellipsis"],
5100
- [8240, "perthousand"],
5101
- [8249, "guilsinglleft"],
5102
- [8250, "guilsinglright"],
5103
- [8364, "Euro"],
5104
- [8482, "trademark"],
5105
- [64257, "fi"],
5106
- [64258, "fl"]
5107
- ]);
5108
-
5109
4875
  //#endregion
5110
4876
  //#region src/io/scanner.ts
5111
4877
  /**
@@ -10955,9 +10721,9 @@ function parseEmbeddedProgram(descriptor, options) {
10955
10721
  * Try to parse a TrueType font from /FontFile2.
10956
10722
  */
10957
10723
  function tryParseFontFile2(descriptor, options) {
10958
- const fontFile2 = resolveValue(descriptor.get("FontFile2"), options);
10959
- if (!fontFile2) return null;
10960
- const data = options.decodeStream(fontFile2);
10724
+ const fontFile2 = descriptor.get("FontFile2", options.resolver);
10725
+ if (!(fontFile2 instanceof PdfStream)) return null;
10726
+ const data = fontFile2.getDecodedData();
10961
10727
  if (!data || data.length === 0) return null;
10962
10728
  try {
10963
10729
  return new TrueTypeFontProgram(parseTTF(data, { isEmbedded: true }), data);
@@ -10970,10 +10736,10 @@ function tryParseFontFile2(descriptor, options) {
10970
10736
  * Try to parse a CFF or OpenType font from /FontFile3.
10971
10737
  */
10972
10738
  function tryParseFontFile3(descriptor, options) {
10973
- const fontFile3 = resolveValue(descriptor.get("FontFile3"), options);
10974
- if (!fontFile3) return null;
10739
+ const fontFile3 = descriptor.get("FontFile3", options.resolver);
10740
+ if (!(fontFile3 instanceof PdfStream)) return null;
10975
10741
  const subtype = getStreamSubtype(fontFile3);
10976
- const data = options.decodeStream(fontFile3);
10742
+ const data = fontFile3.getDecodedData();
10977
10743
  if (!data || data.length === 0) return null;
10978
10744
  try {
10979
10745
  if (subtype === "OpenType") return new TrueTypeFontProgram(parseTTF(data, { isEmbedded: true }), data);
@@ -10994,9 +10760,9 @@ function tryParseFontFile3(descriptor, options) {
10994
10760
  * Try to parse a Type1 font from /FontFile.
10995
10761
  */
10996
10762
  function tryParseFontFile(descriptor, options) {
10997
- const fontFile = resolveValue(descriptor.get("FontFile"), options);
10998
- if (!fontFile) return null;
10999
- const data = options.decodeStream(fontFile);
10763
+ const fontFile = descriptor.get("FontFile", options.resolver);
10764
+ if (!(fontFile instanceof PdfStream)) return null;
10765
+ const data = fontFile.getDecodedData();
11000
10766
  if (!data || data.length === 0) return null;
11001
10767
  try {
11002
10768
  return new Type1FontProgram(parsePfb(data), data);
@@ -11029,15 +10795,7 @@ function tryAutoDetectFontFile3(data) {
11029
10795
  * Get the /Subtype from a stream dictionary.
11030
10796
  */
11031
10797
  function getStreamSubtype(stream) {
11032
- if (stream && stream instanceof PdfStream) return stream.getName("Subtype")?.value;
11033
- }
11034
- /**
11035
- * Resolve a value through indirect references.
11036
- */
11037
- function resolveValue(value, options) {
11038
- if (!value) return null;
11039
- if (options.resolveRef && value instanceof PdfRef) return options.resolveRef(value);
11040
- return value;
10798
+ if (stream) return stream.getName("Subtype")?.value;
11041
10799
  }
11042
10800
  /**
11043
10801
  * Parse a font program directly from bytes.
@@ -11071,6 +10829,725 @@ function parseFontProgram(data) {
11071
10829
  throw new Error("Unrecognized font format");
11072
10830
  }
11073
10831
 
10832
+ //#endregion
10833
+ //#region src/fonts/font-descriptor.ts
10834
+ /**
10835
+ * Font flags as defined in PDF spec Table 123.
10836
+ */
10837
+ const FontFlags = {
10838
+ FIXED_PITCH: 1,
10839
+ SERIF: 2,
10840
+ SYMBOLIC: 4,
10841
+ SCRIPT: 8,
10842
+ NONSYMBOLIC: 32,
10843
+ ITALIC: 64,
10844
+ ALL_CAP: 65536,
10845
+ SMALL_CAP: 1 << 17,
10846
+ FORCE_BOLD: 1 << 18
10847
+ };
10848
+ /**
10849
+ * FontDescriptor contains font metrics and flags.
10850
+ */
10851
+ var FontDescriptor = class FontDescriptor {
10852
+ fontName;
10853
+ flags;
10854
+ fontBBox;
10855
+ italicAngle;
10856
+ ascent;
10857
+ descent;
10858
+ leading;
10859
+ capHeight;
10860
+ xHeight;
10861
+ stemV;
10862
+ stemH;
10863
+ avgWidth;
10864
+ maxWidth;
10865
+ missingWidth;
10866
+ constructor(data) {
10867
+ this.fontName = data.fontName;
10868
+ this.flags = data.flags;
10869
+ this.fontBBox = data.fontBBox;
10870
+ this.italicAngle = data.italicAngle;
10871
+ this.ascent = data.ascent;
10872
+ this.descent = data.descent;
10873
+ this.leading = data.leading;
10874
+ this.capHeight = data.capHeight;
10875
+ this.xHeight = data.xHeight;
10876
+ this.stemV = data.stemV;
10877
+ this.stemH = data.stemH;
10878
+ this.avgWidth = data.avgWidth;
10879
+ this.maxWidth = data.maxWidth;
10880
+ this.missingWidth = data.missingWidth;
10881
+ }
10882
+ /** Check if font is fixed-pitch (monospace) */
10883
+ get isFixedPitch() {
10884
+ return (this.flags & FontFlags.FIXED_PITCH) !== 0;
10885
+ }
10886
+ /** Check if font is serif */
10887
+ get isSerif() {
10888
+ return (this.flags & FontFlags.SERIF) !== 0;
10889
+ }
10890
+ /** Check if font is symbolic (uses custom encoding) */
10891
+ get isSymbolic() {
10892
+ return (this.flags & FontFlags.SYMBOLIC) !== 0;
10893
+ }
10894
+ /** Check if font is script (cursive) */
10895
+ get isScript() {
10896
+ return (this.flags & FontFlags.SCRIPT) !== 0;
10897
+ }
10898
+ /** Check if font is non-symbolic (uses standard encoding) */
10899
+ get isNonSymbolic() {
10900
+ return (this.flags & FontFlags.NONSYMBOLIC) !== 0;
10901
+ }
10902
+ /** Check if font is italic */
10903
+ get isItalic() {
10904
+ return (this.flags & FontFlags.ITALIC) !== 0;
10905
+ }
10906
+ /** Check if font is all caps */
10907
+ get isAllCap() {
10908
+ return (this.flags & FontFlags.ALL_CAP) !== 0;
10909
+ }
10910
+ /** Check if font is small caps */
10911
+ get isSmallCap() {
10912
+ return (this.flags & FontFlags.SMALL_CAP) !== 0;
10913
+ }
10914
+ /** Check if font should be bold */
10915
+ get isForceBold() {
10916
+ return (this.flags & FontFlags.FORCE_BOLD) !== 0;
10917
+ }
10918
+ /**
10919
+ * Parse FontDescriptor from a PDF dictionary.
10920
+ */
10921
+ static parse(dict) {
10922
+ const bboxArray = dict.getArray("FontBBox");
10923
+ const fontBBox = [
10924
+ 0,
10925
+ 0,
10926
+ 0,
10927
+ 0
10928
+ ];
10929
+ if (bboxArray && bboxArray.length >= 4) for (let i = 0; i < 4; i++) {
10930
+ const item = bboxArray.at(i);
10931
+ if (item instanceof PdfNumber) fontBBox[i] = item.value;
10932
+ }
10933
+ return new FontDescriptor({
10934
+ fontName: dict.getName("FontName")?.value ?? "",
10935
+ flags: dict.getNumber("Flags")?.value ?? 0,
10936
+ fontBBox,
10937
+ italicAngle: dict.getNumber("ItalicAngle")?.value ?? 0,
10938
+ ascent: dict.getNumber("Ascent")?.value ?? 0,
10939
+ descent: dict.getNumber("Descent")?.value ?? 0,
10940
+ leading: dict.getNumber("Leading")?.value ?? 0,
10941
+ capHeight: dict.getNumber("CapHeight")?.value ?? 0,
10942
+ xHeight: dict.getNumber("XHeight")?.value ?? 0,
10943
+ stemV: dict.getNumber("StemV")?.value ?? 0,
10944
+ stemH: dict.getNumber("StemH")?.value ?? 0,
10945
+ avgWidth: dict.getNumber("AvgWidth")?.value ?? 0,
10946
+ maxWidth: dict.getNumber("MaxWidth")?.value ?? 0,
10947
+ missingWidth: dict.getNumber("MissingWidth")?.value ?? 0
10948
+ });
10949
+ }
10950
+ };
10951
+
10952
+ //#endregion
10953
+ //#region src/fonts/pdf-font.ts
10954
+ /**
10955
+ * Abstract base class for PDF fonts.
10956
+ */
10957
+ var PdfFont = class {
10958
+ /**
10959
+ * Get width of text in points at a given font size.
10960
+ *
10961
+ * @param text - Unicode text to measure
10962
+ * @param fontSize - Font size in points
10963
+ * @returns Width in points
10964
+ */
10965
+ getTextWidth(text, fontSize) {
10966
+ let totalWidth = 0;
10967
+ const codes = this.encodeText(text);
10968
+ for (const code of codes) totalWidth += this.getWidth(code);
10969
+ return totalWidth * fontSize / 1e3;
10970
+ }
10971
+ };
10972
+
10973
+ //#endregion
10974
+ //#region src/fonts/embedded-font.ts
10975
+ /**
10976
+ * EmbeddedFont represents a font that will be embedded into a PDF.
10977
+ *
10978
+ * Usage:
10979
+ * ```typescript
10980
+ * const fontBytes = await fs.readFile("NotoSans-Regular.ttf");
10981
+ * const font = EmbeddedFont.fromBytes(fontBytes);
10982
+ *
10983
+ * // Check if text can be encoded
10984
+ * if (font.canEncode("Hello ")) {
10985
+ * const codes = font.encodeText("Hello ");
10986
+ * const width = font.getTextWidth("Hello ", 12);
10987
+ * }
10988
+ * ```
10989
+ */
10990
+ var EmbeddedFont = class EmbeddedFont extends PdfFont {
10991
+ subtype = "Type0";
10992
+ /** Underlying font program */
10993
+ fontProgram;
10994
+ /** Original font data */
10995
+ fontData;
10996
+ /** Track used glyphs for subsetting (GID -> code points that use it) */
10997
+ usedGlyphs = new Map([[0, /* @__PURE__ */ new Set()]]);
10998
+ /** Track used code points for ToUnicode (codePoint -> GID) */
10999
+ usedCodePoints = /* @__PURE__ */ new Map();
11000
+ /** Subset tag (generated during save) */
11001
+ _subsetTag = null;
11002
+ /** Whether this font is used in a form field (prevents subsetting) */
11003
+ _usedInForm = false;
11004
+ /** Cached descriptor */
11005
+ _descriptor = null;
11006
+ constructor(fontProgram, fontData) {
11007
+ super();
11008
+ this.fontProgram = fontProgram;
11009
+ this.fontData = fontData;
11010
+ }
11011
+ /**
11012
+ * Create an EmbeddedFont from raw font bytes.
11013
+ *
11014
+ * @param data - TTF, OTF, or Type1 font data
11015
+ * @param options - Embedding options
11016
+ * @returns EmbeddedFont instance
11017
+ * @throws {Error} if font format is not recognized
11018
+ */
11019
+ static fromBytes(data, _options) {
11020
+ return new EmbeddedFont(parseFontProgram(data), data);
11021
+ }
11022
+ /**
11023
+ * Create an EmbeddedFont from an already-parsed TrueType font.
11024
+ */
11025
+ static fromTrueTypeFont(font, data) {
11026
+ return new EmbeddedFont(new TrueTypeFontProgram(font, data), data);
11027
+ }
11028
+ /**
11029
+ * Get the base font name.
11030
+ * During save, this will include a subset tag prefix (e.g., "ABCDEF+FontName").
11031
+ */
11032
+ get baseFontName() {
11033
+ const name = this.fontProgram.postScriptName ?? "Unknown";
11034
+ return this._subsetTag ? `${this._subsetTag}+${name}` : name;
11035
+ }
11036
+ /**
11037
+ * Get the font descriptor.
11038
+ */
11039
+ get descriptor() {
11040
+ if (!this._descriptor) this._descriptor = this.buildDescriptor();
11041
+ return this._descriptor;
11042
+ }
11043
+ /**
11044
+ * Get the underlying font program.
11045
+ */
11046
+ get program() {
11047
+ return this.fontProgram;
11048
+ }
11049
+ /**
11050
+ * Get the original font data.
11051
+ */
11052
+ get data() {
11053
+ return this.fontData;
11054
+ }
11055
+ /**
11056
+ * Get the subset tag (only available after save).
11057
+ */
11058
+ get subsetTag() {
11059
+ return this._subsetTag;
11060
+ }
11061
+ /**
11062
+ * Set the subset tag (called during save).
11063
+ */
11064
+ setSubsetTag(tag) {
11065
+ this._subsetTag = tag;
11066
+ }
11067
+ /**
11068
+ * Get all used glyph IDs.
11069
+ */
11070
+ getUsedGlyphIds() {
11071
+ return [...this.usedGlyphs.keys()].sort((a, b) => a - b);
11072
+ }
11073
+ /**
11074
+ * Get mapping from code point to GID.
11075
+ */
11076
+ getCodePointToGidMap() {
11077
+ return new Map(this.usedCodePoints);
11078
+ }
11079
+ /**
11080
+ * Get mapping from GID to Unicode code point.
11081
+ *
11082
+ * This is used for building the /W widths array and ToUnicode CMap.
11083
+ * Since the content stream contains GIDs (with CIDToGIDMap /Identity),
11084
+ * the /W array must be keyed by GID, and ToUnicode must map GID → Unicode.
11085
+ *
11086
+ * If multiple code points map to the same GID, returns the first one found.
11087
+ */
11088
+ getGidToCodePointMap() {
11089
+ const result = /* @__PURE__ */ new Map();
11090
+ for (const [gid, codePoints] of this.usedGlyphs) if (codePoints.size > 0) {
11091
+ const firstCodePoint = codePoints.values().next().value;
11092
+ if (firstCodePoint !== void 0) result.set(gid, firstCodePoint);
11093
+ }
11094
+ return result;
11095
+ }
11096
+ /**
11097
+ * Iterate over text, tracking glyph usage and returning codePoint/GID pairs.
11098
+ * This is the shared implementation for encodeText and encodeTextToGids.
11099
+ */
11100
+ trackAndEncode(text) {
11101
+ const result = [];
11102
+ for (const char of text) {
11103
+ const codePoint = char.codePointAt(0);
11104
+ if (codePoint === void 0) continue;
11105
+ const gid = this.fontProgram.getGlyphId(codePoint);
11106
+ if (!this.usedGlyphs.has(gid)) this.usedGlyphs.set(gid, /* @__PURE__ */ new Set());
11107
+ this.usedGlyphs.get(gid).add(codePoint);
11108
+ this.usedCodePoints.set(codePoint, gid);
11109
+ result.push({
11110
+ codePoint,
11111
+ gid
11112
+ });
11113
+ }
11114
+ return result;
11115
+ }
11116
+ /**
11117
+ * Encode text to character codes.
11118
+ *
11119
+ * Returns Unicode code points, which is intuitive for users.
11120
+ * The conversion to glyph IDs happens internally when writing to the PDF.
11121
+ *
11122
+ * Also tracks glyph usage for subsetting.
11123
+ */
11124
+ encodeText(text) {
11125
+ return this.trackAndEncode(text).map((e) => e.codePoint);
11126
+ }
11127
+ /**
11128
+ * Encode text to glyph IDs for PDF content stream.
11129
+ *
11130
+ * This is an internal method used when writing to the PDF.
11131
+ * With CIDToGIDMap /Identity, the content stream must contain GIDs.
11132
+ *
11133
+ * @internal
11134
+ */
11135
+ encodeTextToGids(text) {
11136
+ return this.trackAndEncode(text).map((e) => e.gid);
11137
+ }
11138
+ /**
11139
+ * Convert a code point to its glyph ID.
11140
+ *
11141
+ * @internal
11142
+ */
11143
+ codePointToGid(codePoint) {
11144
+ return this.fontProgram.getGlyphId(codePoint);
11145
+ }
11146
+ /**
11147
+ * Get width of a character in glyph units (1000 = 1 em).
11148
+ *
11149
+ * Takes a Unicode code point (user-friendly API).
11150
+ */
11151
+ getWidth(code) {
11152
+ const gid = this.fontProgram.getGlyphId(code);
11153
+ const width = this.fontProgram.getAdvanceWidth(gid);
11154
+ return Math.round(width * 1e3 / this.fontProgram.unitsPerEm);
11155
+ }
11156
+ /**
11157
+ * Decode character code to Unicode string.
11158
+ *
11159
+ * For embedded fonts with Identity-H encoding, the code is the code point,
11160
+ * so this just converts the code point back to a string.
11161
+ */
11162
+ toUnicode(code) {
11163
+ return String.fromCodePoint(code);
11164
+ }
11165
+ /**
11166
+ * Check if the font can encode the given text.
11167
+ * Returns true if all characters have glyphs in the font.
11168
+ */
11169
+ canEncode(text) {
11170
+ for (const char of text) {
11171
+ const codePoint = char.codePointAt(0);
11172
+ if (codePoint === void 0) continue;
11173
+ if (!this.fontProgram.hasGlyph(codePoint)) return false;
11174
+ }
11175
+ return true;
11176
+ }
11177
+ /**
11178
+ * Get the characters that cannot be encoded.
11179
+ */
11180
+ getUnencodableCharacters(text) {
11181
+ const unencodable = [];
11182
+ for (const char of text) {
11183
+ const codePoint = char.codePointAt(0);
11184
+ if (codePoint === void 0) continue;
11185
+ if (!this.fontProgram.hasGlyph(codePoint)) unencodable.push(char);
11186
+ }
11187
+ return unencodable;
11188
+ }
11189
+ /**
11190
+ * Reset glyph usage tracking.
11191
+ * Call this before re-encoding if you want a fresh subset.
11192
+ */
11193
+ resetUsage() {
11194
+ this.usedGlyphs.clear();
11195
+ this.usedGlyphs.set(0, /* @__PURE__ */ new Set());
11196
+ this.usedCodePoints.clear();
11197
+ this._subsetTag = null;
11198
+ }
11199
+ /**
11200
+ * Mark this font as used in a form field.
11201
+ *
11202
+ * Fonts used in form fields cannot be subsetted because users may type
11203
+ * any character at runtime. This method is called automatically when
11204
+ * an EmbeddedFont is used in form field appearances.
11205
+ */
11206
+ markUsedInForm() {
11207
+ this._usedInForm = true;
11208
+ }
11209
+ /**
11210
+ * Check if this font is used in a form field.
11211
+ */
11212
+ get usedInForm() {
11213
+ return this._usedInForm;
11214
+ }
11215
+ /**
11216
+ * Check if this font can be subsetted.
11217
+ *
11218
+ * Returns false if the font is used in a form field (since users can
11219
+ * type any character at runtime).
11220
+ */
11221
+ canSubset() {
11222
+ return !this._usedInForm;
11223
+ }
11224
+ /**
11225
+ * Get width of text in points at a given font size.
11226
+ *
11227
+ * Alias for getTextWidth() to match Standard14Font API.
11228
+ *
11229
+ * @param text - The text to measure
11230
+ * @param size - Font size in points
11231
+ * @returns Width in points
11232
+ */
11233
+ widthOfTextAtSize(text, size) {
11234
+ return this.getTextWidth(text, size);
11235
+ }
11236
+ /**
11237
+ * Get the height of the font at a given size.
11238
+ *
11239
+ * This returns the full height from descender to ascender.
11240
+ *
11241
+ * @param size - Font size in points
11242
+ * @returns Height in points
11243
+ */
11244
+ heightAtSize(size) {
11245
+ const desc = this.descriptor;
11246
+ if (!desc) return size;
11247
+ return (desc.ascent - desc.descent) * size / 1e3;
11248
+ }
11249
+ /**
11250
+ * Calculate font size needed to achieve a specific text height.
11251
+ *
11252
+ * @param height - Desired height in points
11253
+ * @returns Font size in points
11254
+ */
11255
+ sizeAtHeight(height) {
11256
+ const desc = this.descriptor;
11257
+ if (!desc) return height;
11258
+ const unitsHeight = desc.ascent - desc.descent;
11259
+ return height * 1e3 / unitsHeight;
11260
+ }
11261
+ /**
11262
+ * Calculate font size needed for text to fit a specific width.
11263
+ *
11264
+ * @param text - The text to measure
11265
+ * @param width - Desired width in points
11266
+ * @returns Font size in points
11267
+ */
11268
+ sizeAtWidth(text, width) {
11269
+ if (text.length === 0) return 0;
11270
+ const codes = this.encodeText(text);
11271
+ let totalWidth = 0;
11272
+ for (const code of codes) totalWidth += this.getWidth(code);
11273
+ if (totalWidth === 0) return 0;
11274
+ return width * 1e3 / totalWidth;
11275
+ }
11276
+ /**
11277
+ * Build a FontDescriptor from the font program.
11278
+ */
11279
+ buildDescriptor() {
11280
+ const program = this.fontProgram;
11281
+ const bbox = program.bbox;
11282
+ const scale = 1e3 / program.unitsPerEm;
11283
+ return new FontDescriptor({
11284
+ fontName: program.postScriptName ?? "Unknown",
11285
+ flags: this.computeFlags(),
11286
+ fontBBox: [
11287
+ Math.round(bbox[0] * scale),
11288
+ Math.round(bbox[1] * scale),
11289
+ Math.round(bbox[2] * scale),
11290
+ Math.round(bbox[3] * scale)
11291
+ ],
11292
+ italicAngle: program.italicAngle,
11293
+ ascent: Math.round(program.ascent * scale),
11294
+ descent: Math.round(program.descent * scale),
11295
+ leading: 0,
11296
+ capHeight: Math.round(program.capHeight * scale),
11297
+ xHeight: Math.round(program.xHeight * scale),
11298
+ stemV: program.stemV,
11299
+ stemH: 0,
11300
+ avgWidth: 0,
11301
+ maxWidth: 0,
11302
+ missingWidth: this.getWidth(0)
11303
+ });
11304
+ }
11305
+ /**
11306
+ * Compute font flags for the descriptor.
11307
+ */
11308
+ computeFlags() {
11309
+ let flags = 0;
11310
+ if (this.fontProgram.isFixedPitch) flags |= 1;
11311
+ flags |= 4;
11312
+ if (this.fontProgram.italicAngle !== 0) flags |= 64;
11313
+ return flags;
11314
+ }
11315
+ };
11316
+
11317
+ //#endregion
11318
+ //#region src/helpers/unicode.ts
11319
+ /**
11320
+ * Unicode utilities for PDF text handling.
11321
+ *
11322
+ * Provides mappings between Unicode code points and PostScript glyph names.
11323
+ */
11324
+ /**
11325
+ * Map Unicode code point to PostScript glyph name.
11326
+ * Returns undefined if no mapping exists.
11327
+ */
11328
+ function unicodeToGlyphName(unicode) {
11329
+ return UNICODE_TO_GLYPH.get(unicode);
11330
+ }
11331
+ /**
11332
+ * Common Unicode to glyph name mappings.
11333
+ * Covers ASCII and common Latin-1 extended characters.
11334
+ *
11335
+ * For a complete mapping, see the Adobe Glyph List:
11336
+ * https://github.com/adobe-type-tools/agl-aglfn
11337
+ */
11338
+ const UNICODE_TO_GLYPH = new Map([
11339
+ [32, "space"],
11340
+ [33, "exclam"],
11341
+ [34, "quotedbl"],
11342
+ [35, "numbersign"],
11343
+ [36, "dollar"],
11344
+ [37, "percent"],
11345
+ [38, "ampersand"],
11346
+ [39, "quotesingle"],
11347
+ [40, "parenleft"],
11348
+ [41, "parenright"],
11349
+ [42, "asterisk"],
11350
+ [43, "plus"],
11351
+ [44, "comma"],
11352
+ [45, "hyphen"],
11353
+ [46, "period"],
11354
+ [47, "slash"],
11355
+ [48, "zero"],
11356
+ [49, "one"],
11357
+ [50, "two"],
11358
+ [51, "three"],
11359
+ [52, "four"],
11360
+ [53, "five"],
11361
+ [54, "six"],
11362
+ [55, "seven"],
11363
+ [56, "eight"],
11364
+ [57, "nine"],
11365
+ [58, "colon"],
11366
+ [59, "semicolon"],
11367
+ [60, "less"],
11368
+ [61, "equal"],
11369
+ [62, "greater"],
11370
+ [63, "question"],
11371
+ [64, "at"],
11372
+ [65, "A"],
11373
+ [66, "B"],
11374
+ [67, "C"],
11375
+ [68, "D"],
11376
+ [69, "E"],
11377
+ [70, "F"],
11378
+ [71, "G"],
11379
+ [72, "H"],
11380
+ [73, "I"],
11381
+ [74, "J"],
11382
+ [75, "K"],
11383
+ [76, "L"],
11384
+ [77, "M"],
11385
+ [78, "N"],
11386
+ [79, "O"],
11387
+ [80, "P"],
11388
+ [81, "Q"],
11389
+ [82, "R"],
11390
+ [83, "S"],
11391
+ [84, "T"],
11392
+ [85, "U"],
11393
+ [86, "V"],
11394
+ [87, "W"],
11395
+ [88, "X"],
11396
+ [89, "Y"],
11397
+ [90, "Z"],
11398
+ [91, "bracketleft"],
11399
+ [92, "backslash"],
11400
+ [93, "bracketright"],
11401
+ [94, "asciicircum"],
11402
+ [95, "underscore"],
11403
+ [96, "grave"],
11404
+ [97, "a"],
11405
+ [98, "b"],
11406
+ [99, "c"],
11407
+ [100, "d"],
11408
+ [101, "e"],
11409
+ [102, "f"],
11410
+ [103, "g"],
11411
+ [104, "h"],
11412
+ [105, "i"],
11413
+ [106, "j"],
11414
+ [107, "k"],
11415
+ [108, "l"],
11416
+ [109, "m"],
11417
+ [110, "n"],
11418
+ [111, "o"],
11419
+ [112, "p"],
11420
+ [113, "q"],
11421
+ [114, "r"],
11422
+ [115, "s"],
11423
+ [116, "t"],
11424
+ [117, "u"],
11425
+ [118, "v"],
11426
+ [119, "w"],
11427
+ [120, "x"],
11428
+ [121, "y"],
11429
+ [122, "z"],
11430
+ [123, "braceleft"],
11431
+ [124, "bar"],
11432
+ [125, "braceright"],
11433
+ [126, "asciitilde"],
11434
+ [160, "nbspace"],
11435
+ [161, "exclamdown"],
11436
+ [162, "cent"],
11437
+ [163, "sterling"],
11438
+ [164, "currency"],
11439
+ [165, "yen"],
11440
+ [166, "brokenbar"],
11441
+ [167, "section"],
11442
+ [168, "dieresis"],
11443
+ [169, "copyright"],
11444
+ [170, "ordfeminine"],
11445
+ [171, "guillemotleft"],
11446
+ [172, "logicalnot"],
11447
+ [173, "softhyphen"],
11448
+ [174, "registered"],
11449
+ [175, "macron"],
11450
+ [176, "degree"],
11451
+ [177, "plusminus"],
11452
+ [178, "twosuperior"],
11453
+ [179, "threesuperior"],
11454
+ [180, "acute"],
11455
+ [181, "mu"],
11456
+ [182, "paragraph"],
11457
+ [183, "periodcentered"],
11458
+ [184, "cedilla"],
11459
+ [185, "onesuperior"],
11460
+ [186, "ordmasculine"],
11461
+ [187, "guillemotright"],
11462
+ [188, "onequarter"],
11463
+ [189, "onehalf"],
11464
+ [190, "threequarters"],
11465
+ [191, "questiondown"],
11466
+ [192, "Agrave"],
11467
+ [193, "Aacute"],
11468
+ [194, "Acircumflex"],
11469
+ [195, "Atilde"],
11470
+ [196, "Adieresis"],
11471
+ [197, "Aring"],
11472
+ [198, "AE"],
11473
+ [199, "Ccedilla"],
11474
+ [200, "Egrave"],
11475
+ [201, "Eacute"],
11476
+ [202, "Ecircumflex"],
11477
+ [203, "Edieresis"],
11478
+ [204, "Igrave"],
11479
+ [205, "Iacute"],
11480
+ [206, "Icircumflex"],
11481
+ [207, "Idieresis"],
11482
+ [208, "Eth"],
11483
+ [209, "Ntilde"],
11484
+ [210, "Ograve"],
11485
+ [211, "Oacute"],
11486
+ [212, "Ocircumflex"],
11487
+ [213, "Otilde"],
11488
+ [214, "Odieresis"],
11489
+ [215, "multiply"],
11490
+ [216, "Oslash"],
11491
+ [217, "Ugrave"],
11492
+ [218, "Uacute"],
11493
+ [219, "Ucircumflex"],
11494
+ [220, "Udieresis"],
11495
+ [221, "Yacute"],
11496
+ [222, "Thorn"],
11497
+ [223, "germandbls"],
11498
+ [224, "agrave"],
11499
+ [225, "aacute"],
11500
+ [226, "acircumflex"],
11501
+ [227, "atilde"],
11502
+ [228, "adieresis"],
11503
+ [229, "aring"],
11504
+ [230, "ae"],
11505
+ [231, "ccedilla"],
11506
+ [232, "egrave"],
11507
+ [233, "eacute"],
11508
+ [234, "ecircumflex"],
11509
+ [235, "edieresis"],
11510
+ [236, "igrave"],
11511
+ [237, "iacute"],
11512
+ [238, "icircumflex"],
11513
+ [239, "idieresis"],
11514
+ [240, "eth"],
11515
+ [241, "ntilde"],
11516
+ [242, "ograve"],
11517
+ [243, "oacute"],
11518
+ [244, "ocircumflex"],
11519
+ [245, "otilde"],
11520
+ [246, "odieresis"],
11521
+ [247, "divide"],
11522
+ [248, "oslash"],
11523
+ [249, "ugrave"],
11524
+ [250, "uacute"],
11525
+ [251, "ucircumflex"],
11526
+ [252, "udieresis"],
11527
+ [253, "yacute"],
11528
+ [254, "thorn"],
11529
+ [255, "ydieresis"],
11530
+ [8211, "endash"],
11531
+ [8212, "emdash"],
11532
+ [8216, "quoteleft"],
11533
+ [8217, "quoteright"],
11534
+ [8218, "quotesinglbase"],
11535
+ [8220, "quotedblleft"],
11536
+ [8221, "quotedblright"],
11537
+ [8222, "quotedblbase"],
11538
+ [8224, "dagger"],
11539
+ [8225, "daggerdbl"],
11540
+ [8226, "bullet"],
11541
+ [8230, "ellipsis"],
11542
+ [8240, "perthousand"],
11543
+ [8249, "guilsinglleft"],
11544
+ [8250, "guilsinglright"],
11545
+ [8364, "Euro"],
11546
+ [8482, "trademark"],
11547
+ [64257, "fi"],
11548
+ [64258, "fl"]
11549
+ ]);
11550
+
11074
11551
  //#endregion
11075
11552
  //#region src/fonts/encodings/glyph-list.ts
11076
11553
  /**
@@ -13310,147 +13787,6 @@ var ZapfDingbatsEncoding = class ZapfDingbatsEncoding extends SimpleEncoding {
13310
13787
  }
13311
13788
  };
13312
13789
 
13313
- //#endregion
13314
- //#region src/fonts/font-descriptor.ts
13315
- /**
13316
- * Font flags as defined in PDF spec Table 123.
13317
- */
13318
- const FontFlags = {
13319
- FIXED_PITCH: 1,
13320
- SERIF: 2,
13321
- SYMBOLIC: 4,
13322
- SCRIPT: 8,
13323
- NONSYMBOLIC: 32,
13324
- ITALIC: 64,
13325
- ALL_CAP: 65536,
13326
- SMALL_CAP: 1 << 17,
13327
- FORCE_BOLD: 1 << 18
13328
- };
13329
- /**
13330
- * FontDescriptor contains font metrics and flags.
13331
- */
13332
- var FontDescriptor = class FontDescriptor {
13333
- fontName;
13334
- flags;
13335
- fontBBox;
13336
- italicAngle;
13337
- ascent;
13338
- descent;
13339
- leading;
13340
- capHeight;
13341
- xHeight;
13342
- stemV;
13343
- stemH;
13344
- avgWidth;
13345
- maxWidth;
13346
- missingWidth;
13347
- constructor(data) {
13348
- this.fontName = data.fontName;
13349
- this.flags = data.flags;
13350
- this.fontBBox = data.fontBBox;
13351
- this.italicAngle = data.italicAngle;
13352
- this.ascent = data.ascent;
13353
- this.descent = data.descent;
13354
- this.leading = data.leading;
13355
- this.capHeight = data.capHeight;
13356
- this.xHeight = data.xHeight;
13357
- this.stemV = data.stemV;
13358
- this.stemH = data.stemH;
13359
- this.avgWidth = data.avgWidth;
13360
- this.maxWidth = data.maxWidth;
13361
- this.missingWidth = data.missingWidth;
13362
- }
13363
- /** Check if font is fixed-pitch (monospace) */
13364
- get isFixedPitch() {
13365
- return (this.flags & FontFlags.FIXED_PITCH) !== 0;
13366
- }
13367
- /** Check if font is serif */
13368
- get isSerif() {
13369
- return (this.flags & FontFlags.SERIF) !== 0;
13370
- }
13371
- /** Check if font is symbolic (uses custom encoding) */
13372
- get isSymbolic() {
13373
- return (this.flags & FontFlags.SYMBOLIC) !== 0;
13374
- }
13375
- /** Check if font is script (cursive) */
13376
- get isScript() {
13377
- return (this.flags & FontFlags.SCRIPT) !== 0;
13378
- }
13379
- /** Check if font is non-symbolic (uses standard encoding) */
13380
- get isNonSymbolic() {
13381
- return (this.flags & FontFlags.NONSYMBOLIC) !== 0;
13382
- }
13383
- /** Check if font is italic */
13384
- get isItalic() {
13385
- return (this.flags & FontFlags.ITALIC) !== 0;
13386
- }
13387
- /** Check if font is all caps */
13388
- get isAllCap() {
13389
- return (this.flags & FontFlags.ALL_CAP) !== 0;
13390
- }
13391
- /** Check if font is small caps */
13392
- get isSmallCap() {
13393
- return (this.flags & FontFlags.SMALL_CAP) !== 0;
13394
- }
13395
- /** Check if font should be bold */
13396
- get isForceBold() {
13397
- return (this.flags & FontFlags.FORCE_BOLD) !== 0;
13398
- }
13399
- /**
13400
- * Parse FontDescriptor from a PDF dictionary.
13401
- */
13402
- static parse(dict) {
13403
- const bboxArray = dict.getArray("FontBBox");
13404
- const fontBBox = [
13405
- 0,
13406
- 0,
13407
- 0,
13408
- 0
13409
- ];
13410
- if (bboxArray && bboxArray.length >= 4) for (let i = 0; i < 4; i++) {
13411
- const item = bboxArray.at(i);
13412
- if (item && item.type === "number") fontBBox[i] = item.value;
13413
- }
13414
- return new FontDescriptor({
13415
- fontName: dict.getName("FontName")?.value ?? "",
13416
- flags: dict.getNumber("Flags")?.value ?? 0,
13417
- fontBBox,
13418
- italicAngle: dict.getNumber("ItalicAngle")?.value ?? 0,
13419
- ascent: dict.getNumber("Ascent")?.value ?? 0,
13420
- descent: dict.getNumber("Descent")?.value ?? 0,
13421
- leading: dict.getNumber("Leading")?.value ?? 0,
13422
- capHeight: dict.getNumber("CapHeight")?.value ?? 0,
13423
- xHeight: dict.getNumber("XHeight")?.value ?? 0,
13424
- stemV: dict.getNumber("StemV")?.value ?? 0,
13425
- stemH: dict.getNumber("StemH")?.value ?? 0,
13426
- avgWidth: dict.getNumber("AvgWidth")?.value ?? 0,
13427
- maxWidth: dict.getNumber("MaxWidth")?.value ?? 0,
13428
- missingWidth: dict.getNumber("MissingWidth")?.value ?? 0
13429
- });
13430
- }
13431
- };
13432
-
13433
- //#endregion
13434
- //#region src/fonts/pdf-font.ts
13435
- /**
13436
- * Abstract base class for PDF fonts.
13437
- */
13438
- var PdfFont = class {
13439
- /**
13440
- * Get width of text in points at a given font size.
13441
- *
13442
- * @param text - Unicode text to measure
13443
- * @param fontSize - Font size in points
13444
- * @returns Width in points
13445
- */
13446
- getTextWidth(text, fontSize) {
13447
- let totalWidth = 0;
13448
- const codes = this.encodeText(text);
13449
- for (const code of codes) totalWidth += this.getWidth(code);
13450
- return totalWidth * fontSize / 1e3;
13451
- }
13452
- };
13453
-
13454
13790
  //#endregion
13455
13791
  //#region src/fonts/standard-14.ts
13456
13792
  /**
@@ -16689,25 +17025,6 @@ const FONT_GLYPH_WIDTHS = {
16689
17025
 
16690
17026
  //#endregion
16691
17027
  //#region src/fonts/simple-font.ts
16692
- /**
16693
- * SimpleFont - Base class for single-byte encoded fonts.
16694
- *
16695
- * This handles TrueType, Type1, and Type3 fonts which use single-byte
16696
- * character codes (0-255).
16697
- *
16698
- * Font structure:
16699
- * <<
16700
- * /Type /Font
16701
- * /Subtype /TrueType (or /Type1, /Type3)
16702
- * /BaseFont /Helvetica
16703
- * /FirstChar 32
16704
- * /LastChar 255
16705
- * /Widths [278 278 355 ...]
16706
- * /Encoding /WinAnsiEncoding (or dict with /Differences)
16707
- * /FontDescriptor 10 0 R
16708
- * /ToUnicode 11 0 R
16709
- * >>
16710
- */
16711
17028
  const isSimpleFontSubtype = (subtype) => {
16712
17029
  return subtype === "TrueType" || subtype === "Type1" || subtype === "Type3" || subtype === "MMType1";
16713
17030
  };
@@ -16844,34 +17161,25 @@ var SimpleFont = class extends PdfFont {
16844
17161
  * Parse a SimpleFont from a PDF font dictionary.
16845
17162
  */
16846
17163
  function parseSimpleFont(dict, options = {}) {
16847
- const subtypeName = dict.getName("Subtype");
17164
+ const subtypeName = dict.getName("Subtype", options.resolver);
16848
17165
  const subtype = isSimpleFontSubtype(subtypeName?.value) ? subtypeName.value : "TrueType";
16849
- const baseFontName = dict.getName("BaseFont")?.value ?? "Unknown";
16850
- const firstChar = dict.getNumber("FirstChar")?.value ?? 0;
16851
- const lastChar = dict.getNumber("LastChar")?.value ?? 255;
16852
- let w = dict.get("Widths");
16853
- let widthsArray = null;
16854
- if (w instanceof PdfRef && options.resolveRef) w = options.resolveRef(w) ?? void 0;
16855
- if (w instanceof PdfArray) widthsArray = w;
17166
+ const baseFontName = dict.getName("BaseFont", options.resolver)?.value ?? "Unknown";
17167
+ const firstChar = dict.getNumber("FirstChar", options.resolver)?.value ?? 0;
17168
+ const lastChar = dict.getNumber("LastChar", options.resolver)?.value ?? 255;
17169
+ let widthsArray = dict.getArray("Widths", options.resolver);
16856
17170
  const widths = [];
16857
17171
  if (widthsArray) for (let i = 0; i < widthsArray.length; i++) {
16858
- const item = widthsArray.at(i);
17172
+ const item = widthsArray.at(i, options.resolver);
16859
17173
  if (item instanceof PdfNumber) widths.push(item.value);
16860
17174
  else widths.push(0);
16861
17175
  }
16862
- const encoding = parseEncoding(dict, options.resolveRef);
17176
+ const encoding = parseEncoding(dict, options.resolver);
16863
17177
  let descriptor = null;
16864
17178
  let embeddedProgram = null;
16865
- const descriptorRef = dict.get("FontDescriptor");
16866
- if (descriptorRef && options.resolveRef) {
16867
- const descriptorDict = options.resolveRef(descriptorRef);
16868
- if (descriptorDict && "getString" in descriptorDict) {
16869
- descriptor = FontDescriptor.parse(descriptorDict);
16870
- if (options.decodeStream) embeddedProgram = parseEmbeddedProgram(descriptorDict, {
16871
- decodeStream: options.decodeStream,
16872
- resolveRef: options.resolveRef
16873
- });
16874
- }
17179
+ const fontDescriptor = dict.getDict("FontDescriptor", options.resolver);
17180
+ if (fontDescriptor) {
17181
+ descriptor = FontDescriptor.parse(fontDescriptor);
17182
+ embeddedProgram = parseEmbeddedProgram(fontDescriptor, { resolver: options.resolver });
16875
17183
  }
16876
17184
  return new SimpleFont({
16877
17185
  subtype,
@@ -16888,36 +17196,31 @@ function parseSimpleFont(dict, options = {}) {
16888
17196
  /**
16889
17197
  * Parse encoding from font dictionary.
16890
17198
  */
16891
- function parseEncoding(dict, resolveRef) {
16892
- const encodingValue = dict.get("Encoding");
17199
+ function parseEncoding(dict, resolver) {
17200
+ const encodingValue = dict.get("Encoding", resolver);
16893
17201
  if (!encodingValue) {
16894
- const baseFontName = dict.getName("BaseFont")?.value ?? "";
17202
+ const baseFontName = dict.getName("BaseFont", resolver)?.value ?? "";
16895
17203
  if (baseFontName === "Symbol") return SymbolEncoding.instance;
16896
17204
  if (baseFontName === "ZapfDingbats") return ZapfDingbatsEncoding.instance;
16897
17205
  return StandardEncoding.instance;
16898
17206
  }
16899
- if (encodingValue.type === "name") return getEncodingByName(encodingValue.value);
16900
- if (encodingValue.type === "dict") return parseEncodingDict(encodingValue);
16901
- if (encodingValue.type === "ref" && resolveRef) {
16902
- const resolved = resolveRef(encodingValue);
16903
- if (resolved && resolved.type === "dict") return parseEncodingDict(resolved);
16904
- }
17207
+ if (encodingValue instanceof PdfName) return getEncodingByName(encodingValue.value);
17208
+ if (encodingValue instanceof PdfDict) return parseEncodingDict(encodingValue, resolver);
16905
17209
  return WinAnsiEncoding.instance;
16906
17210
  }
16907
17211
  /**
16908
17212
  * Parse encoding dictionary.
16909
17213
  */
16910
- function parseEncodingDict(dict) {
16911
- const baseEncodingName = dict.getName("BaseEncoding");
17214
+ function parseEncodingDict(dict, resolver) {
17215
+ const baseEncodingName = dict.getName("BaseEncoding", resolver);
16912
17216
  const baseEncoding = baseEncodingName ? getEncodingByName(baseEncodingName.value) : WinAnsiEncoding.instance;
16913
- const differencesArray = dict.getArray("Differences");
17217
+ const differencesArray = dict.getArray("Differences", resolver);
16914
17218
  if (!differencesArray || differencesArray.length === 0) return baseEncoding;
16915
17219
  const items = [];
16916
17220
  for (let i = 0; i < differencesArray.length; i++) {
16917
17221
  const item = differencesArray.at(i);
16918
17222
  if (item) {
16919
- if (item.type === "number") items.push(item.value);
16920
- else if (item.type === "name") items.push(item.value);
17223
+ if (item instanceof PdfNumber || item instanceof PdfName) items.push(item.value);
16921
17224
  }
16922
17225
  }
16923
17226
  return new DifferencesEncoding(baseEncoding, DifferencesEncoding.parseDifferencesArray(items));
@@ -16939,6 +17242,15 @@ function getEncodingByName(name) {
16939
17242
  //#endregion
16940
17243
  //#region src/document/forms/form-font.ts
16941
17244
  /**
17245
+ * Form font types for use in form fields.
17246
+ *
17247
+ * Supports two font types:
17248
+ * - EmbeddedFont: Full font with metrics and subsetting
17249
+ * - ExistingFont: Lightweight wrapper for fonts already in the PDF
17250
+ *
17251
+ * PDF Reference: Section 12.7.3.3 "Variable Text"
17252
+ */
17253
+ /**
16942
17254
  * Existing font from PDF's default resources.
16943
17255
  *
16944
17256
  * This is a lightweight wrapper for fonts already present in the PDF,
@@ -17062,18 +17374,11 @@ function mapToStandardFont(name) {
17062
17374
  function parseExistingFont(name, fontObj, registry) {
17063
17375
  let ref = null;
17064
17376
  let simpleFont = null;
17065
- if (fontObj?.type === "ref") {
17377
+ if (fontObj instanceof PdfRef) {
17066
17378
  ref = fontObj;
17067
17379
  const resolved = registry.getObject(fontObj);
17068
- if (resolved?.type === "dict") try {
17069
- const resolveRef = (r) => {
17070
- if (r instanceof PdfRef) {
17071
- const obj = registry.getObject(r);
17072
- if (obj instanceof PdfDict || obj instanceof PdfArray || obj instanceof PdfStream) return obj;
17073
- }
17074
- return null;
17075
- };
17076
- simpleFont = parseSimpleFont(resolved, { resolveRef });
17380
+ if (resolved instanceof PdfDict) try {
17381
+ simpleFont = parseSimpleFont(resolved, { resolver: registry.resolve.bind(registry) });
17077
17382
  } catch (err) {
17078
17383
  console.warn(err);
17079
17384
  }
@@ -17084,7 +17389,7 @@ function parseExistingFont(name, fontObj, registry) {
17084
17389
  * Check if a font is an EmbeddedFont.
17085
17390
  */
17086
17391
  function isEmbeddedFont(font) {
17087
- return "encodeText" in font && "getUsedGlyphIds" in font;
17392
+ return font instanceof EmbeddedFont;
17088
17393
  }
17089
17394
  /**
17090
17395
  * Check if a font is an ExistingFont.
@@ -18342,11 +18647,11 @@ var WidgetAnnotation = class {
18342
18647
  getOnValue() {
18343
18648
  const ap = this.dict.getDict("AP");
18344
18649
  if (!ap) return null;
18345
- const n = ap.get("N");
18650
+ const resolve = this.registry.resolve.bind(this.registry);
18651
+ const n = ap.get("N", resolve);
18346
18652
  if (!n) return null;
18347
- const nResolved = n.type === "ref" ? this.registry.getObject(n) : n;
18348
- if (nResolved instanceof PdfDict && !(nResolved instanceof PdfStream)) {
18349
- for (const key$1 of nResolved.keys()) if (key$1.value !== "Off") return key$1.value;
18653
+ if (n instanceof PdfDict && !(n instanceof PdfStream)) {
18654
+ for (const key$1 of n.keys()) if (key$1.value !== "Off") return key$1.value;
18350
18655
  }
18351
18656
  return null;
18352
18657
  }
@@ -18359,11 +18664,11 @@ var WidgetAnnotation = class {
18359
18664
  hasAppearancesForStates(states) {
18360
18665
  const ap = this.dict.getDict("AP");
18361
18666
  if (!ap) return false;
18362
- const n = ap.get("N");
18667
+ const resolve = this.registry.resolve.bind(this.registry);
18668
+ const n = ap.get("N", resolve);
18363
18669
  if (!n) return false;
18364
- const nResolved = n.type === "ref" ? this.registry.getObject(n) : n;
18365
- if (nResolved instanceof PdfDict && !(nResolved instanceof PdfStream)) {
18366
- for (const state of states) if (!nResolved.has(state)) return false;
18670
+ if (n instanceof PdfDict && !(n instanceof PdfStream)) {
18671
+ for (const state of states) if (!n.has(state)) return false;
18367
18672
  return true;
18368
18673
  }
18369
18674
  return states.length === 0;
@@ -18384,15 +18689,13 @@ var WidgetAnnotation = class {
18384
18689
  getNormalAppearance(state) {
18385
18690
  const ap = this.dict.getDict("AP");
18386
18691
  if (!ap) return null;
18387
- let n = ap.get("N");
18692
+ const resolve = this.registry.resolve.bind(this.registry);
18693
+ const n = ap.get("N", resolve);
18388
18694
  if (!n) return null;
18389
- if (n instanceof PdfRef) n = this.registry.resolve(n) ?? void 0;
18390
18695
  if (n instanceof PdfStream) return n;
18391
18696
  if (n instanceof PdfDict) {
18392
18697
  const stateKey = state ?? this.appearanceState ?? "Off";
18393
- let stateEntry = n.get(stateKey);
18394
- if (!stateEntry) return null;
18395
- if (stateEntry instanceof PdfRef) stateEntry = this.registry.resolve(stateEntry) ?? void 0;
18698
+ const stateEntry = n.get(stateKey, resolve);
18396
18699
  if (stateEntry instanceof PdfStream) return stateEntry;
18397
18700
  return null;
18398
18701
  }
@@ -18404,15 +18707,13 @@ var WidgetAnnotation = class {
18404
18707
  getRolloverAppearance(state) {
18405
18708
  const ap = this.dict.getDict("AP");
18406
18709
  if (!ap) return null;
18407
- let r = ap.get("R");
18710
+ const resolve = this.registry.resolve.bind(this.registry);
18711
+ const r = ap.get("R", resolve);
18408
18712
  if (!r) return null;
18409
- if (r instanceof PdfRef) r = this.registry.resolve(r) ?? void 0;
18410
18713
  if (r instanceof PdfStream) return r;
18411
18714
  if (r instanceof PdfDict) {
18412
18715
  const stateKey = state ?? this.appearanceState ?? "Off";
18413
- let stateEntry = r.get(stateKey);
18414
- if (!stateEntry) return null;
18415
- if (stateEntry instanceof PdfRef) stateEntry = this.registry.resolve(stateEntry) ?? void 0;
18716
+ const stateEntry = r.get(stateKey, resolve);
18416
18717
  if (stateEntry instanceof PdfStream) return stateEntry;
18417
18718
  return null;
18418
18719
  }
@@ -18424,15 +18725,13 @@ var WidgetAnnotation = class {
18424
18725
  getDownAppearance(state) {
18425
18726
  const ap = this.dict.getDict("AP");
18426
18727
  if (!ap) return null;
18427
- let d = ap.get("D");
18728
+ const resolve = this.registry.resolve.bind(this.registry);
18729
+ const d = ap.get("D", resolve);
18428
18730
  if (!d) return null;
18429
- if (d instanceof PdfRef) d = this.registry.resolve(d) ?? void 0;
18430
18731
  if (d instanceof PdfStream) return d;
18431
18732
  if (d instanceof PdfDict) {
18432
18733
  const stateKey = state ?? this.appearanceState ?? "Off";
18433
- let stateEntry = d.get(stateKey);
18434
- if (!stateEntry) return null;
18435
- if (stateEntry instanceof PdfRef) stateEntry = this.registry.resolve(stateEntry) ?? void 0;
18734
+ const stateEntry = d.get(stateKey, resolve);
18436
18735
  if (stateEntry instanceof PdfStream) return stateEntry;
18437
18736
  return null;
18438
18737
  }
@@ -18462,14 +18761,8 @@ var WidgetAnnotation = class {
18462
18761
  * Get appearance characteristics (/MK dictionary).
18463
18762
  */
18464
18763
  getAppearanceCharacteristics() {
18465
- const mkEntry = this.dict.get("MK");
18466
- if (!mkEntry) return null;
18467
- let mk = null;
18468
- if (mkEntry instanceof PdfDict) mk = mkEntry;
18469
- else if (mkEntry.type === "ref") {
18470
- const resolved = this.registry.getObject(mkEntry);
18471
- if (resolved instanceof PdfDict) mk = resolved;
18472
- }
18764
+ const resolve = this.registry.resolve.bind(this.registry);
18765
+ const mk = this.dict.getDict("MK", resolve);
18473
18766
  if (!mk) return null;
18474
18767
  return {
18475
18768
  rotation: mk.getNumber("R")?.value ?? 0,
@@ -18608,11 +18901,8 @@ var FormField = class {
18608
18901
  while (current) {
18609
18902
  if (visited.has(current)) break;
18610
18903
  visited.add(current);
18611
- const value = current.get(key$1);
18612
- if (value !== void 0) {
18613
- if (value instanceof PdfRef) return this.registry.getObject(value);
18614
- return value;
18615
- }
18904
+ const value = current.get(key$1, this.registry.resolve.bind(this.registry));
18905
+ if (value !== void 0) return value;
18616
18906
  const parentRef = current.getRef("Parent");
18617
18907
  if (!parentRef) break;
18618
18908
  const obj = this.registry.getObject(parentRef);
@@ -18853,8 +19143,7 @@ var TerminalField = class extends FormField {
18853
19143
  * This ensures getAppearanceCharacteristics() can work synchronously.
18854
19144
  */
18855
19145
  resolveMK(dict) {
18856
- const mkEntry = dict.get("MK");
18857
- if (mkEntry instanceof PdfRef) this.registry.resolve(mkEntry);
19146
+ dict.getDict("MK", this.registry.resolve.bind(this.registry));
18858
19147
  }
18859
19148
  /**
18860
19149
  * Add a widget to this field's /Kids array.
@@ -19204,12 +19493,6 @@ var ListBoxField = class extends TerminalField {
19204
19493
  //#endregion
19205
19494
  //#region src/document/forms/fields/other-fields.ts
19206
19495
  /**
19207
- * Other field types: Signature, Button, and Unknown.
19208
- *
19209
- * PDF Reference: Section 12.7.4.5 "Signature Fields"
19210
- * PDF Reference: Section 12.7.4.2 "Button Fields"
19211
- */
19212
- /**
19213
19496
  * Signature field.
19214
19497
  */
19215
19498
  var SignatureField = class extends TerminalField {
@@ -19224,13 +19507,7 @@ var SignatureField = class extends TerminalField {
19224
19507
  * Get signature dictionary (if signed).
19225
19508
  */
19226
19509
  getSignatureDict() {
19227
- const v = this.dict.get("V");
19228
- if (!v) return null;
19229
- if (v instanceof PdfRef) {
19230
- const resolved = this.registry.getObject(v);
19231
- return resolved instanceof PdfDict ? resolved : null;
19232
- }
19233
- return v instanceof PdfDict ? v : null;
19510
+ return this.dict.getDict("V", this.registry.resolve.bind(this.registry)) ?? null;
19234
19511
  }
19235
19512
  /**
19236
19513
  * Signature fields don't have simple values.
@@ -19316,7 +19593,7 @@ var RadioField = class extends TerminalField {
19316
19593
  * that are different from the widget appearance state names.
19317
19594
  */
19318
19595
  getExportValues() {
19319
- const opt = this.dict.getArray("Opt");
19596
+ const opt = this.dict.getArray("Opt", this.registry.resolve.bind(this.registry));
19320
19597
  if (!opt) return this.getOptions();
19321
19598
  const values = [];
19322
19599
  for (let i = 0; i < opt.length; i++) {
@@ -19435,11 +19712,6 @@ var TextField = class extends TerminalField {
19435
19712
  //#endregion
19436
19713
  //#region src/document/forms/fields/factory.ts
19437
19714
  /**
19438
- * Form field factory function.
19439
- *
19440
- * Creates the appropriate field type based on /FT and /Ff values.
19441
- */
19442
- /**
19443
19715
  * Create a terminal FormField instance based on /FT and /Ff.
19444
19716
  *
19445
19717
  * This factory creates only terminal fields (value-holding fields with widgets).
@@ -19467,15 +19739,15 @@ function createFormField(dict, ref, registry, acroForm, name) {
19467
19739
  function getInheritableFieldName(dict, key$1, registry) {
19468
19740
  let current = dict;
19469
19741
  const visited = /* @__PURE__ */ new Set();
19742
+ const resolve = registry.resolve.bind(registry);
19470
19743
  while (current) {
19471
19744
  if (visited.has(current)) break;
19472
19745
  visited.add(current);
19473
- const value = current.get(key$1);
19474
- if (value instanceof PdfName) return value.value;
19475
- const parentRef = current.getRef("Parent");
19476
- if (!parentRef) break;
19477
- const obj = registry.getObject(parentRef);
19478
- current = obj instanceof PdfDict ? obj : null;
19746
+ const value = current.getName(key$1, resolve);
19747
+ if (value) return value.value;
19748
+ const parent = current.getDict("Parent", resolve);
19749
+ if (!parent) break;
19750
+ current = parent;
19479
19751
  }
19480
19752
  return null;
19481
19753
  }
@@ -19485,15 +19757,15 @@ function getInheritableFieldName(dict, key$1, registry) {
19485
19757
  function getInheritableFieldNumber(dict, key$1, registry) {
19486
19758
  let current = dict;
19487
19759
  const visited = /* @__PURE__ */ new Set();
19760
+ const resolve = registry.resolve.bind(registry);
19488
19761
  while (current) {
19489
19762
  if (visited.has(current)) break;
19490
19763
  visited.add(current);
19491
- const value = current.get(key$1);
19492
- if (value instanceof PdfNumber) return value.value;
19493
- const parentRef = current.getRef("Parent");
19494
- if (!parentRef) break;
19495
- const obj = registry.getObject(parentRef);
19496
- current = obj instanceof PdfDict ? obj : null;
19764
+ const value = current.getNumber(key$1, resolve);
19765
+ if (value) return value.value;
19766
+ const parent = current.getDict("Parent", resolve);
19767
+ if (!parent) break;
19768
+ current = parent;
19497
19769
  }
19498
19770
  return 0;
19499
19771
  }
@@ -19548,7 +19820,9 @@ var FieldTree = class FieldTree {
19548
19820
  * @returns A fully-loaded FieldTree
19549
19821
  */
19550
19822
  static load(acroForm, registry) {
19551
- const fieldsArray = acroForm.getDict().getArray("Fields");
19823
+ const dict = acroForm.getDict();
19824
+ const resolve = registry.resolve.bind(registry);
19825
+ const fieldsArray = dict.getArray("Fields", resolve);
19552
19826
  if (!fieldsArray) return new FieldTree([]);
19553
19827
  const visited = /* @__PURE__ */ new Set();
19554
19828
  const fields = [];
@@ -19574,7 +19848,7 @@ var FieldTree = class FieldTree {
19574
19848
  if (item instanceof PdfRef) item = registry.resolve(item) ?? void 0;
19575
19849
  if (item instanceof PdfDict) fieldDict = item;
19576
19850
  if (!fieldDict) continue;
19577
- const partialName = fieldDict.getString("T")?.asString() ?? "";
19851
+ const partialName = fieldDict.getString("T", resolve)?.asString() ?? "";
19578
19852
  const fullName = parentName ? partialName ? `${parentName}.${partialName}` : parentName : partialName;
19579
19853
  if (checkIsTerminalField(fieldDict, registry)) {
19580
19854
  const field = createFormField(fieldDict, ref, registry, acroForm, fullName);
@@ -19587,7 +19861,7 @@ var FieldTree = class FieldTree {
19587
19861
  nonTerminal.parent = parent;
19588
19862
  fields.push(nonTerminal);
19589
19863
  if (parent instanceof NonTerminalField) parent.addChild(nonTerminal);
19590
- const kids = fieldDict.getArray("Kids");
19864
+ const kids = fieldDict.getArray("Kids", resolve);
19591
19865
  if (kids) for (let i = 0; i < kids.length; i++) queue.push({
19592
19866
  item: kids.at(i),
19593
19867
  parentName: fullName,
@@ -19657,7 +19931,8 @@ var FieldTree = class FieldTree {
19657
19931
  * - Its /Kids contain widgets (no /T) rather than child fields (have /T)
19658
19932
  */
19659
19933
  function checkIsTerminalField(dict, registry) {
19660
- const kids = dict.getArray("Kids");
19934
+ const resolve = registry.resolve.bind(registry);
19935
+ const kids = dict.getArray("Kids", resolve);
19661
19936
  if (!kids || kids.length === 0) return true;
19662
19937
  let firstKid = kids.at(0);
19663
19938
  if (!firstKid) return true;
@@ -19767,7 +20042,7 @@ var FormFlattener = class {
19767
20042
  for (const pageRef of pageRefs) {
19768
20043
  const pageDict = this.registry.resolve(pageRef);
19769
20044
  if (!(pageDict instanceof PdfDict)) continue;
19770
- const annots = pageDict.getArray("Annots");
20045
+ const annots = pageDict.getArray("Annots", this.registry.resolve.bind(this.registry));
19771
20046
  if (!annots) continue;
19772
20047
  for (let i = 0; i < annots.length; i++) {
19773
20048
  const annotRef = annots.at(i);
@@ -19788,12 +20063,13 @@ var FormFlattener = class {
19788
20063
  flattenWidgetsOnPage(pageRef, widgets) {
19789
20064
  const pageDict = this.registry.resolve(pageRef);
19790
20065
  if (!(pageDict instanceof PdfDict)) return;
19791
- let resources = pageDict.getDict("Resources");
20066
+ const resolve = this.registry.resolve.bind(this.registry);
20067
+ let resources = pageDict.getDict("Resources", resolve);
19792
20068
  if (!resources) {
19793
20069
  resources = new PdfDict();
19794
20070
  pageDict.set("Resources", resources);
19795
20071
  }
19796
- let xObjects = resources.getDict("XObject");
20072
+ let xObjects = resources.getDict("XObject", resolve);
19797
20073
  if (!xObjects) {
19798
20074
  xObjects = new PdfDict();
19799
20075
  resources.set("XObject", xObjects);
@@ -19827,7 +20103,7 @@ var FormFlattener = class {
19827
20103
  * Per PDFBox: BBox must exist and have width/height > 0.
19828
20104
  */
19829
20105
  isVisibleAppearance(appearance) {
19830
- const bbox = appearance.getArray("BBox");
20106
+ const bbox = appearance.getArray("BBox", this.registry.resolve.bind(this.registry));
19831
20107
  if (!bbox || bbox.length < 4) return false;
19832
20108
  const [x1, y1, x2, y2] = bbox.toArray().map((item) => item instanceof PdfNumber ? item.value : 0);
19833
20109
  const width = Math.abs((x2 ?? 0) - (x1 ?? 0));
@@ -19929,7 +20205,7 @@ var FormFlattener = class {
19929
20205
  * Get the appearance stream's transformation matrix.
19930
20206
  */
19931
20207
  getAppearanceMatrix(appearance) {
19932
- const matrixArray = appearance.getArray("Matrix");
20208
+ const matrixArray = appearance.getArray("Matrix", this.registry.resolve.bind(this.registry));
19933
20209
  if (!matrixArray || matrixArray.length < 6) return Matrix.identity();
19934
20210
  const [a, b, c, d, e, f] = matrixArray.toArray().map((item) => item instanceof PdfNumber ? item.value : 0);
19935
20211
  return new Matrix(a ?? 0, b ?? 0, c ?? 0, d ?? 0, e ?? 0, f ?? 0);
@@ -19938,7 +20214,7 @@ var FormFlattener = class {
19938
20214
  * Get appearance BBox, with fallback.
19939
20215
  */
19940
20216
  getAppearanceBBox(appearance) {
19941
- const bbox = appearance.getArray("BBox");
20217
+ const bbox = appearance.getArray("BBox", this.registry.resolve.bind(this.registry));
19942
20218
  if (!bbox || bbox.length < 4) return [
19943
20219
  0,
19944
20220
  0,
@@ -19957,14 +20233,7 @@ var FormFlattener = class {
19957
20233
  * Remove specific annotations from page.
19958
20234
  */
19959
20235
  removeAnnotations(page, toRemove) {
19960
- const annotsEntry = page.get("Annots");
19961
- if (!annotsEntry) return;
19962
- let annots = null;
19963
- if (annotsEntry instanceof PdfArray) annots = annotsEntry;
19964
- else if (annotsEntry instanceof PdfRef) {
19965
- const resolved = this.registry.resolve(annotsEntry);
19966
- if (resolved instanceof PdfArray) annots = resolved;
19967
- }
20236
+ const annots = page.getArray("Annots", this.registry.resolve.bind(this.registry));
19968
20237
  if (!annots) return;
19969
20238
  const remaining = [];
19970
20239
  for (let i = 0; i < annots.length; i++) {
@@ -20030,11 +20299,8 @@ var AcroForm = class AcroForm {
20030
20299
  * @param pageTree Optional page tree for efficient page lookups during flattening
20031
20300
  */
20032
20301
  static load(catalog, registry, pageTree) {
20033
- let acroFormEntry = catalog.get("AcroForm");
20034
- if (!acroFormEntry) return null;
20035
- let dict = null;
20036
- if (acroFormEntry instanceof PdfRef) acroFormEntry = registry.resolve(acroFormEntry) ?? void 0;
20037
- if (acroFormEntry instanceof PdfDict) dict = acroFormEntry;
20302
+ const resolve = registry.resolve.bind(registry);
20303
+ const dict = catalog.getDict("AcroForm", resolve);
20038
20304
  if (!dict) return null;
20039
20305
  return new AcroForm(dict, registry, pageTree ?? null);
20040
20306
  }
@@ -20042,11 +20308,7 @@ var AcroForm = class AcroForm {
20042
20308
  * Default resources dictionary (fonts, etc.).
20043
20309
  */
20044
20310
  getDefaultResources() {
20045
- let dr = this.dict.get("DR");
20046
- if (!dr) return null;
20047
- if (dr instanceof PdfRef) dr = this.registry.resolve(dr) ?? void 0;
20048
- if (dr instanceof PdfDict) return dr;
20049
- return null;
20311
+ return this.dict.getDict("DR", this.registry.resolve.bind(this.registry)) ?? null;
20050
20312
  }
20051
20313
  /**
20052
20314
  * Default appearance string.
@@ -20210,9 +20472,10 @@ var AcroForm = class AcroForm {
20210
20472
  ensureExistingFontsLoaded() {
20211
20473
  if (this.existingFontsCache !== null) return;
20212
20474
  this.existingFontsCache = /* @__PURE__ */ new Map();
20213
- const dr = this.dict.getDict("DR");
20475
+ const resolve = this.registry.resolve.bind(this.registry);
20476
+ const dr = this.dict.getDict("DR", resolve);
20214
20477
  if (!dr) return;
20215
- const fonts = dr.getDict("Font");
20478
+ const fonts = dr.getDict("Font", resolve);
20216
20479
  if (!fonts) return;
20217
20480
  for (const key$1 of fonts.keys()) {
20218
20481
  const fontName = key$1.value;
@@ -20387,12 +20650,13 @@ var AcroForm = class AcroForm {
20387
20650
  * @returns The font name used in the /DR dictionary
20388
20651
  */
20389
20652
  addFontToResources(fontRef, name) {
20390
- let dr = this.dict.getDict("DR");
20653
+ const resolve = this.registry.resolve.bind(this.registry);
20654
+ let dr = this.dict.getDict("DR", resolve);
20391
20655
  if (!dr) {
20392
20656
  dr = new PdfDict();
20393
20657
  this.dict.set("DR", dr);
20394
20658
  }
20395
- let fontsDict = dr.getDict("Font");
20659
+ let fontsDict = dr.getDict("Font", resolve);
20396
20660
  if (!fontsDict) {
20397
20661
  fontsDict = new PdfDict();
20398
20662
  dr.set("Font", fontsDict);
@@ -20476,371 +20740,8 @@ var AcroForm = class AcroForm {
20476
20740
  }
20477
20741
  };
20478
20742
 
20479
- //#endregion
20480
- //#region src/fonts/embedded-font.ts
20481
- /**
20482
- * EmbeddedFont represents a font that will be embedded into a PDF.
20483
- *
20484
- * Usage:
20485
- * ```typescript
20486
- * const fontBytes = await fs.readFile("NotoSans-Regular.ttf");
20487
- * const font = EmbeddedFont.fromBytes(fontBytes);
20488
- *
20489
- * // Check if text can be encoded
20490
- * if (font.canEncode("Hello ")) {
20491
- * const codes = font.encodeText("Hello ");
20492
- * const width = font.getTextWidth("Hello ", 12);
20493
- * }
20494
- * ```
20495
- */
20496
- var EmbeddedFont = class EmbeddedFont extends PdfFont {
20497
- subtype = "Type0";
20498
- /** Underlying font program */
20499
- fontProgram;
20500
- /** Original font data */
20501
- fontData;
20502
- /** Track used glyphs for subsetting (GID -> code points that use it) */
20503
- usedGlyphs = new Map([[0, /* @__PURE__ */ new Set()]]);
20504
- /** Track used code points for ToUnicode (codePoint -> GID) */
20505
- usedCodePoints = /* @__PURE__ */ new Map();
20506
- /** Subset tag (generated during save) */
20507
- _subsetTag = null;
20508
- /** Whether this font is used in a form field (prevents subsetting) */
20509
- _usedInForm = false;
20510
- /** Cached descriptor */
20511
- _descriptor = null;
20512
- constructor(fontProgram, fontData) {
20513
- super();
20514
- this.fontProgram = fontProgram;
20515
- this.fontData = fontData;
20516
- }
20517
- /**
20518
- * Create an EmbeddedFont from raw font bytes.
20519
- *
20520
- * @param data - TTF, OTF, or Type1 font data
20521
- * @param options - Embedding options
20522
- * @returns EmbeddedFont instance
20523
- * @throws {Error} if font format is not recognized
20524
- */
20525
- static fromBytes(data, _options) {
20526
- return new EmbeddedFont(parseFontProgram(data), data);
20527
- }
20528
- /**
20529
- * Create an EmbeddedFont from an already-parsed TrueType font.
20530
- */
20531
- static fromTrueTypeFont(font, data) {
20532
- return new EmbeddedFont(new TrueTypeFontProgram(font, data), data);
20533
- }
20534
- /**
20535
- * Get the base font name.
20536
- * During save, this will include a subset tag prefix (e.g., "ABCDEF+FontName").
20537
- */
20538
- get baseFontName() {
20539
- const name = this.fontProgram.postScriptName ?? "Unknown";
20540
- return this._subsetTag ? `${this._subsetTag}+${name}` : name;
20541
- }
20542
- /**
20543
- * Get the font descriptor.
20544
- */
20545
- get descriptor() {
20546
- if (!this._descriptor) this._descriptor = this.buildDescriptor();
20547
- return this._descriptor;
20548
- }
20549
- /**
20550
- * Get the underlying font program.
20551
- */
20552
- get program() {
20553
- return this.fontProgram;
20554
- }
20555
- /**
20556
- * Get the original font data.
20557
- */
20558
- get data() {
20559
- return this.fontData;
20560
- }
20561
- /**
20562
- * Get the subset tag (only available after save).
20563
- */
20564
- get subsetTag() {
20565
- return this._subsetTag;
20566
- }
20567
- /**
20568
- * Set the subset tag (called during save).
20569
- */
20570
- setSubsetTag(tag) {
20571
- this._subsetTag = tag;
20572
- }
20573
- /**
20574
- * Get all used glyph IDs.
20575
- */
20576
- getUsedGlyphIds() {
20577
- return [...this.usedGlyphs.keys()].sort((a, b) => a - b);
20578
- }
20579
- /**
20580
- * Get mapping from code point to GID.
20581
- */
20582
- getCodePointToGidMap() {
20583
- return new Map(this.usedCodePoints);
20584
- }
20585
- /**
20586
- * Get mapping from GID to Unicode code point.
20587
- *
20588
- * This is used for building the /W widths array and ToUnicode CMap.
20589
- * Since the content stream contains GIDs (with CIDToGIDMap /Identity),
20590
- * the /W array must be keyed by GID, and ToUnicode must map GID → Unicode.
20591
- *
20592
- * If multiple code points map to the same GID, returns the first one found.
20593
- */
20594
- getGidToCodePointMap() {
20595
- const result = /* @__PURE__ */ new Map();
20596
- for (const [gid, codePoints] of this.usedGlyphs) if (codePoints.size > 0) {
20597
- const firstCodePoint = codePoints.values().next().value;
20598
- if (firstCodePoint !== void 0) result.set(gid, firstCodePoint);
20599
- }
20600
- return result;
20601
- }
20602
- /**
20603
- * Iterate over text, tracking glyph usage and returning codePoint/GID pairs.
20604
- * This is the shared implementation for encodeText and encodeTextToGids.
20605
- */
20606
- trackAndEncode(text) {
20607
- const result = [];
20608
- for (const char of text) {
20609
- const codePoint = char.codePointAt(0);
20610
- if (codePoint === void 0) continue;
20611
- const gid = this.fontProgram.getGlyphId(codePoint);
20612
- if (!this.usedGlyphs.has(gid)) this.usedGlyphs.set(gid, /* @__PURE__ */ new Set());
20613
- this.usedGlyphs.get(gid).add(codePoint);
20614
- this.usedCodePoints.set(codePoint, gid);
20615
- result.push({
20616
- codePoint,
20617
- gid
20618
- });
20619
- }
20620
- return result;
20621
- }
20622
- /**
20623
- * Encode text to character codes.
20624
- *
20625
- * Returns Unicode code points, which is intuitive for users.
20626
- * The conversion to glyph IDs happens internally when writing to the PDF.
20627
- *
20628
- * Also tracks glyph usage for subsetting.
20629
- */
20630
- encodeText(text) {
20631
- return this.trackAndEncode(text).map((e) => e.codePoint);
20632
- }
20633
- /**
20634
- * Encode text to glyph IDs for PDF content stream.
20635
- *
20636
- * This is an internal method used when writing to the PDF.
20637
- * With CIDToGIDMap /Identity, the content stream must contain GIDs.
20638
- *
20639
- * @internal
20640
- */
20641
- encodeTextToGids(text) {
20642
- return this.trackAndEncode(text).map((e) => e.gid);
20643
- }
20644
- /**
20645
- * Convert a code point to its glyph ID.
20646
- *
20647
- * @internal
20648
- */
20649
- codePointToGid(codePoint) {
20650
- return this.fontProgram.getGlyphId(codePoint);
20651
- }
20652
- /**
20653
- * Get width of a character in glyph units (1000 = 1 em).
20654
- *
20655
- * Takes a Unicode code point (user-friendly API).
20656
- */
20657
- getWidth(code) {
20658
- const gid = this.fontProgram.getGlyphId(code);
20659
- const width = this.fontProgram.getAdvanceWidth(gid);
20660
- return Math.round(width * 1e3 / this.fontProgram.unitsPerEm);
20661
- }
20662
- /**
20663
- * Decode character code to Unicode string.
20664
- *
20665
- * For embedded fonts with Identity-H encoding, the code is the code point,
20666
- * so this just converts the code point back to a string.
20667
- */
20668
- toUnicode(code) {
20669
- return String.fromCodePoint(code);
20670
- }
20671
- /**
20672
- * Check if the font can encode the given text.
20673
- * Returns true if all characters have glyphs in the font.
20674
- */
20675
- canEncode(text) {
20676
- for (const char of text) {
20677
- const codePoint = char.codePointAt(0);
20678
- if (codePoint === void 0) continue;
20679
- if (!this.fontProgram.hasGlyph(codePoint)) return false;
20680
- }
20681
- return true;
20682
- }
20683
- /**
20684
- * Get the characters that cannot be encoded.
20685
- */
20686
- getUnencodableCharacters(text) {
20687
- const unencodable = [];
20688
- for (const char of text) {
20689
- const codePoint = char.codePointAt(0);
20690
- if (codePoint === void 0) continue;
20691
- if (!this.fontProgram.hasGlyph(codePoint)) unencodable.push(char);
20692
- }
20693
- return unencodable;
20694
- }
20695
- /**
20696
- * Reset glyph usage tracking.
20697
- * Call this before re-encoding if you want a fresh subset.
20698
- */
20699
- resetUsage() {
20700
- this.usedGlyphs.clear();
20701
- this.usedGlyphs.set(0, /* @__PURE__ */ new Set());
20702
- this.usedCodePoints.clear();
20703
- this._subsetTag = null;
20704
- }
20705
- /**
20706
- * Mark this font as used in a form field.
20707
- *
20708
- * Fonts used in form fields cannot be subsetted because users may type
20709
- * any character at runtime. This method is called automatically when
20710
- * an EmbeddedFont is used in form field appearances.
20711
- */
20712
- markUsedInForm() {
20713
- this._usedInForm = true;
20714
- }
20715
- /**
20716
- * Check if this font is used in a form field.
20717
- */
20718
- get usedInForm() {
20719
- return this._usedInForm;
20720
- }
20721
- /**
20722
- * Check if this font can be subsetted.
20723
- *
20724
- * Returns false if the font is used in a form field (since users can
20725
- * type any character at runtime).
20726
- */
20727
- canSubset() {
20728
- return !this._usedInForm;
20729
- }
20730
- /**
20731
- * Get width of text in points at a given font size.
20732
- *
20733
- * Alias for getTextWidth() to match Standard14Font API.
20734
- *
20735
- * @param text - The text to measure
20736
- * @param size - Font size in points
20737
- * @returns Width in points
20738
- */
20739
- widthOfTextAtSize(text, size) {
20740
- return this.getTextWidth(text, size);
20741
- }
20742
- /**
20743
- * Get the height of the font at a given size.
20744
- *
20745
- * This returns the full height from descender to ascender.
20746
- *
20747
- * @param size - Font size in points
20748
- * @returns Height in points
20749
- */
20750
- heightAtSize(size) {
20751
- const desc = this.descriptor;
20752
- if (!desc) return size;
20753
- return (desc.ascent - desc.descent) * size / 1e3;
20754
- }
20755
- /**
20756
- * Calculate font size needed to achieve a specific text height.
20757
- *
20758
- * @param height - Desired height in points
20759
- * @returns Font size in points
20760
- */
20761
- sizeAtHeight(height) {
20762
- const desc = this.descriptor;
20763
- if (!desc) return height;
20764
- const unitsHeight = desc.ascent - desc.descent;
20765
- return height * 1e3 / unitsHeight;
20766
- }
20767
- /**
20768
- * Calculate font size needed for text to fit a specific width.
20769
- *
20770
- * @param text - The text to measure
20771
- * @param width - Desired width in points
20772
- * @returns Font size in points
20773
- */
20774
- sizeAtWidth(text, width) {
20775
- if (text.length === 0) return 0;
20776
- const codes = this.encodeText(text);
20777
- let totalWidth = 0;
20778
- for (const code of codes) totalWidth += this.getWidth(code);
20779
- if (totalWidth === 0) return 0;
20780
- return width * 1e3 / totalWidth;
20781
- }
20782
- /**
20783
- * Build a FontDescriptor from the font program.
20784
- */
20785
- buildDescriptor() {
20786
- const program = this.fontProgram;
20787
- const bbox = program.bbox;
20788
- const scale = 1e3 / program.unitsPerEm;
20789
- return new FontDescriptor({
20790
- fontName: program.postScriptName ?? "Unknown",
20791
- flags: this.computeFlags(),
20792
- fontBBox: [
20793
- Math.round(bbox[0] * scale),
20794
- Math.round(bbox[1] * scale),
20795
- Math.round(bbox[2] * scale),
20796
- Math.round(bbox[3] * scale)
20797
- ],
20798
- italicAngle: program.italicAngle,
20799
- ascent: Math.round(program.ascent * scale),
20800
- descent: Math.round(program.descent * scale),
20801
- leading: 0,
20802
- capHeight: Math.round(program.capHeight * scale),
20803
- xHeight: Math.round(program.xHeight * scale),
20804
- stemV: program.stemV,
20805
- stemH: 0,
20806
- avgWidth: 0,
20807
- maxWidth: 0,
20808
- missingWidth: this.getWidth(0)
20809
- });
20810
- }
20811
- /**
20812
- * Compute font flags for the descriptor.
20813
- */
20814
- computeFlags() {
20815
- let flags = 0;
20816
- if (this.fontProgram.isFixedPitch) flags |= 1;
20817
- flags |= 4;
20818
- if (this.fontProgram.italicAngle !== 0) flags |= 64;
20819
- return flags;
20820
- }
20821
- };
20822
-
20823
20743
  //#endregion
20824
20744
  //#region src/fonts/cid-font.ts
20825
- /**
20826
- * CIDFont - Descendant font for Type0 composite fonts.
20827
- *
20828
- * CIDFonts contain the actual glyph descriptions and metrics for
20829
- * composite (Type0) fonts. They use CIDs (Character IDs) to identify
20830
- * glyphs rather than character codes.
20831
- *
20832
- * Font structure:
20833
- * <<
20834
- * /Type /Font
20835
- * /Subtype /CIDFontType2 (or /CIDFontType0)
20836
- * /BaseFont /NotoSansCJK-Regular
20837
- * /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >>
20838
- * /FontDescriptor 14 0 R
20839
- * /W [1 [500 600] 100 200 500] % Complex width format
20840
- * /DW 1000
20841
- * /CIDToGIDMap /Identity
20842
- * >>
20843
- */
20844
20745
  const isCIDFontSubtype = (subtype) => {
20845
20746
  return subtype === "CIDFontType0" || subtype === "CIDFontType2";
20846
20747
  };
@@ -21005,7 +20906,7 @@ function parseCIDFont(dict, options = {}) {
21005
20906
  ordering: "Identity",
21006
20907
  supplement: 0
21007
20908
  };
21008
- const sysInfoDict = dict.getDict("CIDSystemInfo");
20909
+ const sysInfoDict = dict.getDict("CIDSystemInfo", options.resolver);
21009
20910
  if (sysInfoDict) cidSystemInfo = {
21010
20911
  registry: sysInfoDict.getString("Registry")?.asString() ?? "Adobe",
21011
20912
  ordering: sysInfoDict.getString("Ordering")?.asString() ?? "Identity",
@@ -21013,30 +20914,23 @@ function parseCIDFont(dict, options = {}) {
21013
20914
  };
21014
20915
  const defaultWidth = dict.getNumber("DW")?.value ?? 1e3;
21015
20916
  let widths = new CIDWidthMap();
21016
- let w = dict.get("W");
20917
+ let w = dict.get("W", options.resolver);
21017
20918
  let wArray = null;
21018
- if (w instanceof PdfRef && options.resolveRef) w = options.resolveRef(w) ?? void 0;
21019
20919
  if (w instanceof PdfArray) wArray = w;
21020
20920
  if (wArray) widths = parseCIDWidths(wArray);
21021
20921
  let descriptor = null;
21022
20922
  let embeddedProgram = null;
21023
- const descriptorRef = dict.get("FontDescriptor");
21024
- if (descriptorRef && options.resolveRef) {
21025
- const descriptorDict = options.resolveRef(descriptorRef);
21026
- if (descriptorDict && descriptorDict.type === "dict") {
21027
- descriptor = FontDescriptor.parse(descriptorDict);
21028
- if (options.decodeStream) embeddedProgram = parseEmbeddedProgram(descriptorDict, {
21029
- decodeStream: options.decodeStream,
21030
- resolveRef: options.resolveRef
21031
- });
21032
- }
20923
+ const fontDescriptor = dict.getDict("FontDescriptor", options.resolver);
20924
+ if (fontDescriptor) {
20925
+ descriptor = FontDescriptor.parse(fontDescriptor);
20926
+ embeddedProgram = parseEmbeddedProgram(fontDescriptor, { resolver: options.resolver });
21033
20927
  }
21034
20928
  let cidToGidMap = "Identity";
21035
- const cidToGidValue = dict.get("CIDToGIDMap");
20929
+ const cidToGidValue = dict.get("CIDToGIDMap", options.resolver);
21036
20930
  if (cidToGidValue) {
21037
- if (cidToGidValue.type === "name" && cidToGidValue.value === "Identity") cidToGidMap = "Identity";
21038
- if (cidToGidValue.type === "stream" && options.decodeStream) {
21039
- const mapData = options.decodeStream(cidToGidValue);
20931
+ if (cidToGidValue instanceof PdfName && cidToGidValue.value === "Identity") cidToGidMap = "Identity";
20932
+ if (cidToGidValue instanceof PdfStream) {
20933
+ const mapData = cidToGidValue.getDecodedData();
21040
20934
  if (mapData && mapData.length >= 2) {
21041
20935
  const numEntries = mapData.length / 2;
21042
20936
  cidToGidMap = new Uint16Array(numEntries);
@@ -21318,24 +21212,6 @@ function bytesToLatin1$1(data) {
21318
21212
  //#endregion
21319
21213
  //#region src/fonts/composite-font.ts
21320
21214
  /**
21321
- * CompositeFont - Type0 composite font for CJK and Unicode text.
21322
- *
21323
- * Composite fonts (Type0) combine:
21324
- * - A CMap (character code to CID mapping)
21325
- * - One or more CIDFonts (the actual glyph data)
21326
- * - Optional ToUnicode map (for text extraction)
21327
- *
21328
- * Font structure:
21329
- * <<
21330
- * /Type /Font
21331
- * /Subtype /Type0
21332
- * /BaseFont /NotoSansCJK-Regular
21333
- * /Encoding /Identity-H (or stream)
21334
- * /DescendantFonts [12 0 R]
21335
- * /ToUnicode 13 0 R
21336
- * >>
21337
- */
21338
- /**
21339
21215
  * CompositeFont handles Type0 composite fonts (CJK, Unicode).
21340
21216
  */
21341
21217
  var CompositeFont = class extends PdfFont {
@@ -21410,40 +21286,28 @@ var CompositeFont = class extends PdfFont {
21410
21286
  * Parse CMap from encoding value.
21411
21287
  */
21412
21288
  function parseCMapFromEncoding(encodingValue, options) {
21413
- if (!encodingValue || typeof encodingValue !== "object") return CMap.identityH();
21414
- const enc = encodingValue;
21415
- if (enc.type === "name" && enc.value) return CMap.getPredefined(enc.value) ?? CMap.identityH();
21416
- if (enc.type === "stream" && options.decodeStream) {
21417
- const data = options.decodeStream(encodingValue);
21289
+ let encoding = encodingValue;
21290
+ if (encoding instanceof PdfRef && options.resolver) encoding = options.resolver(encoding) ?? void 0;
21291
+ if (encoding instanceof PdfName && encoding.value) return CMap.getPredefined(encoding.value) ?? CMap.identityH();
21292
+ if (encoding instanceof PdfStream) {
21293
+ const data = encoding.getDecodedData();
21418
21294
  return data ? parseCMap(data) : CMap.identityH();
21419
21295
  }
21420
- if (enc.type === "ref" && options.resolveRef && options.decodeStream) {
21421
- const resolved = options.resolveRef(encodingValue);
21422
- if (resolved && resolved.type === "stream") {
21423
- const data = options.decodeStream(resolved);
21424
- return data ? parseCMap(data) : CMap.identityH();
21425
- }
21426
- }
21427
21296
  return CMap.identityH();
21428
21297
  }
21429
21298
  /**
21430
21299
  * Parse a CompositeFont from a PDF font dictionary.
21431
21300
  */
21432
21301
  function parseCompositeFont(dict, options = {}) {
21433
- const baseFontName = dict.getName("BaseFont")?.value ?? "Unknown";
21434
- const cmap = parseCMapFromEncoding(dict.get("Encoding"), options);
21302
+ const baseFontName = dict.getName("BaseFont", options.resolver)?.value ?? "Unknown";
21303
+ const cmap = parseCMapFromEncoding(dict.get("Encoding", options.resolver), options);
21435
21304
  let cidFont;
21436
- let descendants = dict.get("DescendantFonts");
21305
+ let descendants = dict.get("DescendantFonts", options.resolver);
21437
21306
  let descendantsArray = null;
21438
- if (descendants instanceof PdfRef && options.resolveRef) descendants = options.resolveRef(descendants) ?? void 0;
21439
21307
  if (descendants instanceof PdfArray) descendantsArray = descendants;
21440
21308
  if (descendantsArray && descendantsArray.length > 0) {
21441
- const firstDescendant = descendantsArray.at(0);
21442
- if (firstDescendant?.type === "ref" && options.resolveRef) {
21443
- const cidFontDict = options.resolveRef(firstDescendant);
21444
- if (cidFontDict?.type === "dict") cidFont = parseCIDFont(cidFontDict, options);
21445
- else cidFont = createDefaultCIDFont(baseFontName);
21446
- } else if (firstDescendant?.type === "dict") cidFont = parseCIDFont(firstDescendant, options);
21309
+ const firstDescendant = descendantsArray.at(0, options.resolver);
21310
+ if (firstDescendant instanceof PdfDict) cidFont = parseCIDFont(firstDescendant, options);
21447
21311
  else cidFont = createDefaultCIDFont(baseFontName);
21448
21312
  } else cidFont = createDefaultCIDFont(baseFontName);
21449
21313
  return new CompositeFont({
@@ -21474,7 +21338,7 @@ function createDefaultCIDFont(baseFontName) {
21474
21338
  * @returns A SimpleFont or CompositeFont instance
21475
21339
  */
21476
21340
  function parseFont(dict, options = {}) {
21477
- switch (dict.getName("Subtype")?.value) {
21341
+ switch (dict.getName("Subtype", options.resolver)?.value) {
21478
21342
  case "Type0": return parseCompositeFont(dict, options);
21479
21343
  case "TrueType":
21480
21344
  case "Type1":
@@ -24300,8 +24164,8 @@ var PDFPage = class PDFPage {
24300
24164
  * Page rotation in degrees (0, 90, 180, or 270).
24301
24165
  */
24302
24166
  get rotation() {
24303
- const rotate = this.dict.get("Rotate");
24304
- if (rotate instanceof PdfNumber) {
24167
+ const rotate = this.dict.getNumber("Rotate", this.ctx.resolve.bind(this.ctx));
24168
+ if (rotate) {
24305
24169
  const value = rotate.value % 360;
24306
24170
  if (value === 90 || value === -270) return 90;
24307
24171
  if (value === 180 || value === -180) return 180;
@@ -24321,14 +24185,15 @@ var PDFPage = class PDFPage {
24321
24185
  /**
24322
24186
  * Get the page's Resources dictionary.
24323
24187
  *
24324
- * Creates an empty one if it doesn't exist.
24188
+ * If Resources is a reference, it's dereferenced.
24189
+ * If Resources doesn't exist or is inherited from a parent,
24190
+ * a new empty dict is created on this page.
24325
24191
  */
24326
24192
  getResources() {
24327
- let resources = this.dict.get("Resources");
24328
- if (!(resources instanceof PdfDict)) {
24329
- resources = new PdfDict();
24330
- this.dict.set("Resources", resources);
24331
- }
24193
+ let resources = this.dict.get("Resources", this.ctx.resolve.bind(this.ctx));
24194
+ if (resources instanceof PdfDict) return resources;
24195
+ resources = new PdfDict();
24196
+ this.dict.set("Resources", resources);
24332
24197
  return resources;
24333
24198
  }
24334
24199
  /**
@@ -24458,7 +24323,6 @@ var PDFPage = class PDFPage {
24458
24323
  * ```
24459
24324
  */
24460
24325
  drawField(field, options) {
24461
- if (!this.ctx) throw new Error("Cannot draw field on page without context");
24462
24326
  if (!(field instanceof TerminalField)) throw new Error(`Cannot draw non-terminal field "${field.name}"`);
24463
24327
  if (field instanceof SignatureField) throw new Error("Signature fields cannot be drawn with drawField. Use form.createSignatureField() which creates the widget automatically.");
24464
24328
  if (field instanceof RadioField) {
@@ -24543,7 +24407,6 @@ var PDFPage = class PDFPage {
24543
24407
  * Generate appearance stream for a widget.
24544
24408
  */
24545
24409
  generateWidgetAppearance(field, widget, options) {
24546
- if (!this.ctx) return;
24547
24410
  const catalogDict = this.ctx.catalog.getDict();
24548
24411
  const acroForm = AcroForm.load(catalogDict, this.ctx.registry);
24549
24412
  if (!acroForm) return;
@@ -25008,13 +24871,9 @@ var PDFPage = class PDFPage {
25008
24871
  for (let i = 0; i < annotsArray.length; i++) {
25009
24872
  const entry = annotsArray.at(i);
25010
24873
  if (!entry) continue;
25011
- let annotDict = null;
25012
- let annotRef = null;
25013
- if (entry instanceof PdfRef) {
25014
- annotRef = entry;
25015
- const resolved = this.ctx.resolve(entry);
25016
- if (resolved instanceof PdfDict) annotDict = resolved;
25017
- } else if (entry instanceof PdfDict) annotDict = entry;
24874
+ const resolved = entry instanceof PdfRef ? this.ctx.resolve(entry) : entry;
24875
+ const annotRef = entry instanceof PdfRef ? entry : null;
24876
+ const annotDict = resolved instanceof PdfDict ? resolved : null;
25018
24877
  if (!annotDict) continue;
25019
24878
  if (isWidgetAnnotation(annotDict)) continue;
25020
24879
  if (isPopupAnnotation(annotDict)) continue;
@@ -25036,13 +24895,9 @@ var PDFPage = class PDFPage {
25036
24895
  for (let i = 0; i < annotsArray.length; i++) {
25037
24896
  let entry = annotsArray.at(i);
25038
24897
  if (!entry) continue;
25039
- let annotDict = null;
25040
- let annotRef = null;
25041
- if (entry instanceof PdfRef) {
25042
- annotRef = entry;
25043
- entry = this.ctx.resolve(entry) ?? void 0;
25044
- }
25045
- if (entry instanceof PdfDict) annotDict = entry;
24898
+ const resolved = entry instanceof PdfRef ? this.ctx.resolve(entry) : entry;
24899
+ const annotRef = entry instanceof PdfRef ? entry : null;
24900
+ const annotDict = resolved instanceof PdfDict ? resolved : null;
25046
24901
  if (!annotDict || !isPopupAnnotation(annotDict)) continue;
25047
24902
  popups.push(new PDFPopupAnnotation(annotDict, annotRef, this.ctx.registry));
25048
24903
  }
@@ -25193,7 +25048,6 @@ var PDFPage = class PDFPage {
25193
25048
  * Add a text markup annotation (internal helper).
25194
25049
  */
25195
25050
  addTextMarkupAnnotation(subtype, options) {
25196
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25197
25051
  let annotDict;
25198
25052
  switch (subtype) {
25199
25053
  case "Highlight":
@@ -25242,7 +25096,6 @@ var PDFPage = class PDFPage {
25242
25096
  * ```
25243
25097
  */
25244
25098
  addLinkAnnotation(options) {
25245
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25246
25099
  const destination = options.destination;
25247
25100
  if (destination) {
25248
25101
  const destinationPage = destination.page;
@@ -25262,7 +25115,6 @@ var PDFPage = class PDFPage {
25262
25115
  * @returns The created annotation
25263
25116
  */
25264
25117
  addTextAnnotation(options) {
25265
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25266
25118
  const annotDict = PDFTextAnnotation.create(options);
25267
25119
  const annotRef = this.ctx.register(annotDict);
25268
25120
  this.addAnnotationRef(annotRef);
@@ -25275,7 +25127,6 @@ var PDFPage = class PDFPage {
25275
25127
  * @returns The created annotation
25276
25128
  */
25277
25129
  addLineAnnotation(options) {
25278
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25279
25130
  const annotDict = PDFLineAnnotation.create(options);
25280
25131
  const annotRef = this.ctx.register(annotDict);
25281
25132
  this.addAnnotationRef(annotRef);
@@ -25288,7 +25139,6 @@ var PDFPage = class PDFPage {
25288
25139
  * @returns The created annotation
25289
25140
  */
25290
25141
  addSquareAnnotation(options) {
25291
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25292
25142
  const annotDict = PDFSquareAnnotation.create(options);
25293
25143
  const annotRef = this.ctx.register(annotDict);
25294
25144
  this.addAnnotationRef(annotRef);
@@ -25301,7 +25151,6 @@ var PDFPage = class PDFPage {
25301
25151
  * @returns The created annotation
25302
25152
  */
25303
25153
  addCircleAnnotation(options) {
25304
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25305
25154
  const annotDict = PDFCircleAnnotation.create(options);
25306
25155
  const annotRef = this.ctx.register(annotDict);
25307
25156
  this.addAnnotationRef(annotRef);
@@ -25314,7 +25163,6 @@ var PDFPage = class PDFPage {
25314
25163
  * @returns The created annotation
25315
25164
  */
25316
25165
  addStampAnnotation(options) {
25317
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25318
25166
  const annotDict = PDFStampAnnotation.create(options);
25319
25167
  const annotRef = this.ctx.register(annotDict);
25320
25168
  this.addAnnotationRef(annotRef);
@@ -25327,7 +25175,6 @@ var PDFPage = class PDFPage {
25327
25175
  * @returns The created annotation
25328
25176
  */
25329
25177
  addInkAnnotation(options) {
25330
- if (!this.ctx) throw new Error("Cannot add annotation to page without context");
25331
25178
  const annotDict = PDFInkAnnotation.create(options);
25332
25179
  const annotRef = this.ctx.register(annotDict);
25333
25180
  this.addAnnotationRef(annotRef);
@@ -25347,7 +25194,6 @@ var PDFPage = class PDFPage {
25347
25194
  * ```
25348
25195
  */
25349
25196
  removeAnnotation(annotation) {
25350
- if (!this.ctx) return;
25351
25197
  const annots = this.dict.getArray("Annots");
25352
25198
  if (!annots) return;
25353
25199
  const removeMatchingEntry = (predicate) => {
@@ -25409,7 +25255,6 @@ var PDFPage = class PDFPage {
25409
25255
  * ```
25410
25256
  */
25411
25257
  flattenAnnotations(options) {
25412
- if (!this.ctx) return 0;
25413
25258
  const count = new AnnotationFlattener(this.ctx.registry).flattenPage(this.dict, options);
25414
25259
  this.invalidateAnnotationCache();
25415
25260
  return count;
@@ -25501,16 +25346,24 @@ var PDFPage = class PDFPage {
25501
25346
  prependContent(content) {
25502
25347
  const existingContents = this.dict.get("Contents");
25503
25348
  const newContent = this.createContentStream(`${content}\n`);
25504
- if (!existingContents) this.dict.set("Contents", newContent);
25505
- else if (existingContents instanceof PdfRef) {
25349
+ if (!existingContents) {
25350
+ this.dict.set("Contents", newContent);
25351
+ return;
25352
+ }
25353
+ if (existingContents instanceof PdfRef) {
25506
25354
  this.dict.set("Contents", new PdfArray([newContent, existingContents]));
25507
25355
  this._contentWrapped = true;
25508
- } else if (existingContents instanceof PdfStream) {
25356
+ return;
25357
+ }
25358
+ if (existingContents instanceof PdfStream) {
25509
25359
  this.dict.set("Contents", new PdfArray([newContent, existingContents]));
25510
25360
  this._contentWrapped = true;
25511
- } else if (existingContents instanceof PdfArray) {
25361
+ return;
25362
+ }
25363
+ if (existingContents instanceof PdfArray) {
25512
25364
  existingContents.insert(0, newContent);
25513
25365
  this._contentWrapped = true;
25366
+ return;
25514
25367
  }
25515
25368
  }
25516
25369
  /** Track whether we've already wrapped the original content in q/Q */
@@ -25533,19 +25386,25 @@ var PDFPage = class PDFPage {
25533
25386
  this._contentWrapped = true;
25534
25387
  const qStream = this.createContentStream("q\n");
25535
25388
  const QStream = this.createContentStream("\nQ");
25536
- if (existingContents instanceof PdfRef) this.dict.set("Contents", new PdfArray([
25537
- qStream,
25538
- existingContents,
25539
- QStream,
25540
- newContent
25541
- ]));
25542
- else if (existingContents instanceof PdfStream) this.dict.set("Contents", new PdfArray([
25543
- qStream,
25544
- existingContents,
25545
- QStream,
25546
- newContent
25547
- ]));
25548
- else if (existingContents instanceof PdfArray) {
25389
+ if (existingContents instanceof PdfRef) {
25390
+ this.dict.set("Contents", new PdfArray([
25391
+ qStream,
25392
+ existingContents,
25393
+ QStream,
25394
+ newContent
25395
+ ]));
25396
+ return;
25397
+ }
25398
+ if (existingContents instanceof PdfStream) {
25399
+ this.dict.set("Contents", new PdfArray([
25400
+ qStream,
25401
+ existingContents,
25402
+ QStream,
25403
+ newContent
25404
+ ]));
25405
+ return;
25406
+ }
25407
+ if (existingContents instanceof PdfArray) {
25549
25408
  const newArray = new PdfArray([qStream]);
25550
25409
  for (let i = 0; i < existingContents.length; i++) {
25551
25410
  const item = existingContents.at(i);
@@ -25554,18 +25413,20 @@ var PDFPage = class PDFPage {
25554
25413
  newArray.push(QStream);
25555
25414
  newArray.push(newContent);
25556
25415
  this.dict.set("Contents", newArray);
25416
+ return;
25557
25417
  }
25558
- } else {
25559
- const contents = this.dict.get("Contents");
25560
- if (contents instanceof PdfArray) contents.push(newContent);
25561
- else if (contents !== void 0) this.dict.set("Contents", new PdfArray([contents, newContent]));
25562
25418
  }
25419
+ if (existingContents instanceof PdfArray) {
25420
+ existingContents.push(newContent);
25421
+ return;
25422
+ }
25423
+ if (existingContents !== void 0) this.dict.set("Contents", new PdfArray([existingContents, newContent]));
25563
25424
  }
25564
25425
  /**
25565
25426
  * Get a box (MediaBox, CropBox, etc.) from the page dictionary.
25566
25427
  */
25567
25428
  getBox(name) {
25568
- const box = this.dict.get(name);
25429
+ const box = this.dict.get(name, this.ctx.resolve.bind(this.ctx));
25569
25430
  if (!(box instanceof PdfArray) || box.length < 4) return null;
25570
25431
  const x1 = box.at(0);
25571
25432
  const y1 = box.at(1);
@@ -25602,7 +25463,7 @@ var PDFPage = class PDFPage {
25602
25463
  */
25603
25464
  addFontResource(font) {
25604
25465
  const resources = this.getResources();
25605
- let fonts = resources.get("Font");
25466
+ let fonts = resources.get("Font", this.ctx.resolve.bind(this.ctx));
25606
25467
  if (!(fonts instanceof PdfDict)) {
25607
25468
  fonts = new PdfDict();
25608
25469
  resources.set("Font", fonts);
@@ -25610,7 +25471,7 @@ var PDFPage = class PDFPage {
25610
25471
  if (typeof font === "string") {
25611
25472
  if (!isStandard14Font(font)) throw new Error(`Unknown Standard 14 font: ${font}`);
25612
25473
  for (const [existingName, value] of fonts) if (value instanceof PdfDict) {
25613
- const baseFont = value.get("BaseFont");
25474
+ const baseFont = value.get("BaseFont", this.ctx.resolve.bind(this.ctx));
25614
25475
  if (baseFont instanceof PdfName && baseFont.value === font) return existingName.value;
25615
25476
  }
25616
25477
  const fontDict = PdfDict.of({
@@ -25623,7 +25484,6 @@ var PDFPage = class PDFPage {
25623
25484
  return fontName;
25624
25485
  }
25625
25486
  if (font instanceof EmbeddedFont) {
25626
- if (!this.ctx) throw new Error("Cannot use embedded fonts without document context");
25627
25487
  const fontRef = this.ctx.getFontRef(font);
25628
25488
  for (const [existingName, value] of fonts) if (value instanceof PdfRef && value.objectNumber === fontRef.objectNumber && value.generation === fontRef.generation) return existingName.value;
25629
25489
  const fontName = this.generateUniqueName(fonts, "F");
@@ -25704,21 +25564,14 @@ var PDFPage = class PDFPage {
25704
25564
  * Get the concatenated content stream bytes.
25705
25565
  */
25706
25566
  getContentBytes() {
25707
- const contents = this.dict.get("Contents");
25567
+ const contents = this.dict.get("Contents", this.ctx.resolve.bind(this.ctx));
25708
25568
  if (!contents) return new Uint8Array(0);
25709
- if (contents instanceof PdfRef && this.ctx) {
25710
- const stream = this.ctx.resolve(contents);
25711
- if (stream instanceof PdfStream) return stream.getDecodedData();
25712
- }
25713
25569
  if (contents instanceof PdfStream) return contents.getDecodedData();
25714
25570
  if (contents instanceof PdfArray) {
25715
25571
  const chunks = [];
25716
25572
  for (let i = 0; i < contents.length; i++) {
25717
- const item = contents.at(i);
25718
- if (item instanceof PdfRef && this.ctx) {
25719
- const stream = this.ctx.resolve(item);
25720
- if (stream instanceof PdfStream) chunks.push(stream.getDecodedData());
25721
- } else if (item instanceof PdfStream) chunks.push(item.getDecodedData());
25573
+ const item = contents.at(i, this.ctx.resolve.bind(this.ctx));
25574
+ if (item instanceof PdfStream) chunks.push(item.getDecodedData());
25722
25575
  }
25723
25576
  return this.concatenateChunks(chunks);
25724
25577
  }
@@ -25747,20 +25600,13 @@ var PDFPage = class PDFPage {
25747
25600
  * This method checks the page first, then walks up the Parent chain.
25748
25601
  */
25749
25602
  resolveInheritedResources() {
25750
- if (!this.ctx) return null;
25751
25603
  let currentDict = this.dict;
25752
25604
  while (currentDict) {
25753
- const resourcesEntry = currentDict.get("Resources");
25754
- if (resourcesEntry instanceof PdfRef) {
25755
- const resolved = this.ctx.resolve(resourcesEntry);
25756
- if (resolved instanceof PdfDict) return resolved;
25757
- } else if (resourcesEntry instanceof PdfDict) return resourcesEntry;
25758
- const parentEntry = currentDict.get("Parent");
25759
- if (parentEntry instanceof PdfRef) {
25760
- const parent = this.ctx.resolve(parentEntry);
25761
- if (parent instanceof PdfDict) currentDict = parent;
25762
- else break;
25763
- } else break;
25605
+ const resources = currentDict.get("Resources", this.ctx.resolve.bind(this.ctx));
25606
+ if (resources instanceof PdfDict) return resources;
25607
+ const parent = currentDict.get("Parent", this.ctx.resolve.bind(this.ctx));
25608
+ if (parent instanceof PdfDict) currentDict = parent;
25609
+ else break;
25764
25610
  }
25765
25611
  return null;
25766
25612
  }
@@ -25770,85 +25616,22 @@ var PDFPage = class PDFPage {
25770
25616
  createFontResolver() {
25771
25617
  const resourcesDict = this.resolveInheritedResources();
25772
25618
  if (!resourcesDict) return () => null;
25773
- let fontDict = null;
25774
- const fontEntry = resourcesDict.get("Font");
25775
- if (fontEntry instanceof PdfRef && this.ctx) {
25776
- const resolved = this.ctx.resolve(fontEntry);
25777
- if (resolved instanceof PdfDict) fontDict = resolved;
25778
- } else if (fontEntry instanceof PdfDict) fontDict = fontEntry;
25779
- if (!fontDict) return () => null;
25619
+ const font = resourcesDict.getDict("Font", this.ctx.resolve.bind(this.ctx));
25620
+ if (!font) return () => null;
25780
25621
  const fontCache = /* @__PURE__ */ new Map();
25781
- for (const [nameObj, fontEntry$1] of fontDict) {
25782
- const name = nameObj.value;
25783
- let fontDictEntry = null;
25784
- if (fontEntry$1 instanceof PdfRef && this.ctx) {
25785
- const resolved = this.ctx.resolve(fontEntry$1);
25786
- if (resolved instanceof PdfDict) fontDictEntry = resolved;
25787
- } else if (fontEntry$1 instanceof PdfDict) fontDictEntry = fontEntry$1;
25788
- if (!fontDictEntry) continue;
25622
+ for (const [key$1, entry] of font) {
25623
+ const name = key$1.value;
25624
+ const resolved = entry instanceof PdfRef ? this.ctx.resolve(entry) : entry;
25625
+ let entryDict = resolved instanceof PdfDict ? resolved : null;
25626
+ if (!entryDict) continue;
25789
25627
  let toUnicodeMap = null;
25790
- const toUnicodeEntry = fontDictEntry.get("ToUnicode");
25791
- if (toUnicodeEntry && this.ctx) {
25792
- let toUnicodeStream = null;
25793
- if (toUnicodeEntry instanceof PdfRef) {
25794
- const resolved = this.ctx.resolve(toUnicodeEntry);
25795
- if (resolved instanceof PdfStream) toUnicodeStream = resolved;
25796
- } else if (toUnicodeEntry instanceof PdfStream) toUnicodeStream = toUnicodeEntry;
25797
- if (toUnicodeStream) try {
25798
- toUnicodeMap = parseToUnicode(toUnicodeStream.getDecodedData());
25799
- } catch {}
25800
- }
25801
- const resolvedRefs = /* @__PURE__ */ new Map();
25802
- const decodedStreams = /* @__PURE__ */ new Map();
25803
- const preResolveValue = (value) => {
25804
- if (!this.ctx) return;
25805
- if (value instanceof PdfRef) {
25806
- const key$1 = `${value.objectNumber} ${value.generation} R`;
25807
- if (resolvedRefs.has(key$1)) return;
25808
- const resolved = this.ctx.resolve(value);
25809
- if (resolved instanceof PdfDict || resolved instanceof PdfArray || resolved instanceof PdfStream) {
25810
- resolvedRefs.set(key$1, resolved);
25811
- if (resolved instanceof PdfStream) try {
25812
- const decoded = resolved.getDecodedData();
25813
- decodedStreams.set(key$1, decoded);
25814
- } catch {}
25815
- preResolveValue(resolved);
25816
- }
25817
- } else if (value instanceof PdfDict) for (const [, v] of value) preResolveValue(v);
25818
- else if (value instanceof PdfArray) for (let i = 0; i < value.length; i++) preResolveValue(value.at(i));
25819
- };
25820
- preResolveValue(fontDictEntry.get("DescendantFonts"));
25821
- preResolveValue(fontDictEntry.get("FontDescriptor"));
25822
- preResolveValue(fontDictEntry.get("Encoding"));
25823
- preResolveValue(fontDictEntry.get("Widths"));
25824
- const pdfFont = parseFont(fontDictEntry, {
25825
- resolveRef: (ref) => {
25826
- if (ref instanceof PdfRef && this.ctx) {
25827
- const key$1 = `${ref.objectNumber} ${ref.generation} R`;
25828
- const preResolved = resolvedRefs.get(key$1);
25829
- if (preResolved) return preResolved;
25830
- const obj = this.ctx.getObject(ref);
25831
- if (obj instanceof PdfDict || obj instanceof PdfArray || obj instanceof PdfStream) return obj;
25832
- }
25833
- return null;
25834
- },
25835
- decodeStream: (stream) => {
25836
- if (stream instanceof PdfRef) {
25837
- const key$1 = `${stream.objectNumber} ${stream.generation} R`;
25838
- const decoded = decodedStreams.get(key$1);
25839
- if (decoded) return decoded;
25840
- const preResolved = resolvedRefs.get(key$1);
25841
- if (preResolved instanceof PdfStream) return preResolved.data;
25842
- }
25843
- if (stream instanceof PdfStream) {
25844
- for (const [key$1, resolved] of resolvedRefs) if (resolved === stream) {
25845
- const decoded = decodedStreams.get(key$1);
25846
- if (decoded) return decoded;
25847
- }
25848
- return stream.data;
25849
- }
25850
- return null;
25851
- },
25628
+ const toUnicode = entryDict.get("ToUnicode", this.ctx.resolve.bind(this.ctx));
25629
+ const toUnicodeStream = toUnicode instanceof PdfStream ? toUnicode : null;
25630
+ if (toUnicodeStream) try {
25631
+ toUnicodeMap = parseToUnicode(toUnicodeStream.getDecodedData());
25632
+ } catch {}
25633
+ const pdfFont = parseFont(entryDict, {
25634
+ resolver: this.ctx.resolve.bind(this.ctx),
25852
25635
  toUnicodeMap
25853
25636
  });
25854
25637
  fontCache.set(name, pdfFont);
@@ -25949,9 +25732,9 @@ var PDFLinkAnnotation = class extends PDFAnnotation {
25949
25732
  * Get the URI if this is an external link.
25950
25733
  */
25951
25734
  get uri() {
25952
- const action = this.dict.getDict("A");
25735
+ const action = this.dict.getDict("A", this.registry.resolve.bind(this.registry));
25953
25736
  if (action) {
25954
- if (action.getName("S")?.value === "URI") return action.getString("URI")?.asString() ?? null;
25737
+ if (action.getName("S", this.registry.resolve.bind(this.registry))?.value === "URI") return action.getString("URI", this.registry.resolve.bind(this.registry))?.asString() ?? null;
25955
25738
  }
25956
25739
  return null;
25957
25740
  }
@@ -25959,12 +25742,12 @@ var PDFLinkAnnotation = class extends PDFAnnotation {
25959
25742
  * Get the destination if this is an internal link.
25960
25743
  */
25961
25744
  get destination() {
25962
- const dest = this.dict.get("Dest");
25745
+ const dest = this.dict.get("Dest", this.registry.resolve.bind(this.registry));
25963
25746
  if (dest) return this.parseDestination(dest);
25964
- const action = this.dict.getDict("A");
25747
+ const action = this.dict.getDict("A", this.registry.resolve.bind(this.registry));
25965
25748
  if (action) {
25966
- if (action.getName("S")?.value === "GoTo") {
25967
- const d = action.get("D");
25749
+ if (action.getName("S", this.registry.resolve.bind(this.registry))?.value === "GoTo") {
25750
+ const d = action.get("D", this.registry.resolve.bind(this.registry));
25968
25751
  if (d) return this.parseDestination(d);
25969
25752
  }
25970
25753
  }
@@ -25984,12 +25767,12 @@ var PDFLinkAnnotation = class extends PDFAnnotation {
25984
25767
  type: "goto",
25985
25768
  destination: dest
25986
25769
  };
25987
- const action = this.dict.getDict("A");
25770
+ const action = this.dict.getDict("A", this.registry.resolve.bind(this.registry));
25988
25771
  if (action) {
25989
- const actionType = action.getName("S")?.value;
25772
+ const actionType = action.getName("S", this.registry.resolve.bind(this.registry))?.value;
25990
25773
  if (actionType === "GoToR") {
25991
- const file = action.getString("F")?.asString() ?? "";
25992
- const d = action.get("D");
25774
+ const file = action.getString("F", this.registry.resolve.bind(this.registry))?.asString() ?? "";
25775
+ const d = action.get("D", this.registry.resolve.bind(this.registry));
25993
25776
  return {
25994
25777
  type: "gotoRemote",
25995
25778
  file,
@@ -26004,7 +25787,7 @@ var PDFLinkAnnotation = class extends PDFAnnotation {
26004
25787
  * Highlight mode when the link is clicked.
26005
25788
  */
26006
25789
  get highlightMode() {
26007
- switch (this.dict.getName("H")?.value) {
25790
+ switch (this.dict.getName("H", this.registry.resolve.bind(this.registry))?.value) {
26008
25791
  case "N": return "None";
26009
25792
  case "I": return "Invert";
26010
25793
  case "O": return "Outline";
@@ -26193,7 +25976,7 @@ var PDFUnknownAnnotation = class extends PDFAnnotation {};
26193
25976
  * @returns The appropriate annotation class instance
26194
25977
  */
26195
25978
  function createAnnotation(dict, ref, registry) {
26196
- const subtypeName = dict.getName("Subtype")?.value;
25979
+ const subtypeName = dict.getName("Subtype", registry.resolve.bind(registry))?.value;
26197
25980
  switch (isAnnotationSubtype(subtypeName) ? subtypeName : "Text") {
26198
25981
  case "Text": return new PDFTextAnnotation(dict, ref, registry);
26199
25982
  case "Link": return new PDFLinkAnnotation(dict, ref, registry);
@@ -26219,14 +26002,14 @@ function createAnnotation(dict, ref, registry) {
26219
26002
  /**
26220
26003
  * Check if an annotation is a Widget (form field).
26221
26004
  */
26222
- function isWidgetAnnotation(dict) {
26223
- return dict.getName("Subtype")?.value === "Widget";
26005
+ function isWidgetAnnotation(dict, registry) {
26006
+ return dict.getName("Subtype", registry?.resolve.bind(registry))?.value === "Widget";
26224
26007
  }
26225
26008
  /**
26226
26009
  * Check if an annotation is a Popup.
26227
26010
  */
26228
- function isPopupAnnotation(dict) {
26229
- return dict.getName("Subtype")?.value === "Popup";
26011
+ function isPopupAnnotation(dict, registry) {
26012
+ return dict.getName("Subtype", registry?.resolve.bind(registry))?.value === "Popup";
26230
26013
  }
26231
26014
 
26232
26015
  //#endregion
@@ -26274,19 +26057,14 @@ var AnnotationFlattener = class {
26274
26057
  * @returns Number of annotations flattened
26275
26058
  */
26276
26059
  flattenPage(pageDict, options = {}) {
26277
- let annotsEntry = pageDict.get("Annots");
26278
- if (!annotsEntry) return 0;
26279
- if (annotsEntry instanceof PdfRef) annotsEntry = this.registry.resolve(annotsEntry) ?? void 0;
26280
- let annots = annotsEntry instanceof PdfArray ? annotsEntry : null;
26060
+ let annots = pageDict.getArray("Annots", this.registry.resolve.bind(this.registry));
26281
26061
  if (!annots || annots.length === 0) return 0;
26282
- let resources = pageDict.get("Resources");
26283
- if (resources instanceof PdfRef) resources = this.registry.resolve(resources) ?? void 0;
26062
+ let resources = pageDict.get("Resources", this.registry.resolve.bind(this.registry));
26284
26063
  if (!(resources instanceof PdfDict)) {
26285
26064
  resources = new PdfDict();
26286
26065
  pageDict.set("Resources", resources);
26287
26066
  }
26288
- let xObjects = resources.get("XObject");
26289
- if (xObjects instanceof PdfRef) xObjects = this.registry.resolve(xObjects) ?? void 0;
26067
+ let xObjects = resources.get("XObject", this.registry.resolve.bind(this.registry));
26290
26068
  if (!(xObjects instanceof PdfDict)) {
26291
26069
  xObjects = new PdfDict();
26292
26070
  resources.set("XObject", xObjects);
@@ -26296,19 +26074,20 @@ var AnnotationFlattener = class {
26296
26074
  let xObjectIndex = 0;
26297
26075
  let flattenedCount = 0;
26298
26076
  for (let i = 0; i < annots.length; i++) {
26299
- const entry = annots.at(i);
26077
+ let entry = annots.at(i);
26300
26078
  if (!entry) continue;
26301
26079
  let annotDict = null;
26302
26080
  let annotRef = null;
26303
26081
  if (entry instanceof PdfRef) {
26304
26082
  annotRef = entry;
26305
- const resolved = this.registry.resolve(entry);
26306
- if (resolved instanceof PdfDict) annotDict = resolved;
26307
- } else if (entry instanceof PdfDict) annotDict = entry;
26083
+ entry = this.registry.resolve(entry) ?? void 0;
26084
+ }
26085
+ if (entry instanceof PdfDict) annotDict = entry;
26308
26086
  if (!annotDict) continue;
26309
26087
  if (isWidgetAnnotation(annotDict)) continue;
26310
26088
  if (isPopupAnnotation(annotDict)) continue;
26311
- const subtype = annotDict.getName("Subtype")?.value;
26089
+ const subtypeName = annotDict.getName("Subtype")?.value;
26090
+ const subtype = isAnnotationSubtype(subtypeName) ? subtypeName : null;
26312
26091
  if (!subtype) continue;
26313
26092
  if (subtype === "Link") {
26314
26093
  if (options.removeLinks) {
@@ -26417,9 +26196,7 @@ var AnnotationFlattener = class {
26417
26196
  * Get annotation rectangle as [x1, y1, x2, y2].
26418
26197
  */
26419
26198
  getAnnotationRect(annotDict) {
26420
- let rectArray = annotDict.get("Rect");
26421
- if (rectArray instanceof PdfRef) rectArray = this.registry.resolve(rectArray) ?? void 0;
26422
- let rect = rectArray instanceof PdfArray ? rectArray : null;
26199
+ const rect = annotDict.getArray("Rect", this.registry.resolve.bind(this.registry));
26423
26200
  if (!rect || rect.length < 4) return [
26424
26201
  0,
26425
26202
  0,
@@ -26481,7 +26258,7 @@ var AnnotationFlattener = class {
26481
26258
  * Get appearance BBox, with fallback.
26482
26259
  */
26483
26260
  getAppearanceBBox(appearance) {
26484
- const bbox = appearance.getArray("BBox");
26261
+ const bbox = appearance.getArray("BBox", this.registry.resolve.bind(this.registry));
26485
26262
  if (!bbox || bbox.length < 4) return [
26486
26263
  0,
26487
26264
  0,
@@ -26500,7 +26277,7 @@ var AnnotationFlattener = class {
26500
26277
  * Get the appearance stream's transformation matrix.
26501
26278
  */
26502
26279
  getAppearanceMatrix(appearance) {
26503
- const matrixArray = appearance.getArray("Matrix");
26280
+ const matrixArray = appearance.getArray("Matrix", this.registry.resolve.bind(this.registry));
26504
26281
  if (!matrixArray || matrixArray.length < 6) return Matrix.identity();
26505
26282
  const [a, b, c, d, e, f] = matrixArray.toArray().map((item) => item instanceof PdfNumber ? item.value : 0);
26506
26283
  return new Matrix(a ?? 0, b ?? 0, c ?? 0, d ?? 0, e ?? 0, f ?? 0);
@@ -26509,7 +26286,7 @@ var AnnotationFlattener = class {
26509
26286
  * Check if appearance stream has valid dimensions.
26510
26287
  */
26511
26288
  isVisibleAppearance(appearance) {
26512
- const bbox = appearance.getArray("BBox");
26289
+ const bbox = appearance.getArray("BBox", this.registry.resolve.bind(this.registry));
26513
26290
  if (!bbox || bbox.length < 4) return false;
26514
26291
  const [x1, y1, x2, y2] = bbox.toArray().map((item) => item instanceof PdfNumber ? item.value : 0);
26515
26292
  const width = Math.abs((x2 ?? 0) - (x1 ?? 0));
@@ -26525,6 +26302,8 @@ var AnnotationFlattener = class {
26525
26302
  }
26526
26303
  /**
26527
26304
  * Wrap existing page content in q...Q and append new content.
26305
+ *
26306
+ * @todo Consider using PDFPage API for this.
26528
26307
  */
26529
26308
  wrapAndAppendContent(page, newContent) {
26530
26309
  const existing = page.get("Contents");
@@ -26573,7 +26352,8 @@ var AnnotationFlattener = class {
26573
26352
  if (annotsEntry instanceof PdfRef) {
26574
26353
  const resolved = this.registry.resolve(annotsEntry);
26575
26354
  annots = resolved instanceof PdfArray ? resolved : void 0;
26576
- } else if (annotsEntry instanceof PdfArray) annots = annotsEntry;
26355
+ }
26356
+ if (annotsEntry instanceof PdfArray) annots = annotsEntry;
26577
26357
  if (!annots) return;
26578
26358
  const indicesToRemove = [];
26579
26359
  for (let i = 0; i < annots.length; i++) {
@@ -27755,17 +27535,10 @@ function parseDefaultConfig(dDict, resolve) {
27755
27535
  function hasLayers(ctx) {
27756
27536
  const catalog = ctx.catalog.getDict();
27757
27537
  if (!catalog) return false;
27758
- let ocProperties = catalog.get("OCProperties");
27759
- if (!ocProperties) return false;
27760
- let ocPropsDict = null;
27761
- if (ocProperties instanceof PdfRef) ocProperties = ctx.resolve(ocProperties) ?? void 0;
27762
- if (ocProperties instanceof PdfDict) ocPropsDict = ocProperties;
27538
+ const resolve = ctx.resolve.bind(ctx);
27539
+ const ocPropsDict = catalog.getDict("OCProperties", resolve);
27763
27540
  if (!ocPropsDict) return false;
27764
- let ocgs = ocPropsDict.get("OCGs");
27765
- if (!ocgs) return false;
27766
- let ocgsArray = null;
27767
- if (ocgs instanceof PdfRef) ocgs = ctx.resolve(ocgs) ?? void 0;
27768
- if (ocgs instanceof PdfArray) ocgsArray = ocgs;
27541
+ const ocgsArray = ocPropsDict.getArray("OCGs", resolve);
27769
27542
  if (!ocgsArray || ocgsArray.length === 0) return false;
27770
27543
  return true;
27771
27544
  }
@@ -27778,19 +27551,12 @@ function hasLayers(ctx) {
27778
27551
  function getLayers(ctx) {
27779
27552
  const catalog = ctx.catalog.getDict();
27780
27553
  if (!catalog) return [];
27781
- let ocProperties = catalog.get("OCProperties");
27782
- if (!ocProperties) return [];
27783
- let ocPropsDict = null;
27784
- if (ocProperties instanceof PdfRef) ocProperties = ctx.resolve(ocProperties) ?? void 0;
27785
- if (ocProperties instanceof PdfDict) ocPropsDict = ocProperties;
27554
+ const resolve = ctx.resolve.bind(ctx);
27555
+ const ocPropsDict = catalog.getDict("OCProperties", resolve);
27786
27556
  if (!ocPropsDict) return [];
27787
- let ocgs = ocPropsDict.get("OCGs");
27788
- if (!ocgs) return [];
27789
- let ocgsArray = null;
27790
- if (ocgs instanceof PdfRef) ocgs = ctx.resolve(ocgs) ?? void 0;
27791
- if (ocgs instanceof PdfArray) ocgsArray = ocgs;
27557
+ const ocgsArray = ocPropsDict.getArray("OCGs", resolve);
27792
27558
  if (!ocgsArray) return [];
27793
- const defaultConfig = parseDefaultConfig(ocPropsDict.get("D"), (ref) => ctx.resolve(ref));
27559
+ const defaultConfig = parseDefaultConfig(ocPropsDict.get("D"), resolve);
27794
27560
  const layers = [];
27795
27561
  for (const item of ocgsArray) {
27796
27562
  if (!(item instanceof PdfRef)) continue;
@@ -30954,7 +30720,7 @@ var DocumentParser = class {
30954
30720
  if (type?.value === "Page") {
30955
30721
  if (currentRef) pages.push(currentRef);
30956
30722
  } else if (type?.value === "Pages") {
30957
- const kids = nodeOrRef.getArray("Kids");
30723
+ const kids = nodeOrRef.getArray("Kids", getObject);
30958
30724
  if (kids) for (let i = 0; i < kids.length; i++) {
30959
30725
  const kid = kids.at(i);
30960
30726
  if (kid instanceof PdfRef) walkNode(kid);
@@ -31743,12 +31509,7 @@ function decodeFilename(str) {
31743
31509
  * @returns The stream if found, null if external reference or missing
31744
31510
  */
31745
31511
  function getEmbeddedFileStream(fileSpec, resolver) {
31746
- const efEntry = fileSpec.get("EF");
31747
- let ef = null;
31748
- if (efEntry instanceof PdfRef) {
31749
- const resolved = resolver(efEntry);
31750
- if (resolved instanceof PdfDict) ef = resolved;
31751
- } else if (efEntry instanceof PdfDict) ef = efEntry;
31512
+ const ef = fileSpec.getDict("EF", resolver);
31752
31513
  if (!ef) return null;
31753
31514
  const streamRef = ef.getRef("F") ?? ef.getRef("UF");
31754
31515
  if (!streamRef) return null;
@@ -31775,12 +31536,7 @@ function parseFileSpec(fileSpec, name, resolver) {
31775
31536
  if (desc) info.description = desc.asString();
31776
31537
  const subtype = stream.getName("Subtype");
31777
31538
  if (subtype) info.mimeType = subtype.value.replaceAll("#2F", "/").replaceAll("#20", " ");
31778
- const paramsEntry = stream.get("Params");
31779
- let params = null;
31780
- if (paramsEntry instanceof PdfRef) {
31781
- const resolved = resolver(paramsEntry);
31782
- if (resolved instanceof PdfDict) params = resolved;
31783
- } else if (paramsEntry instanceof PdfDict) params = paramsEntry;
31539
+ const params = stream.getDict("Params", resolver);
31784
31540
  if (params) {
31785
31541
  const size = params.getNumber("Size");
31786
31542
  if (size) info.size = size.value;
@@ -31838,22 +31594,6 @@ function createFileSpec(filename, embeddedFileRef, options = {}) {
31838
31594
  //#endregion
31839
31595
  //#region src/document/name-tree.ts
31840
31596
  /**
31841
- * PDF Name Tree implementation.
31842
- *
31843
- * Name trees are sorted key-value structures used for:
31844
- * - /EmbeddedFiles (attachments)
31845
- * - /Dests (named destinations)
31846
- * - /JavaScript (document-level scripts)
31847
- * - /AP (appearance streams)
31848
- *
31849
- * Structure:
31850
- * - Leaf nodes have /Names: [key1, value1, key2, value2, ...]
31851
- * - Intermediate nodes have /Kids: [ref1, ref2, ...]
31852
- * - Intermediate nodes have /Limits: [minKey, maxKey] for binary search
31853
- *
31854
- * @see PDF 1.7 spec section 7.9.6
31855
- */
31856
- /**
31857
31597
  * Maximum depth for tree traversal (prevents infinite loops on malformed PDFs).
31858
31598
  */
31859
31599
  const MAX_DEPTH = 10;
@@ -31907,12 +31647,7 @@ var NameTree = class {
31907
31647
  let found = false;
31908
31648
  while (lo$1 <= hi$1) {
31909
31649
  const mid = lo$1 + hi$1 >>> 1;
31910
- const kidRef = kids.at(mid);
31911
- if (!(kidRef instanceof PdfRef)) {
31912
- lo$1 = mid + 1;
31913
- continue;
31914
- }
31915
- const kid = this.resolver(kidRef);
31650
+ const kid = kids.at(mid, this.resolver);
31916
31651
  if (!(kid instanceof PdfDict)) {
31917
31652
  lo$1 = mid + 1;
31918
31653
  continue;
@@ -31955,16 +31690,10 @@ var NameTree = class {
31955
31690
  else if (cmp > 0) lo = mid + 1;
31956
31691
  else {
31957
31692
  const valueIndex = keyIndex + 1;
31958
- const value = names.at(valueIndex);
31959
- if (value instanceof PdfRef) return this.resolver(value);
31960
- return value ?? null;
31693
+ return names.at(valueIndex, this.resolver) ?? null;
31961
31694
  }
31962
31695
  }
31963
- for (let i = 0; i < names.length; i += 2) if (extractKey(names.at(i)) === key$1) {
31964
- const value = names.at(i + 1);
31965
- if (value instanceof PdfRef) return this.resolver(value);
31966
- return value ?? null;
31967
- }
31696
+ for (let i = 0; i < names.length; i += 2) if (extractKey(names.at(i)) === key$1) return names.at(i + 1, this.resolver) ?? null;
31968
31697
  return null;
31969
31698
  }
31970
31699
  /**
@@ -31991,15 +31720,17 @@ var NameTree = class {
31991
31720
  }
31992
31721
  if (node.has("Kids")) {
31993
31722
  const kids = node.getArray("Kids");
31994
- if (kids) for (const kidRef of kids) {
31995
- if (!(kidRef instanceof PdfRef)) continue;
31996
- const refKey$1 = `${kidRef.objectNumber}:${kidRef.generation}`;
31997
- if (visited.has(refKey$1)) {
31998
- console.warn(`NameTree: circular reference detected at ${refKey$1}`);
31999
- continue;
31723
+ if (kids) for (let i = 0; i < kids.length; i++) {
31724
+ const kidRef = kids.at(i);
31725
+ if (kidRef instanceof PdfRef) {
31726
+ const refKey$1 = `${kidRef.objectNumber}:${kidRef.generation}`;
31727
+ if (visited.has(refKey$1)) {
31728
+ console.warn(`NameTree: circular reference detected at ${refKey$1}`);
31729
+ continue;
31730
+ }
31731
+ visited.add(refKey$1);
32000
31732
  }
32001
- visited.add(refKey$1);
32002
- const kid = this.resolver(kidRef);
31733
+ const kid = kids.at(i, this.resolver);
32003
31734
  if (kid instanceof PdfDict) queue.push({
32004
31735
  node: kid,
32005
31736
  depth: depth + 1
@@ -32010,9 +31741,8 @@ var NameTree = class {
32010
31741
  if (names) for (let i = 0; i < names.length; i += 2) {
32011
31742
  const key$1 = extractKey(names.at(i));
32012
31743
  if (key$1 === null) continue;
32013
- let value = names.at(i + 1) ?? null;
32014
- if (value instanceof PdfRef) value = this.resolver(value);
32015
- if (value !== null && value !== void 0) yield [key$1, value];
31744
+ const value = names.at(i + 1, this.resolver);
31745
+ if (value !== void 0) yield [key$1, value];
32016
31746
  }
32017
31747
  }
32018
31748
  }
@@ -32279,9 +32009,7 @@ var PDFCatalog = class {
32279
32009
  * Get the /Names dictionary.
32280
32010
  */
32281
32011
  getNames() {
32282
- let namesEntry = this.dict.get("Names");
32283
- if (namesEntry instanceof PdfRef) namesEntry = this.registry.resolve(namesEntry) ?? void 0;
32284
- return namesEntry instanceof PdfDict ? namesEntry : null;
32012
+ return this.dict.getDict("Names", this.registry.resolve.bind(this.registry)) ?? null;
32285
32013
  }
32286
32014
  /**
32287
32015
  * Get or create the /Names dictionary.
@@ -32305,12 +32033,7 @@ var PDFCatalog = class {
32305
32033
  this._embeddedFilesTree = null;
32306
32034
  return null;
32307
32035
  }
32308
- const embeddedFilesEntry = names.get("EmbeddedFiles");
32309
- let embeddedFiles = null;
32310
- if (embeddedFilesEntry instanceof PdfRef) {
32311
- const resolved = this.registry.resolve(embeddedFilesEntry);
32312
- if (resolved instanceof PdfDict) embeddedFiles = resolved;
32313
- } else if (embeddedFilesEntry instanceof PdfDict) embeddedFiles = embeddedFilesEntry;
32036
+ const embeddedFiles = names.getDict("EmbeddedFiles", this.registry.resolve.bind(this.registry));
32314
32037
  if (!embeddedFiles) {
32315
32038
  this._embeddedFilesTree = null;
32316
32039
  return null;
@@ -32406,12 +32129,6 @@ var PDFContext = class {
32406
32129
  return this.registry.resolve(ref);
32407
32130
  }
32408
32131
  /**
32409
- * Get an object by reference (sync, only if already loaded).
32410
- */
32411
- getObject(ref) {
32412
- return this.registry.getObject(ref);
32413
- }
32414
- /**
32415
32132
  * Get the reference for an object.
32416
32133
  */
32417
32134
  getRef(obj) {
@@ -35010,14 +34727,7 @@ var PDFForm = class PDFForm {
35010
34727
  for (const pageRef of pageRefs) {
35011
34728
  const pageDict = this._ctx.registry.resolve(pageRef);
35012
34729
  if (!(pageDict instanceof PdfDict)) continue;
35013
- const annotsEntry = pageDict.get("Annots");
35014
- if (!annotsEntry) continue;
35015
- let annots = null;
35016
- if (annotsEntry instanceof PdfArray) annots = annotsEntry;
35017
- else if (annotsEntry instanceof PdfRef) {
35018
- const resolved = this._ctx.registry.resolve(annotsEntry);
35019
- if (resolved instanceof PdfArray) annots = resolved;
35020
- }
34730
+ const annots = pageDict.getArray("Annots", this._ctx.registry.resolve.bind(this._ctx.registry));
35021
34731
  if (!annots) continue;
35022
34732
  for (let i = annots.length - 1; i >= 0; i--) {
35023
34733
  const item = annots.at(i);
@@ -35978,49 +35688,28 @@ var DSSBuilder = class DSSBuilder {
35978
35688
  */
35979
35689
  static async fromCatalog(catalog, registry, options) {
35980
35690
  const builder = new DSSBuilder(registry, options);
35981
- const dssVal = catalog.get("DSS");
35982
- if (!dssVal) return builder;
35983
- let dss;
35984
- if (dssVal instanceof PdfDict) dss = dssVal;
35985
- else if (dssVal instanceof PdfRef) {
35986
- const resolved = registry.resolve(dssVal);
35987
- if (!(resolved instanceof PdfDict)) return builder;
35988
- dss = resolved;
35989
- } else return builder;
35691
+ const resolve = registry.resolve.bind(registry);
35692
+ const dss = catalog.getDict("DSS", resolve);
35693
+ if (!dss) return builder;
35990
35694
  await builder.loadExistingData(dss, "Certs", builder.certMap, builder.existingCertRefs);
35991
35695
  await builder.loadExistingData(dss, "OCSPs", builder.ocspMap, builder.existingOcspRefs);
35992
35696
  await builder.loadExistingData(dss, "CRLs", builder.crlMap, builder.existingCrlRefs);
35993
- const vriVal = dss.get("VRI");
35994
- if (vriVal) {
35995
- let vri;
35996
- if (vriVal instanceof PdfDict) vri = vriVal;
35997
- else if (vriVal instanceof PdfRef) {
35998
- const resolved = registry.resolve(vriVal);
35999
- if (!(resolved instanceof PdfDict)) return builder;
36000
- vri = resolved;
36001
- } else return builder;
36002
- for (const key$1 of vri.keys()) {
36003
- const entryVal = vri.get(key$1);
36004
- if (entryVal) {
36005
- let entry;
36006
- if (entryVal instanceof PdfDict) entry = entryVal;
36007
- else if (entryVal instanceof PdfRef) {
36008
- const resolved = registry.resolve(entryVal);
36009
- if (!(resolved instanceof PdfDict)) continue;
36010
- entry = resolved;
36011
- } else continue;
36012
- const certHashes = await builder.extractRefHashes(entry, "Cert", builder.certMap);
36013
- const ocspHashes = await builder.extractRefHashes(entry, "OCSP", builder.ocspMap);
36014
- const crlHashes = await builder.extractRefHashes(entry, "CRL", builder.crlMap);
36015
- let timestamp;
36016
- if (entry.get("TU") instanceof PdfString) timestamp = /* @__PURE__ */ new Date();
36017
- builder.vriEntries.set(key$1.value.toUpperCase(), {
36018
- certHashes,
36019
- ocspHashes,
36020
- crlHashes,
36021
- timestamp
36022
- });
36023
- }
35697
+ const vri = dss.getDict("VRI", resolve);
35698
+ if (vri) for (const key$1 of vri.keys()) {
35699
+ const entryVal = vri.get(key$1, resolve);
35700
+ const entry = entryVal instanceof PdfDict ? entryVal : null;
35701
+ if (entry) {
35702
+ const certHashes = await builder.extractRefHashes(entry, "Cert", builder.certMap);
35703
+ const ocspHashes = await builder.extractRefHashes(entry, "OCSP", builder.ocspMap);
35704
+ const crlHashes = await builder.extractRefHashes(entry, "CRL", builder.crlMap);
35705
+ let timestamp;
35706
+ if (entry.getString("TU", resolve)) timestamp = /* @__PURE__ */ new Date();
35707
+ builder.vriEntries.set(key$1.value.toUpperCase(), {
35708
+ certHashes,
35709
+ ocspHashes,
35710
+ crlHashes,
35711
+ timestamp
35712
+ });
36024
35713
  }
36025
35714
  }
36026
35715
  return builder;
@@ -36101,11 +35790,8 @@ var DSSBuilder = class DSSBuilder {
36101
35790
  * Load existing data from DSS array.
36102
35791
  */
36103
35792
  async loadExistingData(dss, key$1, dataMap, refMap) {
36104
- let arrayVal = dss.get(key$1);
36105
- if (!arrayVal) return;
36106
- let array;
36107
- if (arrayVal instanceof PdfRef) arrayVal = this.registry.resolve(arrayVal) ?? void 0;
36108
- if (arrayVal instanceof PdfArray) array = arrayVal;
35793
+ const resolve = this.registry.resolve.bind(this.registry);
35794
+ const array = dss.getArray(key$1, resolve);
36109
35795
  if (!array) return;
36110
35796
  for (const item of array) if (item instanceof PdfRef) {
36111
35797
  const stream = this.registry.resolve(item);
@@ -36125,10 +35811,8 @@ var DSSBuilder = class DSSBuilder {
36125
35811
  */
36126
35812
  async extractRefHashes(entry, key$1, dataMap) {
36127
35813
  const hashes = [];
36128
- let arrayVal = entry.get(key$1);
36129
- if (!arrayVal) return hashes;
36130
- if (arrayVal instanceof PdfRef) arrayVal = this.registry.resolve(arrayVal) ?? void 0;
36131
- const array = arrayVal instanceof PdfArray ? arrayVal : null;
35814
+ const resolve = this.registry.resolve.bind(this.registry);
35815
+ const array = entry.getArray(key$1, resolve);
36132
35816
  if (!array) return hashes;
36133
35817
  for (const item of array) if (item instanceof PdfRef) {
36134
35818
  const stream = this.registry.resolve(item);
@@ -38356,12 +38040,8 @@ var PDF = class PDF {
38356
38040
  */
38357
38041
  getOrCreateViewerPreferences() {
38358
38042
  const catalog = this.ctx.catalog.getDict();
38359
- const existing = catalog.get("ViewerPreferences");
38360
- if (existing instanceof PdfDict) return existing;
38361
- if (existing instanceof PdfRef) {
38362
- const resolved = this.ctx.registry.getObject(existing);
38363
- if (resolved instanceof PdfDict) return resolved;
38364
- }
38043
+ const existing = catalog.getDict("ViewerPreferences", this.ctx.resolve.bind(this.ctx));
38044
+ if (existing) return existing;
38365
38045
  const prefs = new PdfDict();
38366
38046
  catalog.set("ViewerPreferences", prefs);
38367
38047
  return prefs;
@@ -38412,24 +38092,9 @@ var PDF = class PDF {
38412
38092
  if (!ref) return null;
38413
38093
  const dict = this.ctx.resolve(ref);
38414
38094
  if (!(dict instanceof PdfDict)) return null;
38415
- this.ensurePageResourcesResolved(dict);
38416
38095
  return new PDFPage(ref, dict, index, this.ctx);
38417
38096
  }
38418
38097
  /**
38419
- * Ensure page resources are resolved (not a reference).
38420
- *
38421
- * Pages may have Resources as a PdfRef pointing to a shared resources dict.
38422
- * The sync getResources() method on PDFPage needs the actual dict, not a ref.
38423
- * This resolves the reference and replaces it in the page dict.
38424
- */
38425
- ensurePageResourcesResolved(pageDict) {
38426
- const resources = pageDict.get("Resources");
38427
- if (resources instanceof PdfRef) {
38428
- const resolved = this.ctx.resolve(resources);
38429
- if (resolved instanceof PdfDict) pageDict.set("Resources", resolved.clone());
38430
- }
38431
- }
38432
- /**
38433
38098
  * Add a new blank page.
38434
38099
  *
38435
38100
  * @param options - Page size, rotation, and insertion position
@@ -38614,14 +38279,12 @@ var PDF = class PDF {
38614
38279
  if (!srcPage) throw new RangeError(`Page index ${pageIndex} out of bounds`);
38615
38280
  const contentData = this.getPageContentData(source, srcPage);
38616
38281
  const copier = new ObjectCopier(source, this, { includeAnnotations: false });
38617
- let srcResources = srcPage.dict.get("Resources");
38618
- let resources = void 0;
38619
- if (srcResources instanceof PdfRef) srcResources = source.getObject(srcResources) ?? void 0;
38620
- if (srcResources instanceof PdfDict) {
38282
+ const srcResources = srcPage.dict.getDict("Resources", source.getObject.bind(source));
38283
+ let resources;
38284
+ if (srcResources) {
38621
38285
  const copied = await copier.copyObject(srcResources);
38622
- if (copied instanceof PdfDict) resources = copied;
38623
- }
38624
- if (!resources) resources = new PdfDict();
38286
+ resources = copied instanceof PdfDict ? copied : new PdfDict();
38287
+ } else resources = new PdfDict();
38625
38288
  const mediaBox = srcPage.getMediaBox();
38626
38289
  const formXObject = PdfStream.fromDict({
38627
38290
  Type: PdfName.of("XObject"),
@@ -38641,13 +38304,9 @@ var PDF = class PDF {
38641
38304
  * Get the concatenated content stream data from a page.
38642
38305
  */
38643
38306
  getPageContentData(source, page) {
38644
- const contents = page.dict.get("Contents");
38307
+ const contents = page.dict.get("Contents", source.getObject.bind(source));
38645
38308
  if (!contents) return new Uint8Array(0);
38646
- if (contents instanceof PdfRef) {
38647
- const stream = source.getObject(contents);
38648
- if (stream instanceof PdfStream) return stream.getDecodedData();
38649
- return new Uint8Array(0);
38650
- }
38309
+ if (contents instanceof PdfStream) return contents.getDecodedData();
38651
38310
  if (contents instanceof PdfArray) {
38652
38311
  const chunks = [];
38653
38312
  for (let i = 0; i < contents.length; i++) {
@@ -38669,7 +38328,6 @@ var PDF = class PDF {
38669
38328
  }
38670
38329
  return result;
38671
38330
  }
38672
- if (contents instanceof PdfStream) return contents.getDecodedData();
38673
38331
  return new Uint8Array(0);
38674
38332
  }
38675
38333
  /**