modern-pdf-lib 0.12.1 → 0.14.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.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_pdfPage = require('./pdfPage-BMGFx7Xd.cjs');
3
- const require_pdfCatalog = require('./pdfCatalog-y_XG8Hq1.cjs');
4
- const require_libdeflateWasm = require('./libdeflateWasm-DeU6cupL.cjs');
2
+ const require_pdfPage = require('./pdfPage-DBfdinTR.cjs');
3
+ const require_pdfCatalog = require('./pdfCatalog-COKoYQ8C.cjs');
4
+ const require_libdeflateWasm = require('./libdeflateWasm-OkNoqBnO.cjs');
5
5
  const require_fontSubset = require('./fontSubset-pFc8Dueu.cjs');
6
- const require_pngEmbed = require('./pngEmbed-1RWu6KsO.cjs');
6
+ const require_pngEmbed = require('./pngEmbed-OYyOe_W0.cjs');
7
7
  const require_fflateAdapter = require('./fflateAdapter-AHC_S3cb.cjs');
8
8
  let fflate = require("fflate");
9
9
 
@@ -200,20 +200,19 @@ var PdfWriter = class {
200
200
  */
201
201
  writeObjectStream(entries, xrefEntries) {
202
202
  const serializedObjects = [];
203
- new StringByteWriter();
204
203
  for (const entry of entries) {
205
204
  const objWriter = new StringByteWriter();
206
205
  entry.object.serialize(objWriter);
207
206
  serializedObjects.push(objWriter.toUint8Array());
208
207
  }
209
- let headerStr = "";
208
+ const headerParts = [];
210
209
  let dataOffset = 0;
211
210
  for (let i = 0; i < entries.length; i++) {
212
- if (i > 0) headerStr += " ";
213
- headerStr += `${entries[i].ref.objectNumber} ${dataOffset}`;
211
+ headerParts.push(`${entries[i].ref.objectNumber} ${dataOffset}`);
214
212
  dataOffset += serializedObjects[i].length;
215
213
  if (i < entries.length - 1) dataOffset += 1;
216
214
  }
215
+ const headerStr = headerParts.join(" ");
217
216
  const headerBytes = encoder$5.encode(headerStr + " ");
218
217
  const firstOffset = headerBytes.length;
219
218
  let totalDataLen = firstOffset;
@@ -3236,7 +3235,7 @@ function extractMetricsWasm(fontData) {
3236
3235
  * Tracks which glyphs have been used so that subsetting can be
3237
3236
  * performed at save time, and provides text measurement methods.
3238
3237
  *
3239
- * Create via {@link embedFont}.
3238
+ * Create via `PdfDocument.embedFont()`.
3240
3239
  */
3241
3240
  var EmbeddedFont = class {
3242
3241
  /** The raw font file bytes. */
@@ -3581,6 +3580,53 @@ function findTable(data, tag) {
3581
3580
  }
3582
3581
  }
3583
3582
 
3583
+ //#endregion
3584
+ //#region src/parser/parseError.ts
3585
+ /**
3586
+ * @module parser/parseError
3587
+ * Structured error class for PDF parsing failures.
3588
+ * @packageDocumentation
3589
+ */
3590
+ var PdfParseError = class extends Error {
3591
+ name = "PdfParseError";
3592
+ offset;
3593
+ expected;
3594
+ actual;
3595
+ hexContext;
3596
+ constructor(options) {
3597
+ const hexCtx = options.data ? formatHexContext(options.data, options.offset) : "";
3598
+ const parts = [options.message];
3599
+ if (options.expected) parts.push(` Expected: ${options.expected}`);
3600
+ if (options.actual) parts.push(` Got: ${options.actual}`);
3601
+ if (hexCtx) parts.push(` Context:\n${hexCtx}`);
3602
+ super(parts.join("\n"), options.cause ? { cause: options.cause } : void 0);
3603
+ this.offset = options.offset;
3604
+ this.expected = options.expected ?? "";
3605
+ this.actual = options.actual ?? "";
3606
+ this.hexContext = hexCtx;
3607
+ }
3608
+ };
3609
+ function formatHexContext(data, offset, windowSize = 16) {
3610
+ const start = Math.max(0, offset - windowSize);
3611
+ const end = Math.min(data.length, offset + windowSize);
3612
+ const slice = data.subarray(start, end);
3613
+ const hexParts = [];
3614
+ const asciiParts = [];
3615
+ for (let i = 0; i < slice.length; i++) {
3616
+ const byte = slice[i];
3617
+ const isErrorByte = start + i === offset;
3618
+ const hex = byte.toString(16).padStart(2, "0");
3619
+ hexParts.push(isErrorByte ? `[${hex}]` : ` ${hex} `);
3620
+ asciiParts.push(byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : ".");
3621
+ }
3622
+ return [
3623
+ ` Offset ${start}:`,
3624
+ ` Hex: ${hexParts.join("")}`,
3625
+ ` ASCII: ${asciiParts.join(" ")}`,
3626
+ ` Error at offset ${offset} (marked with [])`
3627
+ ].join("\n");
3628
+ }
3629
+
3584
3630
  //#endregion
3585
3631
  //#region src/parser/lexer.ts
3586
3632
  /**
@@ -3708,7 +3754,7 @@ const isDelimiter = /* @__PURE__ */ (() => {
3708
3754
  * `hexVal[b]` is the numeric value (0-15) of a hex character, or -1 if
3709
3755
  * the byte is not a valid hex digit.
3710
3756
  */
3711
- const hexVal = /* @__PURE__ */ (() => {
3757
+ const hexVal$1 = /* @__PURE__ */ (() => {
3712
3758
  const t = new Int8Array(256).fill(-1);
3713
3759
  for (let i = 0; i <= 9; i++) t[CH_0 + i] = i;
3714
3760
  for (let i = 0; i < 6; i++) {
@@ -3736,7 +3782,7 @@ const hexVal = /* @__PURE__ */ (() => {
3736
3782
  */
3737
3783
  var PdfLexer = class {
3738
3784
  /** The raw PDF bytes being tokenized. */
3739
- data;
3785
+ _data;
3740
3786
  /** Total length of the input (cached for hot loops). */
3741
3787
  len;
3742
3788
  /** Current read position (byte offset). */
@@ -3759,11 +3805,20 @@ var PdfLexer = class {
3759
3805
  * must not mutate it while the lexer is in use.
3760
3806
  */
3761
3807
  constructor(data) {
3762
- this.data = data;
3808
+ this._data = data;
3763
3809
  this.len = data.length;
3764
3810
  this.position = 0;
3765
3811
  }
3766
3812
  /**
3813
+ * Public accessor for the raw PDF byte buffer.
3814
+ *
3815
+ * This allows other parsers (e.g. object parser, xref parser) to
3816
+ * include hex-context dumps in structured error messages.
3817
+ */
3818
+ get rawData() {
3819
+ return this._data;
3820
+ }
3821
+ /**
3767
3822
  * Consume and return the next token.
3768
3823
  *
3769
3824
  * Returns a token with `type === TokenType.EOF` when the input is
@@ -3799,8 +3854,14 @@ var PdfLexer = class {
3799
3854
  * @throws If there are not enough bytes remaining.
3800
3855
  */
3801
3856
  readStreamData(length) {
3802
- if (this.position + length > this.len) throw new Error(`PdfLexer.readStreamData: requested ${length} bytes at offset ${this.position}, but only ${this.len - this.position} remain`);
3803
- const slice = this.data.subarray(this.position, this.position + length);
3857
+ if (this.position + length > this.len) throw new PdfParseError({
3858
+ message: `PdfLexer.readStreamData: requested ${length} bytes at offset ${this.position}, but only ${this.len - this.position} remain`,
3859
+ offset: this.position,
3860
+ expected: `${length} bytes available`,
3861
+ actual: `${this.len - this.position} bytes remaining`,
3862
+ data: this._data
3863
+ });
3864
+ const slice = this._data.subarray(this.position, this.position + length);
3804
3865
  this.position += length;
3805
3866
  return slice;
3806
3867
  }
@@ -3813,7 +3874,13 @@ var PdfLexer = class {
3813
3874
  * @throws If the offset is out of range.
3814
3875
  */
3815
3876
  seek(offset) {
3816
- if (offset < 0 || offset > this.len) throw new RangeError(`PdfLexer.seek: offset ${offset} is outside [0, ${this.len}]`);
3877
+ if (offset < 0 || offset > this.len) throw new PdfParseError({
3878
+ message: `PdfLexer.seek: offset ${offset} is outside [0, ${this.len}]`,
3879
+ offset,
3880
+ expected: `offset in range [0, ${this.len}]`,
3881
+ actual: `${offset}`,
3882
+ data: this._data
3883
+ });
3817
3884
  this.position = offset;
3818
3885
  this.peeked = null;
3819
3886
  }
@@ -3826,7 +3893,7 @@ var PdfLexer = class {
3826
3893
  */
3827
3894
  byteAt(offset) {
3828
3895
  if (offset < 0 || offset >= this.len) return -1;
3829
- return this.data[offset];
3896
+ return this._data[offset];
3830
3897
  }
3831
3898
  /**
3832
3899
  * Return the total length of the input buffer (in bytes).
@@ -3842,7 +3909,7 @@ var PdfLexer = class {
3842
3909
  * extracting stream data.
3843
3910
  */
3844
3911
  skipWhitespace() {
3845
- const d = this.data;
3912
+ const d = this._data;
3846
3913
  let pos = this.position;
3847
3914
  while (pos < this.len) {
3848
3915
  const b = d[pos];
@@ -3876,7 +3943,7 @@ var PdfLexer = class {
3876
3943
  value: null,
3877
3944
  offset: this.position
3878
3945
  };
3879
- const d = this.data;
3946
+ const d = this._data;
3880
3947
  const startPos = this.position;
3881
3948
  const b = d[startPos];
3882
3949
  if (b === CH_LBRACKET) {
@@ -3916,7 +3983,13 @@ var PdfLexer = class {
3916
3983
  };
3917
3984
  }
3918
3985
  this.position++;
3919
- throw new Error(`PdfLexer: unexpected '>' at offset ${startPos} (expected '>>' for dict end)`);
3986
+ throw new PdfParseError({
3987
+ message: `PdfLexer: unexpected '>' at offset ${startPos} (expected '>>' for dict end)`,
3988
+ offset: startPos,
3989
+ expected: "'>>' (dict end delimiter)",
3990
+ actual: "'>' (lone angle bracket)",
3991
+ data: this._data
3992
+ });
3920
3993
  }
3921
3994
  if (b === CH_LPAREN) return this.readLiteralString(startPos);
3922
3995
  if (b === CH_SLASH) return this.readName(startPos);
@@ -3931,7 +4004,7 @@ var PdfLexer = class {
3931
4004
  * `-.002`, `+.5`). Scientific notation is **not** permitted.
3932
4005
  */
3933
4006
  readNumber(startPos) {
3934
- const d = this.data;
4007
+ const d = this._data;
3935
4008
  let pos = startPos;
3936
4009
  let hasSign = false;
3937
4010
  let hasDot = false;
@@ -3975,10 +4048,10 @@ var PdfLexer = class {
3975
4048
  * parentheses.
3976
4049
  */
3977
4050
  readLiteralString(startPos) {
3978
- const d = this.data;
4051
+ const d = this._data;
3979
4052
  let pos = startPos + 1;
3980
4053
  let depth = 1;
3981
- let result = "";
4054
+ const parts = [];
3982
4055
  while (pos < this.len && depth > 0) {
3983
4056
  const c = d[pos];
3984
4057
  if (c === CH_BACKSLASH) {
@@ -3987,35 +4060,35 @@ var PdfLexer = class {
3987
4060
  const esc = d[pos];
3988
4061
  switch (esc) {
3989
4062
  case 110:
3990
- result += "\n";
4063
+ parts.push("\n");
3991
4064
  pos++;
3992
4065
  break;
3993
4066
  case 114:
3994
- result += "\r";
4067
+ parts.push("\r");
3995
4068
  pos++;
3996
4069
  break;
3997
4070
  case 116:
3998
- result += " ";
4071
+ parts.push(" ");
3999
4072
  pos++;
4000
4073
  break;
4001
4074
  case 98:
4002
- result += "\b";
4075
+ parts.push("\b");
4003
4076
  pos++;
4004
4077
  break;
4005
4078
  case 102:
4006
- result += "\f";
4079
+ parts.push("\f");
4007
4080
  pos++;
4008
4081
  break;
4009
4082
  case CH_LPAREN:
4010
- result += "(";
4083
+ parts.push("(");
4011
4084
  pos++;
4012
4085
  break;
4013
4086
  case CH_RPAREN:
4014
- result += ")";
4087
+ parts.push(")");
4015
4088
  pos++;
4016
4089
  break;
4017
4090
  case CH_BACKSLASH:
4018
- result += "\\";
4091
+ parts.push("\\");
4019
4092
  pos++;
4020
4093
  break;
4021
4094
  case WS_LF:
@@ -4037,9 +4110,9 @@ var PdfLexer = class {
4037
4110
  pos++;
4038
4111
  }
4039
4112
  }
4040
- result += String.fromCharCode(octal & 255);
4113
+ parts.push(String.fromCharCode(octal & 255));
4041
4114
  } else {
4042
- result += String.fromCharCode(esc);
4115
+ parts.push(String.fromCharCode(esc));
4043
4116
  pos++;
4044
4117
  }
4045
4118
  break;
@@ -4048,30 +4121,36 @@ var PdfLexer = class {
4048
4121
  }
4049
4122
  if (c === CH_LPAREN) {
4050
4123
  depth++;
4051
- result += "(";
4124
+ parts.push("(");
4052
4125
  pos++;
4053
4126
  continue;
4054
4127
  }
4055
4128
  if (c === CH_RPAREN) {
4056
4129
  depth--;
4057
- if (depth > 0) result += ")";
4130
+ if (depth > 0) parts.push(")");
4058
4131
  pos++;
4059
4132
  continue;
4060
4133
  }
4061
4134
  if (c === WS_CR) {
4062
- result += "\n";
4135
+ parts.push("\n");
4063
4136
  pos++;
4064
4137
  if (pos < this.len && d[pos] === WS_LF) pos++;
4065
4138
  continue;
4066
4139
  }
4067
- result += String.fromCharCode(c);
4140
+ parts.push(String.fromCharCode(c));
4068
4141
  pos++;
4069
4142
  }
4070
- if (depth !== 0) throw new Error(`PdfLexer: unterminated literal string starting at offset ${startPos}`);
4143
+ if (depth !== 0) throw new PdfParseError({
4144
+ message: `PdfLexer: unterminated literal string starting at offset ${startPos}`,
4145
+ offset: startPos,
4146
+ expected: "closing ')' for literal string",
4147
+ actual: "end of input",
4148
+ data: this._data
4149
+ });
4071
4150
  this.position = pos;
4072
4151
  return {
4073
4152
  type: TokenType$1.LiteralString,
4074
- value: result,
4153
+ value: parts.join(""),
4075
4154
  offset: startPos
4076
4155
  };
4077
4156
  }
@@ -4082,9 +4161,10 @@ var PdfLexer = class {
4082
4161
  * odd, a trailing `0` is assumed (per spec SS 7.3.4.3).
4083
4162
  */
4084
4163
  readHexString(startPos) {
4085
- const d = this.data;
4164
+ const d = this._data;
4086
4165
  let pos = startPos + 1;
4087
- let hex = "";
4166
+ const bytes = [];
4167
+ let hi = -1;
4088
4168
  while (pos < this.len) {
4089
4169
  const c = d[pos];
4090
4170
  if (c === CH_GT) {
@@ -4095,21 +4175,26 @@ var PdfLexer = class {
4095
4175
  pos++;
4096
4176
  continue;
4097
4177
  }
4098
- if (hexVal[c] === -1) throw new Error(`PdfLexer: invalid hex digit 0x${c.toString(16).padStart(2, "0")} at offset ${pos} in hex string starting at ${startPos}`);
4099
- hex += String.fromCharCode(c);
4178
+ const v = hexVal$1[c];
4179
+ if (v === -1) throw new PdfParseError({
4180
+ message: `PdfLexer: invalid hex digit 0x${c.toString(16).padStart(2, "0")} at offset ${pos} in hex string starting at ${startPos}`,
4181
+ offset: pos,
4182
+ expected: "hex digit (0-9, a-f, A-F)",
4183
+ actual: `0x${c.toString(16).padStart(2, "0")}`,
4184
+ data: this._data
4185
+ });
4186
+ if (hi === -1) hi = v;
4187
+ else {
4188
+ bytes.push(hi << 4 | v);
4189
+ hi = -1;
4190
+ }
4100
4191
  pos++;
4101
4192
  }
4102
- if (hex.length % 2 !== 0) hex += "0";
4103
- let result = "";
4104
- for (let i = 0; i < hex.length; i += 2) {
4105
- const hi = hexVal[hex.charCodeAt(i)];
4106
- const lo = hexVal[hex.charCodeAt(i + 1)];
4107
- result += String.fromCharCode(hi << 4 | lo);
4108
- }
4193
+ if (hi !== -1) bytes.push(hi << 4);
4109
4194
  this.position = pos;
4110
4195
  return {
4111
4196
  type: TokenType$1.HexString,
4112
- value: result,
4197
+ value: String.fromCharCode.apply(null, bytes),
4113
4198
  offset: startPos
4114
4199
  };
4115
4200
  }
@@ -4120,28 +4205,40 @@ var PdfLexer = class {
4120
4205
  * **includes** the leading `/`.
4121
4206
  */
4122
4207
  readName(startPos) {
4123
- const d = this.data;
4208
+ const d = this._data;
4124
4209
  let pos = startPos + 1;
4125
- let name = "/";
4210
+ const parts = ["/"];
4126
4211
  while (pos < this.len) {
4127
4212
  const c = d[pos];
4128
4213
  if (isWhitespace[c] || isDelimiter[c]) break;
4129
4214
  if (c === CH_HASH) {
4130
- if (pos + 2 >= this.len) throw new Error(`PdfLexer: incomplete #XX escape in name at offset ${pos}`);
4131
- const hi = hexVal[d[pos + 1]];
4132
- const lo = hexVal[d[pos + 2]];
4133
- if (hi === -1 || lo === -1) throw new Error(`PdfLexer: invalid #XX escape in name at offset ${pos}`);
4134
- name += String.fromCharCode(hi << 4 | lo);
4215
+ if (pos + 2 >= this.len) throw new PdfParseError({
4216
+ message: `PdfLexer: incomplete #XX escape in name at offset ${pos}`,
4217
+ offset: pos,
4218
+ expected: "two hex digits after # in name",
4219
+ actual: "end of input",
4220
+ data: this._data
4221
+ });
4222
+ const hi = hexVal$1[d[pos + 1]];
4223
+ const lo = hexVal$1[d[pos + 2]];
4224
+ if (hi === -1 || lo === -1) throw new PdfParseError({
4225
+ message: `PdfLexer: invalid #XX escape in name at offset ${pos}`,
4226
+ offset: pos,
4227
+ expected: "valid hex digits after # in name",
4228
+ actual: `#${String.fromCharCode(d[pos + 1])}${String.fromCharCode(d[pos + 2])}`,
4229
+ data: this._data
4230
+ });
4231
+ parts.push(String.fromCharCode(hi << 4 | lo));
4135
4232
  pos += 3;
4136
4233
  continue;
4137
4234
  }
4138
- name += String.fromCharCode(c);
4235
+ parts.push(String.fromCharCode(c));
4139
4236
  pos++;
4140
4237
  }
4141
4238
  this.position = pos;
4142
4239
  return {
4143
4240
  type: TokenType$1.Name,
4144
- value: name,
4241
+ value: parts.join(""),
4145
4242
  offset: startPos
4146
4243
  };
4147
4244
  }
@@ -4152,7 +4249,7 @@ var PdfLexer = class {
4152
4249
  * available for callers that want to preserve them.
4153
4250
  */
4154
4251
  readComment(startPos) {
4155
- const d = this.data;
4252
+ const d = this._data;
4156
4253
  let pos = startPos + 1;
4157
4254
  const begin = pos;
4158
4255
  while (pos < this.len) {
@@ -4177,7 +4274,7 @@ var PdfLexer = class {
4177
4274
  * handle them.
4178
4275
  */
4179
4276
  readKeyword(startPos) {
4180
- const d = this.data;
4277
+ const d = this._data;
4181
4278
  let pos = startPos;
4182
4279
  while (pos < this.len) {
4183
4280
  const c = d[pos];
@@ -4256,10 +4353,7 @@ var PdfLexer = class {
4256
4353
  * because it avoids the per-call overhead of the streaming decoder.
4257
4354
  */
4258
4355
  bytesToAscii(from, to) {
4259
- const d = this.data;
4260
- let s = "";
4261
- for (let i = from; i < to; i++) s += String.fromCharCode(d[i]);
4262
- return s;
4356
+ return String.fromCharCode.apply(null, this._data.subarray(from, to));
4263
4357
  }
4264
4358
  };
4265
4359
 
@@ -4332,13 +4426,31 @@ var PdfObjectParser = class {
4332
4426
  */
4333
4427
  parseIndirectObject() {
4334
4428
  const objNumToken = this.lexer.nextToken();
4335
- if (objNumToken.type !== TokenType$1.Number || !Number.isInteger(objNumToken.value)) throw new Error(`PdfObjectParser.parseIndirectObject: expected integer object number at offset ${objNumToken.offset}, got ${TokenType$1[objNumToken.type]} (${String(objNumToken.value)})`);
4429
+ if (objNumToken.type !== TokenType$1.Number || !Number.isInteger(objNumToken.value)) throw new PdfParseError({
4430
+ message: `PdfObjectParser.parseIndirectObject: expected integer object number at offset ${objNumToken.offset}, got ${TokenType$1[objNumToken.type]} (${String(objNumToken.value)})`,
4431
+ offset: objNumToken.offset,
4432
+ expected: "integer object number",
4433
+ actual: `${TokenType$1[objNumToken.type]} (${String(objNumToken.value)})`,
4434
+ data: this.lexer.rawData
4435
+ });
4336
4436
  const objNum = objNumToken.value;
4337
4437
  const genNumToken = this.lexer.nextToken();
4338
- if (genNumToken.type !== TokenType$1.Number || !Number.isInteger(genNumToken.value)) throw new Error(`PdfObjectParser.parseIndirectObject: expected integer generation number at offset ${genNumToken.offset}, got ${TokenType$1[genNumToken.type]} (${String(genNumToken.value)})`);
4438
+ if (genNumToken.type !== TokenType$1.Number || !Number.isInteger(genNumToken.value)) throw new PdfParseError({
4439
+ message: `PdfObjectParser.parseIndirectObject: expected integer generation number at offset ${genNumToken.offset}, got ${TokenType$1[genNumToken.type]} (${String(genNumToken.value)})`,
4440
+ offset: genNumToken.offset,
4441
+ expected: "integer generation number",
4442
+ actual: `${TokenType$1[genNumToken.type]} (${String(genNumToken.value)})`,
4443
+ data: this.lexer.rawData
4444
+ });
4339
4445
  const genNum = genNumToken.value;
4340
4446
  const objKw = this.lexer.nextToken();
4341
- if (objKw.type !== TokenType$1.ObjKeyword) throw new Error(`PdfObjectParser.parseIndirectObject: expected 'obj' keyword at offset ${objKw.offset}, got ${TokenType$1[objKw.type]} (${String(objKw.value)})`);
4447
+ if (objKw.type !== TokenType$1.ObjKeyword) throw new PdfParseError({
4448
+ message: `PdfObjectParser.parseIndirectObject: expected 'obj' keyword at offset ${objKw.offset}, got ${TokenType$1[objKw.type]} (${String(objKw.value)})`,
4449
+ offset: objKw.offset,
4450
+ expected: "'obj' keyword",
4451
+ actual: `${TokenType$1[objKw.type]} (${String(objKw.value)})`,
4452
+ data: this.lexer.rawData
4453
+ });
4342
4454
  return this.parseIndirectObjectBody(objNum, genNum);
4343
4455
  }
4344
4456
  /**
@@ -4383,8 +4495,20 @@ var PdfObjectParser = class {
4383
4495
  case TokenType$1.Name: return require_pdfCatalog.PdfName.of(token.value);
4384
4496
  case TokenType$1.ArrayStart: return this.parseArray();
4385
4497
  case TokenType$1.DictStart: return this.parseDictOrStream();
4386
- case TokenType$1.EOF: throw new Error(`PdfObjectParser: unexpected end of input at offset ${token.offset}`);
4387
- default: throw new Error(`PdfObjectParser: unexpected token ${TokenType$1[token.type]} (${String(token.value)}) at offset ${token.offset}`);
4498
+ case TokenType$1.EOF: throw new PdfParseError({
4499
+ message: `PdfObjectParser: unexpected end of input at offset ${token.offset}`,
4500
+ offset: token.offset,
4501
+ expected: "a PDF object (number, string, name, array, dict, etc.)",
4502
+ actual: "end of input",
4503
+ data: this.lexer.rawData
4504
+ });
4505
+ default: throw new PdfParseError({
4506
+ message: `PdfObjectParser: unexpected token ${TokenType$1[token.type]} (${String(token.value)}) at offset ${token.offset}`,
4507
+ offset: token.offset,
4508
+ expected: "a PDF object (number, string, name, array, dict, etc.)",
4509
+ actual: `${TokenType$1[token.type]} (${String(token.value)})`,
4510
+ data: this.lexer.rawData
4511
+ });
4388
4512
  }
4389
4513
  }
4390
4514
  /**
@@ -4430,7 +4554,13 @@ var PdfObjectParser = class {
4430
4554
  if (this.lexer.peekToken().type === TokenType$1.StreamKeyword) finalObject = this.readStream(object);
4431
4555
  }
4432
4556
  const endToken = this.lexer.nextToken();
4433
- if (endToken.type !== TokenType$1.EndObjKeyword) throw new Error(`PdfObjectParser: expected 'endobj' for object ${objNum} ${genNum} at offset ${endToken.offset}, got ${TokenType$1[endToken.type]} (${String(endToken.value)})`);
4557
+ if (endToken.type !== TokenType$1.EndObjKeyword) throw new PdfParseError({
4558
+ message: `PdfObjectParser: expected 'endobj' for object ${objNum} ${genNum} at offset ${endToken.offset}, got ${TokenType$1[endToken.type]} (${String(endToken.value)})`,
4559
+ offset: endToken.offset,
4560
+ expected: `'endobj' keyword for object ${objNum} ${genNum}`,
4561
+ actual: `${TokenType$1[endToken.type]} (${String(endToken.value)})`,
4562
+ data: this.lexer.rawData
4563
+ });
4434
4564
  this.registry.registerWithRef(ref, finalObject);
4435
4565
  return {
4436
4566
  ref,
@@ -4450,7 +4580,13 @@ var PdfObjectParser = class {
4450
4580
  this.lexer.nextToken();
4451
4581
  break;
4452
4582
  }
4453
- if (peek.type === TokenType$1.EOF) throw new Error(`PdfObjectParser: unterminated array at offset ${peek.offset}`);
4583
+ if (peek.type === TokenType$1.EOF) throw new PdfParseError({
4584
+ message: `PdfObjectParser: unterminated array at offset ${peek.offset}`,
4585
+ offset: peek.offset,
4586
+ expected: "']' to close array",
4587
+ actual: "end of input",
4588
+ data: this.lexer.rawData
4589
+ });
4454
4590
  items.push(this.parseObject());
4455
4591
  }
4456
4592
  return new require_pdfCatalog.PdfArray(items);
@@ -4479,9 +4615,21 @@ var PdfObjectParser = class {
4479
4615
  this.lexer.nextToken();
4480
4616
  break;
4481
4617
  }
4482
- if (peek.type === TokenType$1.EOF) throw new Error(`PdfObjectParser: unterminated dictionary at offset ${peek.offset}`);
4618
+ if (peek.type === TokenType$1.EOF) throw new PdfParseError({
4619
+ message: `PdfObjectParser: unterminated dictionary at offset ${peek.offset}`,
4620
+ offset: peek.offset,
4621
+ expected: "'>>' to close dictionary",
4622
+ actual: "end of input",
4623
+ data: this.lexer.rawData
4624
+ });
4483
4625
  const keyToken = this.lexer.nextToken();
4484
- if (keyToken.type !== TokenType$1.Name) throw new Error(`PdfObjectParser: expected name as dictionary key at offset ${keyToken.offset}, got ${TokenType$1[keyToken.type]} (${String(keyToken.value)})`);
4626
+ if (keyToken.type !== TokenType$1.Name) throw new PdfParseError({
4627
+ message: `PdfObjectParser: expected name as dictionary key at offset ${keyToken.offset}, got ${TokenType$1[keyToken.type]} (${String(keyToken.value)})`,
4628
+ offset: keyToken.offset,
4629
+ expected: "name token as dictionary key",
4630
+ actual: `${TokenType$1[keyToken.type]} (${String(keyToken.value)})`,
4631
+ data: this.lexer.rawData
4632
+ });
4485
4633
  const key = keyToken.value;
4486
4634
  const value = this.parseObject();
4487
4635
  dict.set(key, value);
@@ -4500,13 +4648,25 @@ var PdfObjectParser = class {
4500
4648
  */
4501
4649
  readStream(dict) {
4502
4650
  const streamKw = this.lexer.nextToken();
4503
- if (streamKw.type !== TokenType$1.StreamKeyword) throw new Error(`PdfObjectParser.readStream: expected 'stream' keyword at offset ${streamKw.offset}, got ${TokenType$1[streamKw.type]}`);
4651
+ if (streamKw.type !== TokenType$1.StreamKeyword) throw new PdfParseError({
4652
+ message: `PdfObjectParser.readStream: expected 'stream' keyword at offset ${streamKw.offset}, got ${TokenType$1[streamKw.type]}`,
4653
+ offset: streamKw.offset,
4654
+ expected: "'stream' keyword",
4655
+ actual: `${TokenType$1[streamKw.type]}`,
4656
+ data: this.lexer.rawData
4657
+ });
4504
4658
  this.skipStreamEol();
4505
4659
  const length = this.resolveStreamLength(dict);
4506
4660
  const data = this.lexer.readStreamData(length);
4507
4661
  this.skipEndstreamWhitespace();
4508
4662
  const endKw = this.lexer.nextToken();
4509
- if (endKw.type !== TokenType$1.EndStreamKeyword) throw new Error(`PdfObjectParser.readStream: expected 'endstream' keyword at offset ${endKw.offset}, got ${TokenType$1[endKw.type]} (${String(endKw.value)})`);
4663
+ if (endKw.type !== TokenType$1.EndStreamKeyword) throw new PdfParseError({
4664
+ message: `PdfObjectParser.readStream: expected 'endstream' keyword at offset ${endKw.offset}, got ${TokenType$1[endKw.type]} (${String(endKw.value)})`,
4665
+ offset: endKw.offset,
4666
+ expected: "'endstream' keyword",
4667
+ actual: `${TokenType$1[endKw.type]} (${String(endKw.value)})`,
4668
+ data: this.lexer.rawData
4669
+ });
4510
4670
  return new require_pdfCatalog.PdfStream(dict, data);
4511
4671
  }
4512
4672
  /**
@@ -4551,18 +4711,42 @@ var PdfObjectParser = class {
4551
4711
  */
4552
4712
  resolveStreamLength(dict) {
4553
4713
  const lengthObj = dict.get("/Length");
4554
- if (lengthObj === void 0) throw new Error("PdfObjectParser.resolveStreamLength: stream dictionary is missing /Length");
4714
+ if (lengthObj === void 0) throw new PdfParseError({
4715
+ message: "PdfObjectParser.resolveStreamLength: stream dictionary is missing /Length",
4716
+ offset: this.lexer.position,
4717
+ expected: "/Length entry in stream dictionary",
4718
+ actual: "no /Length entry",
4719
+ data: this.lexer.rawData
4720
+ });
4555
4721
  if (lengthObj.kind === "number") return lengthObj.value;
4556
4722
  if (lengthObj.kind === "ref") {
4557
4723
  const ref = lengthObj;
4558
4724
  const resolved = this.registry.resolve(ref);
4559
4725
  if (resolved !== void 0) {
4560
- if (resolved.kind !== "number") throw new Error(`PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R resolved to ${resolved.kind}, expected number`);
4726
+ if (resolved.kind !== "number") throw new PdfParseError({
4727
+ message: `PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R resolved to ${resolved.kind}, expected number`,
4728
+ offset: this.lexer.position,
4729
+ expected: "number for /Length reference",
4730
+ actual: `${resolved.kind}`,
4731
+ data: this.lexer.rawData
4732
+ });
4561
4733
  return resolved.value;
4562
4734
  }
4563
- throw new Error(`PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R is not yet resolved in the registry. Parse the referenced object first.`);
4735
+ throw new PdfParseError({
4736
+ message: `PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R is not yet resolved in the registry. Parse the referenced object first.`,
4737
+ offset: this.lexer.position,
4738
+ expected: "resolved /Length reference",
4739
+ actual: `unresolved reference ${ref.objectNumber} ${ref.generationNumber} R`,
4740
+ data: this.lexer.rawData
4741
+ });
4564
4742
  }
4565
- throw new Error(`PdfObjectParser.resolveStreamLength: /Length must be a number or indirect reference, got ${lengthObj.kind}`);
4743
+ throw new PdfParseError({
4744
+ message: `PdfObjectParser.resolveStreamLength: /Length must be a number or indirect reference, got ${lengthObj.kind}`,
4745
+ offset: this.lexer.position,
4746
+ expected: "number or indirect reference for /Length",
4747
+ actual: `${lengthObj.kind}`,
4748
+ data: this.lexer.rawData
4749
+ });
4566
4750
  }
4567
4751
  };
4568
4752
 
@@ -4643,10 +4827,10 @@ async function tryLoadLibdeflate() {
4643
4827
  if (libdeflateAttempted) return libdeflateEngine;
4644
4828
  libdeflateAttempted = true;
4645
4829
  try {
4646
- const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await Promise.resolve().then(() => require("./libdeflateWasm-DeU6cupL.cjs")).then((n) => n.libdeflateWasm_exports);
4830
+ const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await Promise.resolve().then(() => require("./libdeflateWasm-OkNoqBnO.cjs")).then((n) => n.libdeflateWasm_exports);
4647
4831
  let customBytes;
4648
4832
  try {
4649
- const { getWasmLoaderConfig } = await Promise.resolve().then(() => require("./loader-DWwMj8jZ.cjs"));
4833
+ const { getWasmLoaderConfig } = await Promise.resolve().then(() => require("./loader-_fqS-TmT.cjs"));
4650
4834
  customBytes = getWasmLoaderConfig().moduleBytes?.["libdeflate"];
4651
4835
  } catch {}
4652
4836
  await initDeflateWasm(customBytes);
@@ -4764,9 +4948,19 @@ function stringToLatin1Bytes(str) {
4764
4948
  */
4765
4949
  function extractTrailer(dict) {
4766
4950
  const sizeVal = numVal$2(dict.get("/Size"));
4767
- if (sizeVal === void 0) throw new Error("Invalid PDF: trailer dictionary missing /Size entry");
4951
+ if (sizeVal === void 0) throw new PdfParseError({
4952
+ message: "Invalid PDF: trailer dictionary missing /Size entry",
4953
+ offset: 0,
4954
+ expected: "/Size entry in trailer dictionary",
4955
+ actual: "no /Size entry"
4956
+ });
4768
4957
  const rootRef = refVal(dict.get("/Root"));
4769
- if (rootRef === void 0) throw new Error("Invalid PDF: trailer dictionary missing /Root entry");
4958
+ if (rootRef === void 0) throw new PdfParseError({
4959
+ message: "Invalid PDF: trailer dictionary missing /Root entry",
4960
+ offset: 0,
4961
+ expected: "/Root entry in trailer dictionary",
4962
+ actual: "no /Root entry"
4963
+ });
4770
4964
  const trailer = {
4771
4965
  size: sizeVal,
4772
4966
  rootRef
@@ -4805,7 +4999,12 @@ async function decodeStream$1(streamData, dict) {
4805
4999
  const arr = filter;
4806
5000
  if (arr.length > 0 && arr.items[0].kind === "name") filterName = arr.items[0].value;
4807
5001
  }
4808
- if (filterName !== "/FlateDecode") throw new Error(`Unsupported xref stream filter: ${filterName ?? "unknown"}. Only /FlateDecode is supported for cross-reference streams.`);
5002
+ if (filterName !== "/FlateDecode") throw new PdfParseError({
5003
+ message: `Unsupported xref stream filter: ${filterName ?? "unknown"}. Only /FlateDecode is supported for cross-reference streams.`,
5004
+ offset: 0,
5005
+ expected: "/FlateDecode filter",
5006
+ actual: `${filterName ?? "unknown"} filter`
5007
+ });
4809
5008
  let decompressed = await decompress(streamData);
4810
5009
  const decodeParms = dict.get("/DecodeParms");
4811
5010
  if (decodeParms !== void 0 && decodeParms.kind === "dict") {
@@ -4939,11 +5138,30 @@ var XrefParser = class {
4939
5138
  const startPos = this.data.length - searchWindow;
4940
5139
  const tail = TEXT_DECODER$1.decode(this.data.subarray(startPos, this.data.length));
4941
5140
  const idx = tail.lastIndexOf("startxref");
4942
- if (idx === -1) throw new Error("Invalid PDF: could not find \"startxref\" marker in the last 2048 bytes. The file may be truncated or corrupt.");
4943
- const match = tail.substring(idx + 9).trim().match(/^(\d+)/);
4944
- if (!match) throw new Error("Invalid PDF: \"startxref\" found but no valid offset follows it.");
5141
+ if (idx === -1) throw new PdfParseError({
5142
+ message: "Invalid PDF: could not find \"startxref\" marker in the last 2048 bytes. The file may be truncated or corrupt.",
5143
+ offset: startPos,
5144
+ expected: "\"startxref\" marker near end of file",
5145
+ actual: "no \"startxref\" found",
5146
+ data: this.data
5147
+ });
5148
+ const afterKeyword = tail.substring(idx + 9).trim();
5149
+ const match = afterKeyword.match(/^(\d+)/);
5150
+ if (!match) throw new PdfParseError({
5151
+ message: "Invalid PDF: \"startxref\" found but no valid offset follows it.",
5152
+ offset: startPos + idx,
5153
+ expected: "decimal offset after \"startxref\"",
5154
+ actual: `"${afterKeyword.substring(0, 20)}"`,
5155
+ data: this.data
5156
+ });
4945
5157
  const offset = parseInt(match[1], 10);
4946
- if (offset < 0 || offset >= this.data.length) throw new Error(`Invalid PDF: startxref offset ${offset} is out of range (file size: ${this.data.length}).`);
5158
+ if (offset < 0 || offset >= this.data.length) throw new PdfParseError({
5159
+ message: `Invalid PDF: startxref offset ${offset} is out of range (file size: ${this.data.length}).`,
5160
+ offset: startPos + idx,
5161
+ expected: `offset in range [0, ${this.data.length})`,
5162
+ actual: `${offset}`,
5163
+ data: this.data
5164
+ });
4947
5165
  return offset;
4948
5166
  }
4949
5167
  /**
@@ -4996,7 +5214,13 @@ var XrefParser = class {
4996
5214
  const prevVal = numVal$2(trailerDict.get("/Prev"));
4997
5215
  currentOffset = prevVal !== void 0 && prevVal >= 0 ? prevVal : void 0;
4998
5216
  }
4999
- if (primaryTrailer === void 0) throw new Error("Invalid PDF: could not extract a valid trailer from the cross-reference structure.");
5217
+ if (primaryTrailer === void 0) throw new PdfParseError({
5218
+ message: "Invalid PDF: could not extract a valid trailer from the cross-reference structure.",
5219
+ offset: startOffset,
5220
+ expected: "valid trailer dictionary in cross-reference structure",
5221
+ actual: "no valid trailer found",
5222
+ data: this.data
5223
+ });
5000
5224
  return {
5001
5225
  entries,
5002
5226
  trailer: primaryTrailer
@@ -5023,40 +5247,82 @@ var XrefParser = class {
5023
5247
  parseTraditionalXref(offset) {
5024
5248
  const entries = [];
5025
5249
  let pos = offset;
5026
- const xrefTag = TEXT_DECODER$1.decode(this.data.subarray(pos, pos + 4));
5027
- if (xrefTag !== "xref") throw new Error(`Invalid PDF: expected "xref" keyword at offset ${offset}, found "${xrefTag}".`);
5250
+ if (!this.isTraditionalXref(pos)) {
5251
+ const xrefTag = TEXT_DECODER$1.decode(this.data.subarray(pos, pos + 4));
5252
+ throw new PdfParseError({
5253
+ message: `Invalid PDF: expected "xref" keyword at offset ${offset}, found "${xrefTag}".`,
5254
+ offset,
5255
+ expected: "\"xref\" keyword",
5256
+ actual: `"${xrefTag}"`,
5257
+ data: this.data
5258
+ });
5259
+ }
5028
5260
  pos += 4;
5029
5261
  pos = this.skipWhitespaceAt(pos);
5030
5262
  while (pos < this.data.length) {
5031
- if (TEXT_DECODER$1.decode(this.data.subarray(pos, Math.min(pos + 7, this.data.length))).startsWith("trailer")) break;
5263
+ if (this.matchesBytes(pos, 116, 114, 97, 105, 108, 101, 114)) break;
5032
5264
  const headerLine = this.readLineAt(pos);
5033
5265
  const headerMatch = headerLine.text.trim().match(/^(\d+)\s+(\d+)/);
5034
- if (!headerMatch) throw new Error(`Invalid PDF: malformed xref subsection header at offset ${pos}: "${headerLine.text.trim()}"`);
5266
+ if (!headerMatch) throw new PdfParseError({
5267
+ message: `Invalid PDF: malformed xref subsection header at offset ${pos}: "${headerLine.text.trim()}"`,
5268
+ offset: pos,
5269
+ expected: "xref subsection header \"firstObjNum count\"",
5270
+ actual: `"${headerLine.text.trim()}"`,
5271
+ data: this.data
5272
+ });
5035
5273
  const firstObjNum = parseInt(headerMatch[1], 10);
5036
5274
  const count = parseInt(headerMatch[2], 10);
5037
5275
  pos = headerLine.nextPos;
5038
5276
  for (let i = 0; i < count; i++) {
5039
5277
  const objectNumber = firstObjNum + i;
5040
- const entryText = this.readXrefEntryAt(pos);
5041
- const entryMatch = entryText.text.trim().match(/^(\d{10})\s+(\d{5})\s+([fn])/);
5042
- if (!entryMatch) throw new Error(`Invalid PDF: malformed xref entry at offset ${pos} for object ${objectNumber}: "${entryText.text.trim()}"`);
5043
- const entryOffset = parseInt(entryMatch[1], 10);
5044
- const gen = parseInt(entryMatch[2], 10);
5045
- const marker = entryMatch[3];
5046
- entries.push({
5047
- objectNumber,
5048
- generationNumber: gen,
5049
- offset: entryOffset,
5050
- type: marker === "n" ? "in-use" : "free"
5051
- });
5052
- pos = entryText.nextPos;
5278
+ const parsed = this.parseXrefEntryDirect(pos);
5279
+ if (parsed) {
5280
+ entries.push({
5281
+ objectNumber,
5282
+ generationNumber: parsed.gen,
5283
+ offset: parsed.offset,
5284
+ type: parsed.type
5285
+ });
5286
+ pos = parsed.nextPos;
5287
+ } else {
5288
+ const entryText = this.readXrefEntryAt(pos);
5289
+ const entryMatch = entryText.text.trim().match(/^(\d{10})\s+(\d{5})\s+([fn])/);
5290
+ if (!entryMatch) throw new PdfParseError({
5291
+ message: `Invalid PDF: malformed xref entry at offset ${pos} for object ${objectNumber}: "${entryText.text.trim()}"`,
5292
+ offset: pos,
5293
+ expected: "xref entry \"OOOOOOOOOO GGGGG f/n\"",
5294
+ actual: `"${entryText.text.trim()}"`,
5295
+ data: this.data
5296
+ });
5297
+ entries.push({
5298
+ objectNumber,
5299
+ generationNumber: parseInt(entryMatch[2], 10),
5300
+ offset: parseInt(entryMatch[1], 10),
5301
+ type: entryMatch[3] === "n" ? "in-use" : "free"
5302
+ });
5303
+ pos = entryText.nextPos;
5304
+ }
5053
5305
  }
5054
5306
  }
5055
- const trailerTag = TEXT_DECODER$1.decode(this.data.subarray(pos, pos + 7));
5056
- if (trailerTag !== "trailer") throw new Error(`Invalid PDF: expected "trailer" keyword at offset ${pos}, found "${trailerTag}".`);
5307
+ if (!this.matchesBytes(pos, 116, 114, 97, 105, 108, 101, 114)) {
5308
+ const trailerTag = TEXT_DECODER$1.decode(this.data.subarray(pos, pos + 7));
5309
+ throw new PdfParseError({
5310
+ message: `Invalid PDF: expected "trailer" keyword at offset ${pos}, found "${trailerTag}".`,
5311
+ offset: pos,
5312
+ expected: "\"trailer\" keyword",
5313
+ actual: `"${trailerTag}"`,
5314
+ data: this.data
5315
+ });
5316
+ }
5057
5317
  pos += 7;
5058
5318
  const trailerObj = this.objectParser.parseObjectAt(pos);
5059
- if (trailerObj.kind !== "dict") throw new Error(`Invalid PDF: expected dictionary after "trailer" keyword at offset ${pos}, got ${trailerObj.kind}.`);
5319
+ if (trailerObj.kind !== "dict") throw new PdfParseError({
5320
+ message: `Invalid PDF: expected dictionary after "trailer" keyword at offset ${pos}, got ${trailerObj.kind}.`,
5321
+ offset: pos,
5322
+ expected: "dictionary after \"trailer\" keyword",
5323
+ actual: `${trailerObj.kind}`,
5324
+ data: this.data
5325
+ });
5060
5326
  return {
5061
5327
  entries,
5062
5328
  trailerDict: trailerObj
@@ -5075,22 +5341,58 @@ var XrefParser = class {
5075
5341
  */
5076
5342
  async parseXrefStream(offset) {
5077
5343
  const { object } = this.objectParser.parseIndirectObjectAt(offset);
5078
- if (object.kind !== "stream") throw new Error(`Invalid PDF: expected stream object at offset ${offset} for xref stream, got ${object.kind}.`);
5344
+ if (object.kind !== "stream") throw new PdfParseError({
5345
+ message: `Invalid PDF: expected stream object at offset ${offset} for xref stream, got ${object.kind}.`,
5346
+ offset,
5347
+ expected: "stream object for xref stream",
5348
+ actual: `${object.kind}`,
5349
+ data: this.data
5350
+ });
5079
5351
  const stream = object;
5080
5352
  const dict = stream.dict;
5081
5353
  const typeObj = dict.get("/Type");
5082
- if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/XRef") throw new Error(`Invalid PDF: cross-reference stream at offset ${offset} does not have /Type /XRef.`);
5354
+ if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/XRef") throw new PdfParseError({
5355
+ message: `Invalid PDF: cross-reference stream at offset ${offset} does not have /Type /XRef.`,
5356
+ offset,
5357
+ expected: "/Type /XRef in cross-reference stream dictionary",
5358
+ actual: typeObj ? `${typeObj.kind}` : "no /Type entry",
5359
+ data: this.data
5360
+ });
5083
5361
  const wObj = dict.get("/W");
5084
- if (wObj === void 0 || wObj.kind !== "array") throw new Error("Invalid PDF: cross-reference stream missing /W (field widths) array.");
5362
+ if (wObj === void 0 || wObj.kind !== "array") throw new PdfParseError({
5363
+ message: "Invalid PDF: cross-reference stream missing /W (field widths) array.",
5364
+ offset,
5365
+ expected: "/W array in cross-reference stream",
5366
+ actual: wObj ? `${wObj.kind}` : "no /W entry",
5367
+ data: this.data
5368
+ });
5085
5369
  const wArr = wObj;
5086
- if (wArr.length < 3) throw new Error("Invalid PDF: cross-reference stream /W array must have at least 3 elements.");
5370
+ if (wArr.length < 3) throw new PdfParseError({
5371
+ message: "Invalid PDF: cross-reference stream /W array must have at least 3 elements.",
5372
+ offset,
5373
+ expected: "/W array with at least 3 elements",
5374
+ actual: `/W array with ${wArr.length} element(s)`,
5375
+ data: this.data
5376
+ });
5087
5377
  const w0 = numVal$2(wArr.items[0]) ?? 0;
5088
5378
  const w1 = numVal$2(wArr.items[1]) ?? 0;
5089
5379
  const w2 = numVal$2(wArr.items[2]) ?? 0;
5090
5380
  const entryWidth = w0 + w1 + w2;
5091
- if (entryWidth === 0) throw new Error("Invalid PDF: cross-reference stream /W widths sum to 0.");
5381
+ if (entryWidth === 0) throw new PdfParseError({
5382
+ message: "Invalid PDF: cross-reference stream /W widths sum to 0.",
5383
+ offset,
5384
+ expected: "non-zero sum of /W widths",
5385
+ actual: "0",
5386
+ data: this.data
5387
+ });
5092
5388
  const size = numVal$2(dict.get("/Size"));
5093
- if (size === void 0) throw new Error("Invalid PDF: cross-reference stream missing /Size.");
5389
+ if (size === void 0) throw new PdfParseError({
5390
+ message: "Invalid PDF: cross-reference stream missing /Size.",
5391
+ offset,
5392
+ expected: "/Size entry in cross-reference stream",
5393
+ actual: "no /Size entry",
5394
+ data: this.data
5395
+ });
5094
5396
  let subsections;
5095
5397
  const indexObj = dict.get("/Index");
5096
5398
  if (indexObj !== void 0 && indexObj.kind === "array") {
@@ -5166,24 +5468,50 @@ var XrefParser = class {
5166
5468
  */
5167
5469
  rebuildXrefFromScan() {
5168
5470
  const entries = /* @__PURE__ */ new Map();
5169
- const fileText = TEXT_DECODER$1.decode(this.data);
5170
- const objPattern = /(\d+)\s+(\d+)\s+obj\b/g;
5171
- let match;
5172
- while ((match = objPattern.exec(fileText)) !== null) {
5173
- const objectNumber = parseInt(match[1], 10);
5174
- const gen = parseInt(match[2], 10);
5175
- const offset = match.index;
5471
+ const d = this.data;
5472
+ const len = d.length;
5473
+ for (let i = 0; i < len - 2; i++) {
5474
+ if (d[i] !== 111 || d[i + 1] !== 98 || d[i + 2] !== 106) continue;
5475
+ if (i + 3 < len) {
5476
+ const after = d[i + 3];
5477
+ if (after > 32 && after !== 37 && after !== 40 && after !== 41 && after !== 47 && after !== 60 && after !== 62 && after !== 91 && after !== 93 && after !== 123 && after !== 125) continue;
5478
+ }
5479
+ let j = i - 1;
5480
+ while (j >= 0 && (d[j] === 32 || d[j] === 10 || d[j] === 13 || d[j] === 9 || d[j] === 0)) j--;
5481
+ const genEnd = j + 1;
5482
+ while (j >= 0 && d[j] >= 48 && d[j] <= 57) j--;
5483
+ const genStart = j + 1;
5484
+ if (genStart >= genEnd) continue;
5485
+ while (j >= 0 && (d[j] === 32 || d[j] === 10 || d[j] === 13 || d[j] === 9 || d[j] === 0)) j--;
5486
+ const objEnd = j + 1;
5487
+ while (j >= 0 && d[j] >= 48 && d[j] <= 57) j--;
5488
+ const objStart = j + 1;
5489
+ if (objStart >= objEnd) continue;
5490
+ let objectNumber = 0;
5491
+ for (let k = objStart; k < objEnd; k++) objectNumber = objectNumber * 10 + (d[k] - 48);
5492
+ let gen = 0;
5493
+ for (let k = genStart; k < genEnd; k++) gen = gen * 10 + (d[k] - 48);
5176
5494
  entries.set(objectNumber, {
5177
5495
  objectNumber,
5178
5496
  generationNumber: gen,
5179
- offset,
5497
+ offset: objStart,
5180
5498
  type: "in-use"
5181
5499
  });
5182
5500
  }
5183
- if (entries.size === 0) throw new Error("Invalid PDF: could not find any indirect objects during recovery scan. The file may not be a valid PDF.");
5501
+ if (entries.size === 0) throw new PdfParseError({
5502
+ message: "Invalid PDF: could not find any indirect objects during recovery scan. The file may not be a valid PDF.",
5503
+ offset: 0,
5504
+ expected: "at least one \"N G obj\" pattern in file",
5505
+ actual: "no indirect objects found",
5506
+ data: this.data
5507
+ });
5184
5508
  let rootRef;
5185
5509
  let infoRef;
5186
- const trailerIdx = fileText.lastIndexOf("trailer");
5510
+ let trailerIdx = -1;
5511
+ for (let i = len - 7; i >= 0; i--) if (d[i] === 116 && d[i + 1] === 114 && d[i + 2] === 97 && d[i + 3] === 105 && d[i + 4] === 108 && d[i + 5] === 101 && d[i + 6] === 114) {
5512
+ trailerIdx = i;
5513
+ break;
5514
+ }
5187
5515
  if (trailerIdx !== -1) try {
5188
5516
  const trailerObj = this.objectParser.parseObjectAt(trailerIdx + 7);
5189
5517
  if (trailerObj.kind === "dict") {
@@ -5203,7 +5531,13 @@ var XrefParser = class {
5203
5531
  }
5204
5532
  }
5205
5533
  } catch {}
5206
- if (rootRef === void 0) throw new Error("Invalid PDF: recovery scan could not locate the document catalog (/Root). The file appears to be severely corrupt.");
5534
+ if (rootRef === void 0) throw new PdfParseError({
5535
+ message: "Invalid PDF: recovery scan could not locate the document catalog (/Root). The file appears to be severely corrupt.",
5536
+ offset: 0,
5537
+ expected: "document catalog (/Type /Catalog) in recovery scan",
5538
+ actual: "no /Root or /Catalog found",
5539
+ data: this.data
5540
+ });
5207
5541
  const trailer = {
5208
5542
  size: (entries.size > 0 ? entries.keys().reduce((max, n) => Math.max(max, n), 0) : 0) + 1,
5209
5543
  rootRef
@@ -5218,6 +5552,48 @@ var XrefParser = class {
5218
5552
  * Determine whether the data at the given offset starts with the
5219
5553
  * "xref" keyword (indicating a traditional xref table).
5220
5554
  */
5555
+ /**
5556
+ * Check if the bytes at `pos` match the given byte values.
5557
+ */
5558
+ matchesBytes(pos, ...bytes) {
5559
+ if (pos + bytes.length > this.data.length) return false;
5560
+ for (let i = 0; i < bytes.length; i++) if (this.data[pos + i] !== bytes[i]) return false;
5561
+ return true;
5562
+ }
5563
+ /**
5564
+ * Parse a standard xref entry directly from bytes, avoiding TextDecoder
5565
+ * and regex. Returns null if the bytes don't form a valid entry.
5566
+ *
5567
+ * Standard format: `OOOOOOOOOO GGGGG f/n` (18 significant bytes)
5568
+ */
5569
+ parseXrefEntryDirect(pos) {
5570
+ const d = this.data;
5571
+ if (pos + 18 > d.length) return null;
5572
+ let offset = 0;
5573
+ for (let k = 0; k < 10; k++) {
5574
+ const b = d[pos + k];
5575
+ if (b < 48 || b > 57) return null;
5576
+ offset = offset * 10 + (b - 48);
5577
+ }
5578
+ if (d[pos + 10] !== 32) return null;
5579
+ let gen = 0;
5580
+ for (let k = 0; k < 5; k++) {
5581
+ const b = d[pos + 11 + k];
5582
+ if (b < 48 || b > 57) return null;
5583
+ gen = gen * 10 + (b - 48);
5584
+ }
5585
+ if (d[pos + 16] !== 32) return null;
5586
+ const marker = d[pos + 17];
5587
+ if (marker !== 110 && marker !== 102) return null;
5588
+ let nextPos = pos + 18;
5589
+ while (nextPos < d.length && (d[nextPos] === 32 || d[nextPos] === 13 || d[nextPos] === 10)) nextPos++;
5590
+ return {
5591
+ offset,
5592
+ gen,
5593
+ type: marker === 110 ? "in-use" : "free",
5594
+ nextPos
5595
+ };
5596
+ }
5221
5597
  isTraditionalXref(offset) {
5222
5598
  if (offset + 4 > this.data.length) return false;
5223
5599
  return this.data[offset] === 120 && this.data[offset + 1] === 114 && this.data[offset + 2] === 101 && this.data[offset + 3] === 102;
@@ -6015,10 +6391,12 @@ function computeOwnerPasswordValue(ownerPassword, userPassword, revision, keyLen
6015
6391
  if (revision >= 3) for (let i = 0; i < 50; i++) hash = md5(hash.subarray(0, keyByteLength));
6016
6392
  const rc4Key = hash.subarray(0, keyByteLength);
6017
6393
  let encrypted = rc4(rc4Key, padPassword(userPassword));
6018
- if (revision >= 3) for (let i = 1; i <= 19; i++) {
6394
+ if (revision >= 3) {
6019
6395
  const modKey = new Uint8Array(rc4Key.length);
6020
- for (let j = 0; j < rc4Key.length; j++) modKey[j] = (rc4Key[j] ^ i) & 255;
6021
- encrypted = rc4(modKey, encrypted);
6396
+ for (let i = 1; i <= 19; i++) {
6397
+ for (let j = 0; j < rc4Key.length; j++) modKey[j] = (rc4Key[j] ^ i) & 255;
6398
+ encrypted = rc4(modKey, encrypted);
6399
+ }
6022
6400
  }
6023
6401
  return encrypted;
6024
6402
  }
@@ -6048,10 +6426,12 @@ function computeUserPasswordR2(fileKey) {
6048
6426
  */
6049
6427
  function computeUserPasswordR3R4(fileKey, fileId) {
6050
6428
  let encrypted = rc4(fileKey, md5(concat$1(PASSWORD_PADDING, fileId)));
6051
- for (let i = 1; i <= 19; i++) {
6429
+ {
6052
6430
  const modKey = new Uint8Array(fileKey.length);
6053
- for (let j = 0; j < fileKey.length; j++) modKey[j] = (fileKey[j] ^ i) & 255;
6054
- encrypted = rc4(modKey, encrypted);
6431
+ for (let i = 1; i <= 19; i++) {
6432
+ for (let j = 0; j < fileKey.length; j++) modKey[j] = (fileKey[j] ^ i) & 255;
6433
+ encrypted = rc4(modKey, encrypted);
6434
+ }
6055
6435
  }
6056
6436
  const result = new Uint8Array(32);
6057
6437
  result.set(encrypted.subarray(0, 16));
@@ -6117,9 +6497,17 @@ async function algorithm2B(password, salt, uKey) {
6117
6497
  let K = await sha256(uKey ? concat$1(password, salt, uKey) : concat$1(password, salt));
6118
6498
  let round = 0;
6119
6499
  while (true) {
6120
- const K1block = uKey ? concat$1(password, K, uKey) : concat$1(password, K);
6121
- const K1 = new Uint8Array(K1block.length * 64);
6122
- for (let i = 0; i < 64; i++) K1.set(K1block, i * K1block.length);
6500
+ const pLen = password.length;
6501
+ const kLen = K.length;
6502
+ const uLen = uKey ? uKey.length : 0;
6503
+ const blockLen = pLen + kLen + uLen;
6504
+ const K1 = new Uint8Array(blockLen * 64);
6505
+ for (let i = 0; i < 64; i++) {
6506
+ const base = i * blockLen;
6507
+ K1.set(password, base);
6508
+ K1.set(K, base + pLen);
6509
+ if (uKey) K1.set(uKey, base + pLen + kLen);
6510
+ }
6123
6511
  const E = await aesEncryptCBCNoPad(K.subarray(0, 16), K.subarray(16, 32), K1);
6124
6512
  let bigModVal = 0;
6125
6513
  for (let i = 0; i < 16; i++) bigModVal = (bigModVal * 256 + E[i]) % 3;
@@ -6916,7 +7304,13 @@ var PdfDocumentParser = class {
6916
7304
  * @param data The raw PDF file bytes as a Uint8Array.
6917
7305
  */
6918
7306
  constructor(data) {
6919
- if (data.length < 8) throw new Error("Invalid PDF: file is too short to contain a valid PDF header.");
7307
+ if (data.length < 8) throw new PdfParseError({
7308
+ message: "Invalid PDF: file is too short to contain a valid PDF header.",
7309
+ offset: 0,
7310
+ expected: "at least 8 bytes for a valid PDF header",
7311
+ actual: `${data.length} bytes`,
7312
+ data
7313
+ });
6920
7314
  this.data = data;
6921
7315
  }
6922
7316
  /**
@@ -6967,7 +7361,14 @@ var PdfDocumentParser = class {
6967
7361
  const { object } = this.objectParser.parseIndirectObjectAt(entry.offset);
6968
7362
  resolved = object;
6969
7363
  } catch (err) {
6970
- throw new Error(`Failed to parse indirect object ${objNum} ${entry.generationNumber} at offset ${entry.offset}`, { cause: err });
7364
+ throw new PdfParseError({
7365
+ message: `Failed to parse indirect object ${objNum} ${entry.generationNumber} at offset ${entry.offset}`,
7366
+ offset: entry.offset,
7367
+ expected: `valid indirect object ${objNum} ${entry.generationNumber}`,
7368
+ actual: "parse failure",
7369
+ data: this.data,
7370
+ cause: err instanceof Error ? err : void 0
7371
+ });
6971
7372
  }
6972
7373
  this.objectCache.set(objNum, resolved);
6973
7374
  return resolved;
@@ -6991,7 +7392,13 @@ var PdfDocumentParser = class {
6991
7392
  const encryptRef = this.trailer.encryptRef;
6992
7393
  this.encryptDictObjNum = encryptRef.objectNumber;
6993
7394
  const encryptObj = this.resolveRef(encryptRef);
6994
- if (encryptObj.kind !== "dict") throw new Error("Invalid PDF: /Encrypt entry is not a dictionary.");
7395
+ if (encryptObj.kind !== "dict") throw new PdfParseError({
7396
+ message: "Invalid PDF: /Encrypt entry is not a dictionary.",
7397
+ offset: 0,
7398
+ expected: "dictionary for /Encrypt entry",
7399
+ actual: `${encryptObj.kind}`,
7400
+ data: this.data
7401
+ });
6995
7402
  const encryptDict = encryptObj;
6996
7403
  const fileId = this.trailer.id?.[0] ?? new Uint8Array(0);
6997
7404
  const passwordsToTry = [];
@@ -7006,8 +7413,21 @@ var PdfDocumentParser = class {
7006
7413
  } catch (err) {
7007
7414
  lastError = err instanceof Error ? err : new Error(String(err));
7008
7415
  }
7009
- if (password !== void 0) throw new Error(`Failed to decrypt PDF: the provided password is incorrect. ${lastError?.message ?? ""}`);
7010
- else throw new Error("This PDF is encrypted and requires a password. Pass { password: \"...\" } in the options to decrypt it.");
7416
+ if (password !== void 0) throw new PdfParseError({
7417
+ message: `Failed to decrypt PDF: the provided password is incorrect. ${lastError?.message ?? ""}`,
7418
+ offset: 0,
7419
+ expected: "valid decryption password",
7420
+ actual: "incorrect password",
7421
+ data: this.data,
7422
+ cause: lastError
7423
+ });
7424
+ else throw new PdfParseError({
7425
+ message: "This PDF is encrypted and requires a password. Pass { password: \"...\" } in the options to decrypt it.",
7426
+ offset: 0,
7427
+ expected: "unencrypted PDF or password option",
7428
+ actual: "encrypted PDF without password",
7429
+ data: this.data
7430
+ });
7011
7431
  }
7012
7432
  /**
7013
7433
  * Decrypt all resolved objects in the object cache.
@@ -7103,7 +7523,12 @@ var PdfDocumentParser = class {
7103
7523
  * @throws If the page index is out of range.
7104
7524
  */
7105
7525
  getPageDict(pageIndex) {
7106
- if (pageIndex < 0 || pageIndex >= this.flattenedPages.length) throw new Error(`Page index ${pageIndex} is out of range. The document has ${this.flattenedPages.length} page(s).`);
7526
+ if (pageIndex < 0 || pageIndex >= this.flattenedPages.length) throw new PdfParseError({
7527
+ message: `Page index ${pageIndex} is out of range. The document has ${this.flattenedPages.length} page(s).`,
7528
+ offset: 0,
7529
+ expected: `page index in range [0, ${this.flattenedPages.length})`,
7530
+ actual: `${pageIndex}`
7531
+ });
7107
7532
  return this.flattenedPages[pageIndex].dict;
7108
7533
  }
7109
7534
  /**
@@ -7123,16 +7548,34 @@ var PdfDocumentParser = class {
7123
7548
  validateHeader() {
7124
7549
  const header = TEXT_DECODER.decode(this.data.subarray(0, Math.min(1024, this.data.length)));
7125
7550
  const pdfIdx = header.indexOf("%PDF-");
7126
- if (pdfIdx === -1 || pdfIdx > 1024) throw new Error("Invalid PDF: file does not start with \"%PDF-\" header. This may not be a PDF file.");
7551
+ if (pdfIdx === -1 || pdfIdx > 1024) throw new PdfParseError({
7552
+ message: "Invalid PDF: file does not start with \"%PDF-\" header. This may not be a PDF file.",
7553
+ offset: 0,
7554
+ expected: "\"%PDF-\" header near start of file",
7555
+ actual: "no \"%PDF-\" marker found",
7556
+ data: this.data
7557
+ });
7127
7558
  const versionMatch = header.substring(pdfIdx).match(/%PDF-(\d+\.\d+)/);
7128
- if (!versionMatch) throw new Error("Invalid PDF: could not parse version from header.");
7559
+ if (!versionMatch) throw new PdfParseError({
7560
+ message: "Invalid PDF: could not parse version from header.",
7561
+ offset: pdfIdx,
7562
+ expected: "\"%PDF-X.Y\" version string",
7563
+ actual: `"${header.substring(pdfIdx, pdfIdx + 10)}"`,
7564
+ data: this.data
7565
+ });
7129
7566
  this.pdfVersion = versionMatch[1];
7130
7567
  const majorMinor = this.pdfVersion.split(".");
7131
7568
  const major = parseInt(majorMinor[0], 10);
7132
7569
  const minor = parseInt(majorMinor[1], 10);
7133
7570
  if (major === 1 && minor >= 0 && minor <= 9) return;
7134
7571
  if (major === 2 && minor >= 0) return;
7135
- throw new Error(`Unsupported PDF version: ${this.pdfVersion}. Expected PDF 1.0-1.9 or 2.0+.`);
7572
+ throw new PdfParseError({
7573
+ message: `Unsupported PDF version: ${this.pdfVersion}. Expected PDF 1.0-1.9 or 2.0+.`,
7574
+ offset: 0,
7575
+ expected: "PDF version 1.0-1.9 or 2.0+",
7576
+ actual: `PDF version ${this.pdfVersion}`,
7577
+ data: this.data
7578
+ });
7136
7579
  }
7137
7580
  /**
7138
7581
  * Resolve the document catalog dictionary from the trailer's /Root
@@ -7140,12 +7583,24 @@ var PdfDocumentParser = class {
7140
7583
  */
7141
7584
  resolveCatalog() {
7142
7585
  const rootObj = this.resolveRef(this.trailer.rootRef);
7143
- if (rootObj.kind !== "dict") throw new Error(`Invalid PDF: /Root (catalog) at object ${this.trailer.rootRef.objectNumber} is not a dictionary (got ${rootObj.kind}).`);
7586
+ if (rootObj.kind !== "dict") throw new PdfParseError({
7587
+ message: `Invalid PDF: /Root (catalog) at object ${this.trailer.rootRef.objectNumber} is not a dictionary (got ${rootObj.kind}).`,
7588
+ offset: 0,
7589
+ expected: "dictionary for /Root (catalog)",
7590
+ actual: `${rootObj.kind}`,
7591
+ data: this.data
7592
+ });
7144
7593
  const catalog = rootObj;
7145
7594
  const typeObj = catalog.get("/Type");
7146
7595
  if (typeObj !== void 0 && typeObj.kind === "name") {
7147
7596
  const typeName = typeObj.value;
7148
- if (typeName !== "/Catalog") throw new Error(`Invalid PDF: /Root dictionary has /Type "${typeName}", expected "/Catalog".`);
7597
+ if (typeName !== "/Catalog") throw new PdfParseError({
7598
+ message: `Invalid PDF: /Root dictionary has /Type "${typeName}", expected "/Catalog".`,
7599
+ offset: 0,
7600
+ expected: "/Type /Catalog in /Root dictionary",
7601
+ actual: `/Type "${typeName}"`,
7602
+ data: this.data
7603
+ });
7149
7604
  }
7150
7605
  return catalog;
7151
7606
  }
@@ -7159,9 +7614,21 @@ var PdfDocumentParser = class {
7159
7614
  */
7160
7615
  resolvePageTree(catalog) {
7161
7616
  const pagesRef = catalog.get("/Pages");
7162
- if (pagesRef === void 0) throw new Error("Invalid PDF: catalog dictionary missing /Pages entry.");
7617
+ if (pagesRef === void 0) throw new PdfParseError({
7618
+ message: "Invalid PDF: catalog dictionary missing /Pages entry.",
7619
+ offset: 0,
7620
+ expected: "/Pages entry in catalog dictionary",
7621
+ actual: "no /Pages entry",
7622
+ data: this.data
7623
+ });
7163
7624
  const pagesObj = this.resolveObject(pagesRef);
7164
- if (pagesObj.kind !== "dict") throw new Error(`Invalid PDF: /Pages entry is not a dictionary (got ${pagesObj.kind}).`);
7625
+ if (pagesObj.kind !== "dict") throw new PdfParseError({
7626
+ message: `Invalid PDF: /Pages entry is not a dictionary (got ${pagesObj.kind}).`,
7627
+ offset: 0,
7628
+ expected: "dictionary for /Pages entry",
7629
+ actual: `${pagesObj.kind}`,
7630
+ data: this.data
7631
+ });
7165
7632
  const pages = [];
7166
7633
  this.traversePageTree(pagesObj, {}, pages, /* @__PURE__ */ new Set());
7167
7634
  return pages;
@@ -7198,7 +7665,13 @@ var PdfDocumentParser = class {
7198
7665
  }
7199
7666
  if (typeName === "/Page") {
7200
7667
  const mediaBox = currentInherited.mediaBox;
7201
- if (mediaBox === void 0) throw new Error("Invalid PDF: /Page node has no /MediaBox (not even inherited).");
7668
+ if (mediaBox === void 0) throw new PdfParseError({
7669
+ message: "Invalid PDF: /Page node has no /MediaBox (not even inherited).",
7670
+ offset: 0,
7671
+ expected: "/MediaBox on page node or inherited from parent",
7672
+ actual: "no /MediaBox found",
7673
+ data: this.data
7674
+ });
7202
7675
  result.push({
7203
7676
  dict: node,
7204
7677
  mediaBox,
@@ -7210,7 +7683,13 @@ var PdfDocumentParser = class {
7210
7683
  const kidsObj = node.get("/Kids");
7211
7684
  if (kidsObj === void 0) return;
7212
7685
  const kids = this.resolveObject(kidsObj);
7213
- if (kids.kind !== "array") throw new Error(`Invalid PDF: /Pages /Kids is not an array (got ${kids.kind}).`);
7686
+ if (kids.kind !== "array") throw new PdfParseError({
7687
+ message: `Invalid PDF: /Pages /Kids is not an array (got ${kids.kind}).`,
7688
+ offset: 0,
7689
+ expected: "array for /Pages /Kids",
7690
+ actual: `${kids.kind}`,
7691
+ data: this.data
7692
+ });
7214
7693
  const kidsArr = kids;
7215
7694
  for (let i = 0; i < kidsArr.length; i++) {
7216
7695
  const kidRef = kidsArr.items[i];
@@ -7246,22 +7725,53 @@ var PdfDocumentParser = class {
7246
7725
  return require_pdfCatalog.PdfNull.instance;
7247
7726
  }
7248
7727
  const containerEntry = this.xrefEntries.get(containerNum);
7249
- if (containerEntry === void 0 || containerEntry.type !== "in-use") throw new Error(`Invalid PDF: object stream ${containerNum} referenced by compressed object ${entry.objectNumber} not found in xref table.`);
7728
+ if (containerEntry === void 0 || containerEntry.type !== "in-use") throw new PdfParseError({
7729
+ message: `Invalid PDF: object stream ${containerNum} referenced by compressed object ${entry.objectNumber} not found in xref table.`,
7730
+ offset: 0,
7731
+ expected: `in-use xref entry for object stream ${containerNum}`,
7732
+ actual: containerEntry ? `${containerEntry.type} entry` : "no entry",
7733
+ data: this.data
7734
+ });
7250
7735
  let containerObj;
7251
7736
  try {
7252
7737
  const { object } = this.objectParser.parseIndirectObjectAt(containerEntry.offset);
7253
7738
  containerObj = object;
7254
7739
  } catch (err) {
7255
- throw new Error(`Failed to parse object stream ${containerNum} at offset ${containerEntry.offset}`, { cause: err });
7740
+ throw new PdfParseError({
7741
+ message: `Failed to parse object stream ${containerNum} at offset ${containerEntry.offset}`,
7742
+ offset: containerEntry.offset,
7743
+ expected: `valid object stream ${containerNum}`,
7744
+ actual: "parse failure",
7745
+ data: this.data,
7746
+ cause: err instanceof Error ? err : void 0
7747
+ });
7256
7748
  }
7257
- if (containerObj.kind !== "stream") throw new Error(`Invalid PDF: object ${containerNum} expected to be an object stream but is ${containerObj.kind}.`);
7749
+ if (containerObj.kind !== "stream") throw new PdfParseError({
7750
+ message: `Invalid PDF: object ${containerNum} expected to be an object stream but is ${containerObj.kind}.`,
7751
+ offset: containerEntry.offset,
7752
+ expected: "stream object for object stream",
7753
+ actual: `${containerObj.kind}`,
7754
+ data: this.data
7755
+ });
7258
7756
  const containerStream = containerObj;
7259
7757
  const containerDict = containerStream.dict;
7260
7758
  const typeObj = containerDict.get("/Type");
7261
- if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/ObjStm") throw new Error(`Invalid PDF: object ${containerNum} is not an object stream (/Type /ObjStm).`);
7759
+ if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/ObjStm") throw new PdfParseError({
7760
+ message: `Invalid PDF: object ${containerNum} is not an object stream (/Type /ObjStm).`,
7761
+ offset: containerEntry.offset,
7762
+ expected: "/Type /ObjStm in object stream dictionary",
7763
+ actual: typeObj ? `${typeObj.kind}` : "no /Type entry",
7764
+ data: this.data
7765
+ });
7262
7766
  const n = numVal$1(containerDict.get("/N"));
7263
7767
  const first = numVal$1(containerDict.get("/First"));
7264
- if (n === void 0 || first === void 0) throw new Error(`Invalid PDF: object stream ${containerNum} missing /N or /First entries.`);
7768
+ if (n === void 0 || first === void 0) throw new PdfParseError({
7769
+ message: `Invalid PDF: object stream ${containerNum} missing /N or /First entries.`,
7770
+ offset: containerEntry.offset,
7771
+ expected: "/N and /First entries in object stream",
7772
+ actual: `${n === void 0 ? "no /N" : "/N present"}, ${first === void 0 ? "no /First" : "/First present"}`,
7773
+ data: this.data
7774
+ });
7265
7775
  const decompressedData = this.decompressStreamSync(containerStream);
7266
7776
  const headerTokens = TEXT_DECODER.decode(decompressedData.subarray(0, first)).trim().split(/\s+/);
7267
7777
  const objEntries = [];
@@ -7658,7 +8168,7 @@ function undoPngPredictorSync(data, columns) {
7658
8168
  * string.
7659
8169
  *
7660
8170
  * This is the primary entry point for parsing existing PDFs. It creates
7661
- * a {@link PdfDocumentParser}, runs the full parse pipeline, and returns
8171
+ * a `PdfDocumentParser`, runs the full parse pipeline, and returns
7662
8172
  * a populated {@link PdfDocument}.
7663
8173
  *
7664
8174
  * @param data The PDF data as a `Uint8Array`, `ArrayBuffer`, or a
@@ -8149,7 +8659,17 @@ const NS_PDFAID = "http://www.aiim.org/pdfa/ns/id/";
8149
8659
  * @internal
8150
8660
  */
8151
8661
  function escapeXml(str) {
8152
- return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
8662
+ const parts = [];
8663
+ for (let i = 0; i < str.length; i++) {
8664
+ const c = str.charCodeAt(i);
8665
+ if (c === 38) parts.push("&amp;");
8666
+ else if (c === 60) parts.push("&lt;");
8667
+ else if (c === 62) parts.push("&gt;");
8668
+ else if (c === 34) parts.push("&quot;");
8669
+ else if (c === 39) parts.push("&apos;");
8670
+ else parts.push(str[i]);
8671
+ }
8672
+ return parts.join("");
8153
8673
  }
8154
8674
  /**
8155
8675
  * Format a Date as an ISO 8601 string for XMP.
@@ -9452,9 +9972,10 @@ function remapRef$1(sourceRef, context) {
9452
9972
  context.refMap.set(sourceRef.objectNumber, placeholderRef);
9453
9973
  return placeholderRef;
9454
9974
  }
9975
+ let streamHash;
9455
9976
  if (sourceObj.kind === "stream") {
9456
- const hash = hashBytes(sourceObj.data);
9457
- const dedup = context.hashMap.get(hash);
9977
+ streamHash = hashBytes(sourceObj.data);
9978
+ const dedup = context.hashMap.get(streamHash);
9458
9979
  if (dedup) {
9459
9980
  context.refMap.set(sourceRef.objectNumber, dedup);
9460
9981
  return dedup;
@@ -9464,10 +9985,7 @@ function remapRef$1(sourceRef, context) {
9464
9985
  context.refMap.set(sourceRef.objectNumber, targetRef);
9465
9986
  const clonedObj = deepClone$1(sourceObj, context);
9466
9987
  context.targetRegistry.assign(targetRef, clonedObj);
9467
- if (sourceObj.kind === "stream") {
9468
- const hash = hashBytes(sourceObj.data);
9469
- context.hashMap.set(hash, targetRef);
9470
- }
9988
+ if (streamHash !== void 0) context.hashMap.set(streamHash, targetRef);
9471
9989
  return targetRef;
9472
9990
  }
9473
9991
  /**
@@ -14046,7 +14564,6 @@ function read2DMode(reader) {
14046
14564
  if (bit === 1) {
14047
14565
  bit = reader.readBit();
14048
14566
  if (bit < 0) return Mode2D.EOL;
14049
- if (bit === 1) return Mode2D.HORIZONTAL;
14050
14567
  if (bit === 0) return Mode2D.VERTICAL_MINUS_1;
14051
14568
  return Mode2D.VERTICAL_PLUS_1;
14052
14569
  }
@@ -14212,6 +14729,9 @@ function packBits(pixels, columns, blackIs1) {
14212
14729
  /**
14213
14730
  * Decode JBIG2Decode stream data.
14214
14731
  *
14732
+ * Uses the pure-JS decoder (synchronous). For optional WASM
14733
+ * acceleration, use {@link decodeJBIG2Async}.
14734
+ *
14215
14735
  * @param data - The JBIG2-encoded content stream bytes.
14216
14736
  * @param parms - Optional `/DecodeParms` dictionary. May contain a
14217
14737
  * `/JBIG2Globals` key with a PdfDict/stream holding
@@ -17174,9 +17694,28 @@ function hexValue(ch) {
17174
17694
  * `~>` marks end-of-data.
17175
17695
  */
17176
17696
  function decodeASCII85(data) {
17177
- const result = [];
17178
- const group = [];
17697
+ let out = new Uint8Array(Math.max(data.length * 4 / 5 | 0, 256));
17698
+ let outPos = 0;
17699
+ const group = new Uint8Array(5);
17700
+ let groupLen = 0;
17179
17701
  let i = 0;
17702
+ function ensureOut(needed) {
17703
+ if (outPos + needed > out.length) {
17704
+ const newBuf = new Uint8Array(Math.max(out.length * 2, outPos + needed));
17705
+ newBuf.set(out.subarray(0, outPos));
17706
+ out = newBuf;
17707
+ }
17708
+ }
17709
+ function decodeGroup(count) {
17710
+ for (let k = count; k < 5; k++) group[k] = 84;
17711
+ const val = group[0] * 85 * 85 * 85 * 85 + group[1] * 85 * 85 * 85 + group[2] * 85 * 85 + group[3] * 85 + group[4];
17712
+ const numBytes = count === 5 ? 4 : count - 1;
17713
+ ensureOut(numBytes);
17714
+ if (numBytes >= 1) out[outPos++] = val >>> 24 & 255;
17715
+ if (numBytes >= 2) out[outPos++] = val >>> 16 & 255;
17716
+ if (numBytes >= 3) out[outPos++] = val >>> 8 & 255;
17717
+ if (numBytes >= 4) out[outPos++] = val & 255;
17718
+ }
17180
17719
  while (i < data.length) {
17181
17720
  const ch = data[i];
17182
17721
  if (ch === 126) break;
@@ -17185,8 +17724,12 @@ function decodeASCII85(data) {
17185
17724
  continue;
17186
17725
  }
17187
17726
  if (ch === 122) {
17188
- if (group.length > 0) throw new Error("ASCII85Decode: \"z\" inside a group");
17189
- result.push(0, 0, 0, 0);
17727
+ if (groupLen > 0) throw new Error("ASCII85Decode: \"z\" inside a group");
17728
+ ensureOut(4);
17729
+ out[outPos++] = 0;
17730
+ out[outPos++] = 0;
17731
+ out[outPos++] = 0;
17732
+ out[outPos++] = 0;
17190
17733
  i++;
17191
17734
  continue;
17192
17735
  }
@@ -17194,24 +17737,15 @@ function decodeASCII85(data) {
17194
17737
  i++;
17195
17738
  continue;
17196
17739
  }
17197
- group.push(ch - 33);
17198
- if (group.length === 5) {
17199
- const val = group[0] * 85 * 85 * 85 * 85 + group[1] * 85 * 85 * 85 + group[2] * 85 * 85 + group[3] * 85 + group[4];
17200
- result.push(val >>> 24 & 255, val >>> 16 & 255, val >>> 8 & 255, val & 255);
17201
- group.length = 0;
17740
+ group[groupLen++] = ch - 33;
17741
+ if (groupLen === 5) {
17742
+ decodeGroup(5);
17743
+ groupLen = 0;
17202
17744
  }
17203
17745
  i++;
17204
17746
  }
17205
- if (group.length >= 2) {
17206
- const origLen = group.length;
17207
- while (group.length < 5) group.push(84);
17208
- const val = group[0] * 85 * 85 * 85 * 85 + group[1] * 85 * 85 * 85 + group[2] * 85 * 85 + group[3] * 85 + group[4];
17209
- const numBytes = origLen - 1;
17210
- if (numBytes >= 1) result.push(val >>> 24 & 255);
17211
- if (numBytes >= 2) result.push(val >>> 16 & 255);
17212
- if (numBytes >= 3) result.push(val >>> 8 & 255);
17213
- }
17214
- return new Uint8Array(result);
17747
+ if (groupLen >= 2) decodeGroup(groupLen);
17748
+ return out.subarray(0, outPos);
17215
17749
  }
17216
17750
  /**
17217
17751
  * Decode an LZWDecode stream.
@@ -17231,6 +17765,10 @@ function decodeLZW(data, parms) {
17231
17765
  }
17232
17766
  /**
17233
17767
  * Core LZW decompression.
17768
+ *
17769
+ * Uses a flat pooled buffer for the code table instead of per-entry
17770
+ * Uint8Array allocations, and a pre-allocated output buffer with
17771
+ * manual growth instead of `number[]` + push.
17234
17772
  */
17235
17773
  function lzwDecompress(data, earlyChange) {
17236
17774
  const CLEAR_TABLE = 256;
@@ -17255,71 +17793,88 @@ function lzwDecompress(data, earlyChange) {
17255
17793
  }
17256
17794
  return result;
17257
17795
  }
17258
- let table = [];
17796
+ let tableBuf = new Uint8Array(65536);
17797
+ const tableOff = new Int32Array(4096);
17798
+ const tableLen = new Int32Array(4096);
17799
+ let tableBufUsed = 256;
17259
17800
  let codeSize = 9;
17260
17801
  let nextCode = 258;
17802
+ for (let i = 0; i < 256; i++) {
17803
+ tableBuf[i] = i;
17804
+ tableOff[i] = i;
17805
+ tableLen[i] = 1;
17806
+ }
17261
17807
  function resetTable() {
17262
- table = [];
17263
- for (let i = 0; i < 256; i++) table[i] = new Uint8Array([i]);
17264
- table[256] = new Uint8Array(0);
17265
- table[257] = new Uint8Array(0);
17808
+ tableBufUsed = 256;
17266
17809
  nextCode = 258;
17267
17810
  codeSize = 9;
17268
17811
  }
17269
- resetTable();
17270
- const output = [];
17271
- let prevEntry = null;
17812
+ let out = new Uint8Array(Math.max(data.length * 3, 4096));
17813
+ let outPos = 0;
17814
+ function ensureOut(needed) {
17815
+ if (outPos + needed > out.length) {
17816
+ const newBuf = new Uint8Array(Math.max(out.length * 2, outPos + needed));
17817
+ newBuf.set(out.subarray(0, outPos));
17818
+ out = newBuf;
17819
+ }
17820
+ }
17821
+ function ensureTable(needed) {
17822
+ if (tableBufUsed + needed > tableBuf.length) {
17823
+ const newBuf = new Uint8Array(Math.max(tableBuf.length * 2, tableBufUsed + needed));
17824
+ newBuf.set(tableBuf.subarray(0, tableBufUsed));
17825
+ tableBuf = newBuf;
17826
+ }
17827
+ }
17828
+ function writeEntry(code) {
17829
+ const off = tableOff[code];
17830
+ const len = tableLen[code];
17831
+ ensureOut(len);
17832
+ out.set(tableBuf.subarray(off, off + len), outPos);
17833
+ outPos += len;
17834
+ }
17835
+ function addEntry(prevCode, firstByte) {
17836
+ const prevOff = tableOff[prevCode];
17837
+ const prevLen = tableLen[prevCode];
17838
+ const newLen = prevLen + 1;
17839
+ ensureTable(newLen);
17840
+ tableBuf.set(tableBuf.subarray(prevOff, prevOff + prevLen), tableBufUsed);
17841
+ tableBuf[tableBufUsed + prevLen] = firstByte;
17842
+ tableOff[nextCode] = tableBufUsed;
17843
+ tableLen[nextCode] = newLen;
17844
+ tableBufUsed += newLen;
17845
+ nextCode++;
17846
+ }
17272
17847
  let code = readBits(codeSize);
17273
17848
  if (code === CLEAR_TABLE) {
17274
17849
  resetTable();
17275
17850
  code = readBits(codeSize);
17276
17851
  }
17277
- if (code === EOD) return new Uint8Array(output);
17278
- let entry = table[code];
17279
- if (entry) {
17280
- for (const b of entry) output.push(b);
17281
- prevEntry = entry;
17282
- }
17852
+ if (code === EOD) return new Uint8Array(0);
17853
+ writeEntry(code);
17854
+ let prevCode = code;
17283
17855
  while (true) {
17284
17856
  code = readBits(codeSize);
17285
17857
  if (code === EOD) break;
17286
17858
  if (code === CLEAR_TABLE) {
17287
17859
  resetTable();
17288
- prevEntry = null;
17289
17860
  code = readBits(codeSize);
17290
17861
  if (code === EOD) break;
17291
- entry = table[code];
17292
- if (entry) {
17293
- for (const b of entry) output.push(b);
17294
- prevEntry = entry;
17295
- }
17862
+ writeEntry(code);
17863
+ prevCode = code;
17296
17864
  continue;
17297
17865
  }
17298
- if (code < nextCode && table[code]) {
17299
- entry = table[code];
17300
- for (const b of entry) output.push(b);
17301
- if (prevEntry) {
17302
- const newEntry = new Uint8Array(prevEntry.length + 1);
17303
- newEntry.set(prevEntry);
17304
- newEntry[prevEntry.length] = entry[0];
17305
- table[nextCode] = newEntry;
17306
- nextCode++;
17307
- }
17866
+ if (code < nextCode) {
17867
+ writeEntry(code);
17868
+ addEntry(prevCode, tableBuf[tableOff[code]]);
17308
17869
  } else {
17309
- if (!prevEntry) throw new Error("LZWDecode: invalid code sequence");
17310
- const newEntry = new Uint8Array(prevEntry.length + 1);
17311
- newEntry.set(prevEntry);
17312
- newEntry[prevEntry.length] = prevEntry[0];
17313
- for (const b of newEntry) output.push(b);
17314
- table[nextCode] = newEntry;
17315
- nextCode++;
17316
- entry = newEntry;
17317
- }
17318
- prevEntry = entry;
17870
+ addEntry(prevCode, tableBuf[tableOff[prevCode]]);
17871
+ writeEntry(nextCode - 1);
17872
+ }
17873
+ prevCode = code;
17319
17874
  const threshold = (1 << codeSize) - earlyChange;
17320
17875
  if (nextCode >= threshold && codeSize < 12) codeSize++;
17321
17876
  }
17322
- return new Uint8Array(output);
17877
+ return out.subarray(0, outPos);
17323
17878
  }
17324
17879
  /**
17325
17880
  * Decode a RunLengthDecode stream.
@@ -17451,7 +18006,6 @@ function embedPageAsFormXObject(page, sourceRegistry, targetRegistry, xObjectNam
17451
18006
  const pageWidth = page.width;
17452
18007
  const pageHeight = page.height;
17453
18008
  const contentChunks = [];
17454
- new TextDecoder();
17455
18009
  const originalRefs = page.getOriginalContentRefs();
17456
18010
  for (const ref of originalRefs) {
17457
18011
  const obj = sourceRegistry.resolve(ref);
@@ -17536,6 +18090,93 @@ function embedPageAsFormXObject(page, sourceRegistry, targetRegistry, xObjectNam
17536
18090
  };
17537
18091
  }
17538
18092
 
18093
+ //#endregion
18094
+ //#region src/core/pdfDocumentEmbed.ts
18095
+ /**
18096
+ * @module core/pdfDocumentEmbed
18097
+ *
18098
+ * Pure helper functions for font CMap generation and image format
18099
+ * validation/parsing. Extracted from {@link pdfDocument} to keep the
18100
+ * PdfDocument class focused on high-level document management.
18101
+ */
18102
+ /**
18103
+ * Build a /ToUnicode CMap from a font's cmap table.
18104
+ * Maps glyph IDs (used as CIDs with Identity-H) to Unicode codepoints.
18105
+ *
18106
+ * @param cmapTable Mapping from Unicode codepoint to glyph ID.
18107
+ * @returns A CMap string suitable for a PDF /ToUnicode stream.
18108
+ */
18109
+ function buildToUnicodeCmap(cmapTable) {
18110
+ const gidToUnicode = /* @__PURE__ */ new Map();
18111
+ for (const [codepoint, gid] of cmapTable) if (!gidToUnicode.has(gid)) gidToUnicode.set(gid, codepoint);
18112
+ const entries = gidToUnicode.entries().toArray().sort((a, b) => a[0] - b[0]);
18113
+ const lines = [];
18114
+ lines.push("/CIDInit /ProcSet findresource begin");
18115
+ lines.push("12 dict begin");
18116
+ lines.push("begincmap");
18117
+ lines.push("/CIDSystemInfo");
18118
+ lines.push("<< /Registry (Adobe)");
18119
+ lines.push("/Ordering (UCS)");
18120
+ lines.push("/Supplement 0");
18121
+ lines.push(">> def");
18122
+ lines.push("/CMapName /Adobe-Identity-UCS def");
18123
+ lines.push("/CMapType 2 def");
18124
+ lines.push("1 begincodespacerange");
18125
+ lines.push("<0000> <FFFF>");
18126
+ lines.push("endcodespacerange");
18127
+ const CHUNK_SIZE = 100;
18128
+ for (let i = 0; i < entries.length; i += CHUNK_SIZE) {
18129
+ const chunk = entries.slice(i, i + CHUNK_SIZE);
18130
+ lines.push(`${chunk.length} beginbfchar`);
18131
+ for (const [gid, codepoint] of chunk) {
18132
+ const gidHex = gid.toString(16).padStart(4, "0").toUpperCase();
18133
+ const uniHex = codepoint.toString(16).padStart(4, "0").toUpperCase();
18134
+ lines.push(`<${gidHex}> <${uniHex}>`);
18135
+ }
18136
+ lines.push("endbfchar");
18137
+ }
18138
+ lines.push("endcmap");
18139
+ lines.push("CMapName currentdict /CMap defineresource pop");
18140
+ lines.push("end");
18141
+ lines.push("end");
18142
+ return lines.join("\n");
18143
+ }
18144
+ /**
18145
+ * Validate a JPEG file signature (SOI marker).
18146
+ *
18147
+ * @param data The raw file bytes.
18148
+ * @throws If the data is too short or the SOI marker is invalid.
18149
+ */
18150
+ function validateJpegSignature(data) {
18151
+ if (data.length < 2 || data[0] !== 255 || data[1] !== 216) throw new Error("Invalid JPEG: bad SOI marker");
18152
+ }
18153
+ /**
18154
+ * Parse width, height, and component count from a JPEG's SOF marker.
18155
+ *
18156
+ * @param data The raw JPEG file bytes.
18157
+ * @returns Width, height, and number of color components.
18158
+ */
18159
+ function parseJpegDimensions(data) {
18160
+ validateJpegSignature(data);
18161
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
18162
+ let offset = 2;
18163
+ while (offset < data.length - 1) {
18164
+ if (data[offset] !== 255) throw new Error("Invalid JPEG: expected marker");
18165
+ const marker = data[offset + 1];
18166
+ if (marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207) {
18167
+ const height = view.getUint16(offset + 5, false);
18168
+ return {
18169
+ width: view.getUint16(offset + 7, false),
18170
+ height,
18171
+ components: data[offset + 9]
18172
+ };
18173
+ }
18174
+ const segmentLength = view.getUint16(offset + 2, false);
18175
+ offset += 2 + segmentLength;
18176
+ }
18177
+ throw new Error("Invalid JPEG: SOF marker not found");
18178
+ }
18179
+
17539
18180
  //#endregion
17540
18181
  //#region src/core/pdfDocument.ts
17541
18182
  /**
@@ -17882,7 +18523,7 @@ var PdfDocument = class PdfDocument {
17882
18523
  async embedTrueTypeFont(fontData, options) {
17883
18524
  const embeddedFont = await embedFont(fontData);
17884
18525
  const metrics = embeddedFont.metrics;
17885
- const psName = options?.customName || metrics.postScriptName || metrics.familyName || "CustomFont";
18526
+ const psName = options?.customName ?? metrics.postScriptName ?? metrics.familyName ?? "CustomFont";
17886
18527
  const existing = this.embeddedFonts.get(`__ttf__${psName}`);
17887
18528
  if (existing) return existing;
17888
18529
  this.fontCounter++;
@@ -17939,7 +18580,7 @@ var PdfDocument = class PdfDocument {
17939
18580
  cidFontDict.set("/DW", require_pdfCatalog.PdfNumber.of(Math.round(metrics.defaultWidth * scale)));
17940
18581
  cidFontDict.set("/CIDToGIDMap", require_pdfCatalog.PdfName.of("Identity"));
17941
18582
  const cidFontRef = this.registry.register(cidFontDict);
17942
- const toUnicodeCmapStr = this.buildToUnicodeCmap(metrics.cmapTable);
18583
+ const toUnicodeCmapStr = buildToUnicodeCmap(metrics.cmapTable);
17943
18584
  const toUnicodeStream = require_pdfCatalog.PdfStream.fromString(toUnicodeCmapStr);
17944
18585
  const toUnicodeRef = this.registry.register(toUnicodeStream);
17945
18586
  const type0Dict = new require_pdfCatalog.PdfDict();
@@ -17997,7 +18638,7 @@ var PdfDocument = class PdfDocument {
17997
18638
  async embedCffFont(fontData, options) {
17998
18639
  const embeddedFont = await embedFont(fontData);
17999
18640
  const metrics = embeddedFont.metrics;
18000
- const psName = options?.customName || metrics.postScriptName || metrics.familyName || "CFFFont";
18641
+ const psName = options?.customName ?? metrics.postScriptName ?? metrics.familyName ?? "CFFFont";
18001
18642
  const existing = this.embeddedFonts.get(`__cff__${psName}`);
18002
18643
  if (existing) return existing;
18003
18644
  this.fontCounter++;
@@ -18056,7 +18697,7 @@ var PdfDocument = class PdfDocument {
18056
18697
  cidFontDict.set("/W", wArray);
18057
18698
  cidFontDict.set("/DW", require_pdfCatalog.PdfNumber.of(Math.round(metrics.defaultWidth * scale)));
18058
18699
  const cidFontRef = this.registry.register(cidFontDict);
18059
- const toUnicodeCmapStr = this.buildToUnicodeCmap(metrics.cmapTable);
18700
+ const toUnicodeCmapStr = buildToUnicodeCmap(metrics.cmapTable);
18060
18701
  const toUnicodeStream = require_pdfCatalog.PdfStream.fromString(toUnicodeCmapStr);
18061
18702
  const toUnicodeRef = this.registry.register(toUnicodeStream);
18062
18703
  const type0Dict = new require_pdfCatalog.PdfDict();
@@ -18102,46 +18743,6 @@ var PdfDocument = class PdfDocument {
18102
18743
  return fontRef;
18103
18744
  }
18104
18745
  /**
18105
- * Build a /ToUnicode CMap from the font's cmap table.
18106
- * Maps glyph IDs (used as CIDs with Identity-H) to Unicode codepoints.
18107
- * @internal
18108
- */
18109
- buildToUnicodeCmap(cmapTable) {
18110
- const gidToUnicode = /* @__PURE__ */ new Map();
18111
- for (const [codepoint, gid] of cmapTable) if (!gidToUnicode.has(gid)) gidToUnicode.set(gid, codepoint);
18112
- const entries = gidToUnicode.entries().toArray().sort((a, b) => a[0] - b[0]);
18113
- const lines = [];
18114
- lines.push("/CIDInit /ProcSet findresource begin");
18115
- lines.push("12 dict begin");
18116
- lines.push("begincmap");
18117
- lines.push("/CIDSystemInfo");
18118
- lines.push("<< /Registry (Adobe)");
18119
- lines.push("/Ordering (UCS)");
18120
- lines.push("/Supplement 0");
18121
- lines.push(">> def");
18122
- lines.push("/CMapName /Adobe-Identity-UCS def");
18123
- lines.push("/CMapType 2 def");
18124
- lines.push("1 begincodespacerange");
18125
- lines.push("<0000> <FFFF>");
18126
- lines.push("endcodespacerange");
18127
- const CHUNK_SIZE = 100;
18128
- for (let i = 0; i < entries.length; i += CHUNK_SIZE) {
18129
- const chunk = entries.slice(i, i + CHUNK_SIZE);
18130
- lines.push(`${chunk.length} beginbfchar`);
18131
- for (const [gid, codepoint] of chunk) {
18132
- const gidHex = gid.toString(16).padStart(4, "0").toUpperCase();
18133
- const uniHex = codepoint.toString(16).padStart(4, "0").toUpperCase();
18134
- lines.push(`<${gidHex}> <${uniHex}>`);
18135
- }
18136
- lines.push("endbfchar");
18137
- }
18138
- lines.push("endcmap");
18139
- lines.push("CMapName currentdict /CMap defineresource pop");
18140
- lines.push("end");
18141
- lines.push("end");
18142
- return lines.join("\n");
18143
- }
18144
- /**
18145
18746
  * Embed a PNG image.
18146
18747
  *
18147
18748
  * Fully decodes the PNG (including filter reconstruction and alpha
@@ -18327,7 +18928,7 @@ var PdfDocument = class PdfDocument {
18327
18928
  * @param pages Array of PdfPage instances to embed.
18328
18929
  * @returns Array of {@link EmbeddedPdfPage} handles, one per input page.
18329
18930
  */
18330
- async embedPages(pages) {
18931
+ embedPages(pages) {
18331
18932
  return pages.map((page) => this.embedPage(page));
18332
18933
  }
18333
18934
  /** Set the document title. */
@@ -18810,6 +19411,79 @@ var PdfDocument = class PdfDocument {
18810
19411
  addWatermark(this, options);
18811
19412
  }
18812
19413
  /**
19414
+ * Create a soft mask Form XObject that can be used with
19415
+ * {@link PdfPage.applySoftMask}.
19416
+ *
19417
+ * The builder callback receives a {@link SoftMaskBuilder} with methods
19418
+ * for generating grayscale content where white (`1`) represents fully
19419
+ * opaque regions and black (`0`) represents fully transparent regions.
19420
+ *
19421
+ * The returned {@link SoftMaskRef} is passed to
19422
+ * {@link PdfPage.applySoftMask} to activate the mask for subsequent
19423
+ * drawing operations on that page.
19424
+ *
19425
+ * @param width Width of the mask in points.
19426
+ * @param height Height of the mask in points.
19427
+ * @param builder Callback that draws the mask content.
19428
+ * @returns A reference to the soft mask Form XObject.
19429
+ *
19430
+ * @example
19431
+ * ```ts
19432
+ * const mask = doc.createSoftMask(200, 200, (b) => {
19433
+ * // White background = fully opaque
19434
+ * b.drawRectangle(0, 0, 200, 200, 1);
19435
+ * // Black circle = fully transparent hole
19436
+ * b.drawCircle(100, 100, 80, 0);
19437
+ * });
19438
+ * page.applySoftMask(mask);
19439
+ * page.drawRectangle({ x: 50, y: 50, width: 200, height: 200, color: rgb(1, 0, 0) });
19440
+ * page.clearSoftMask();
19441
+ * ```
19442
+ */
19443
+ createSoftMask(width, height, builder) {
19444
+ const maskOps = [];
19445
+ const kappa = .5522847498;
19446
+ builder({
19447
+ drawRectangle(x, y, w, h, gray) {
19448
+ maskOps.push(`${gray} g`);
19449
+ maskOps.push(`${x} ${y} ${w} ${h} re`);
19450
+ maskOps.push("f");
19451
+ },
19452
+ drawCircle(cx, cy, r, gray) {
19453
+ maskOps.push(`${gray} g`);
19454
+ const ox = r * kappa;
19455
+ const oy = r * kappa;
19456
+ maskOps.push(`${cx - r} ${cy} m`);
19457
+ maskOps.push(`${cx - r} ${cy + oy} ${cx - ox} ${cy + r} ${cx} ${cy + r} c`);
19458
+ maskOps.push(`${cx + ox} ${cy + r} ${cx + r} ${cy + oy} ${cx + r} ${cy} c`);
19459
+ maskOps.push(`${cx + r} ${cy - oy} ${cx + ox} ${cy - r} ${cx} ${cy - r} c`);
19460
+ maskOps.push(`${cx - ox} ${cy - r} ${cx - r} ${cy - oy} ${cx - r} ${cy} c`);
19461
+ maskOps.push("f");
19462
+ },
19463
+ pushRawOperators(ops) {
19464
+ maskOps.push(ops);
19465
+ }
19466
+ });
19467
+ const groupDict = new require_pdfCatalog.PdfDict();
19468
+ groupDict.set("/S", require_pdfCatalog.PdfName.of("Transparency"));
19469
+ groupDict.set("/CS", require_pdfCatalog.PdfName.of("DeviceGray"));
19470
+ const formDict = new require_pdfCatalog.PdfDict();
19471
+ formDict.set("/Type", require_pdfCatalog.PdfName.of("XObject"));
19472
+ formDict.set("/Subtype", require_pdfCatalog.PdfName.of("Form"));
19473
+ formDict.set("/BBox", require_pdfCatalog.PdfArray.fromNumbers([
19474
+ 0,
19475
+ 0,
19476
+ width,
19477
+ height
19478
+ ]));
19479
+ formDict.set("/Group", groupDict);
19480
+ const stream = require_pdfCatalog.PdfStream.fromString(maskOps.join("\n"), formDict);
19481
+ return {
19482
+ _tag: "softMask",
19483
+ ref: this.registry.register(stream)
19484
+ };
19485
+ }
19486
+ /**
18813
19487
  * Apply all pending redactions across all pages.
18814
19488
  *
18815
19489
  * Redaction marks are added to individual pages using
@@ -19044,30 +19718,6 @@ var PdfDocument = class PdfDocument {
19044
19718
  function createPdf() {
19045
19719
  return new PdfDocument();
19046
19720
  }
19047
- /**
19048
- * Parse width, height, and component count from a JPEG's SOF marker.
19049
- * @internal
19050
- */
19051
- function parseJpegDimensions(data) {
19052
- if (data.length < 2 || data[0] !== 255 || data[1] !== 216) throw new Error("Invalid JPEG: bad SOI marker");
19053
- const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
19054
- let offset = 2;
19055
- while (offset < data.length - 1) {
19056
- if (data[offset] !== 255) throw new Error("Invalid JPEG: expected marker");
19057
- const marker = data[offset + 1];
19058
- if (marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207) {
19059
- const height = view.getUint16(offset + 5, false);
19060
- return {
19061
- width: view.getUint16(offset + 7, false),
19062
- height,
19063
- components: data[offset + 9]
19064
- };
19065
- }
19066
- const segmentLength = view.getUint16(offset + 2, false);
19067
- offset += 2 + segmentLength;
19068
- }
19069
- throw new Error("Invalid JPEG: SOF marker not found");
19070
- }
19071
19721
 
19072
19722
  //#endregion
19073
19723
  //#region src/utils/pdfValueHelpers.ts
@@ -19810,8 +20460,8 @@ function compressStream(stream, level) {
19810
20460
  * @returns The incremental save result.
19811
20461
  */
19812
20462
  async function saveDocumentIncremental(originalBytes, doc, options) {
19813
- const { buildDocumentStructure } = await Promise.resolve().then(() => require("./pdfCatalog-y_XG8Hq1.cjs")).then((n) => n.pdfCatalog_exports);
19814
- const { PdfPage: _PdfPage } = await Promise.resolve().then(() => require("./pdfPage-BMGFx7Xd.cjs")).then((n) => n.pdfPage_exports);
20463
+ const { buildDocumentStructure } = await Promise.resolve().then(() => require("./pdfCatalog-COKoYQ8C.cjs")).then((n) => n.pdfCatalog_exports);
20464
+ const { PdfPage: _PdfPage } = await Promise.resolve().then(() => require("./pdfPage-DBfdinTR.cjs")).then((n) => n.pdfPage_exports);
19815
20465
  const registry = doc.getRegistry();
19816
20466
  const structure = buildDocumentStructure(doc.getInternalPages().map((p) => p.finalize()), {
19817
20467
  producer: doc.getProducer(),
@@ -21918,6 +22568,19 @@ var TokenType = /* @__PURE__ */ function(TokenType) {
21918
22568
  return TokenType;
21919
22569
  }(TokenType || {});
21920
22570
  /**
22571
+ * `hexVal[b]` is the numeric value (0-15) of a hex character, or -1 if
22572
+ * the byte is not a valid hex digit.
22573
+ */
22574
+ const hexVal = /* @__PURE__ */ (() => {
22575
+ const t = new Int8Array(256).fill(-1);
22576
+ for (let i = 0; i <= 9; i++) t[48 + i] = i;
22577
+ for (let i = 0; i < 6; i++) {
22578
+ t[65 + i] = 10 + i;
22579
+ t[97 + i] = 10 + i;
22580
+ }
22581
+ return t;
22582
+ })();
22583
+ /**
21921
22584
  * Combined lexer + parser for PDF content streams.
21922
22585
  *
21923
22586
  * Content streams are simpler than full PDF object syntax — there are no
@@ -22036,20 +22699,22 @@ var ContentStreamLexer = class {
22036
22699
  }
22037
22700
  const dataStart = this.pos;
22038
22701
  let dataEnd = this.pos;
22039
- while (this.pos < this.data.length) {
22040
- if (this.isWhitespace(this.data[this.pos])) {
22041
- const wsPos = this.pos;
22042
- let probe = wsPos + 1;
22043
- if (probe + 1 < this.data.length && this.data[probe] === 69 && this.data[probe + 1] === 73) {
22044
- const afterEI = probe + 2;
22045
- if (afterEI >= this.data.length || this.isWhitespace(this.data[afterEI])) {
22046
- dataEnd = wsPos;
22047
- this.pos = afterEI;
22048
- break;
22049
- }
22702
+ let searchFrom = this.pos;
22703
+ while (searchFrom < this.data.length) {
22704
+ const eIdx = this.data.indexOf(69, searchFrom);
22705
+ if (eIdx === -1 || eIdx + 1 >= this.data.length) {
22706
+ this.pos = this.data.length;
22707
+ break;
22708
+ }
22709
+ if (eIdx > dataStart && this.isWhitespace(this.data[eIdx - 1]) && this.data[eIdx + 1] === 73) {
22710
+ const afterEI = eIdx + 2;
22711
+ if (afterEI >= this.data.length || this.isWhitespace(this.data[afterEI])) {
22712
+ dataEnd = eIdx - 1;
22713
+ this.pos = afterEI;
22714
+ break;
22050
22715
  }
22051
22716
  }
22052
- this.pos++;
22717
+ searchFrom = eIdx + 1;
22053
22718
  }
22054
22719
  return {
22055
22720
  dict,
@@ -22117,7 +22782,7 @@ var ContentStreamLexer = class {
22117
22782
  */
22118
22783
  readLiteralString() {
22119
22784
  this.pos++;
22120
- let result = "";
22785
+ const parts = [];
22121
22786
  let depth = 1;
22122
22787
  while (this.pos < this.data.length && depth > 0) {
22123
22788
  const ch = this.data[this.pos];
@@ -22127,35 +22792,35 @@ var ContentStreamLexer = class {
22127
22792
  const esc = this.data[this.pos];
22128
22793
  switch (esc) {
22129
22794
  case 110:
22130
- result += "\n";
22795
+ parts.push("\n");
22131
22796
  this.pos++;
22132
22797
  break;
22133
22798
  case 114:
22134
- result += "\r";
22799
+ parts.push("\r");
22135
22800
  this.pos++;
22136
22801
  break;
22137
22802
  case 116:
22138
- result += " ";
22803
+ parts.push(" ");
22139
22804
  this.pos++;
22140
22805
  break;
22141
22806
  case 98:
22142
- result += "\b";
22807
+ parts.push("\b");
22143
22808
  this.pos++;
22144
22809
  break;
22145
22810
  case 102:
22146
- result += "\f";
22811
+ parts.push("\f");
22147
22812
  this.pos++;
22148
22813
  break;
22149
22814
  case 40:
22150
- result += "(";
22815
+ parts.push("(");
22151
22816
  this.pos++;
22152
22817
  break;
22153
22818
  case 41:
22154
- result += ")";
22819
+ parts.push(")");
22155
22820
  this.pos++;
22156
22821
  break;
22157
22822
  case 92:
22158
- result += "\\";
22823
+ parts.push("\\");
22159
22824
  this.pos++;
22160
22825
  break;
22161
22826
  case 10:
@@ -22183,29 +22848,29 @@ var ContentStreamLexer = class {
22183
22848
  }
22184
22849
  }
22185
22850
  }
22186
- result += String.fromCharCode(octal & 255);
22851
+ parts.push(String.fromCharCode(octal & 255));
22187
22852
  } else {
22188
- result += String.fromCharCode(esc);
22853
+ parts.push(String.fromCharCode(esc));
22189
22854
  this.pos++;
22190
22855
  }
22191
22856
  break;
22192
22857
  }
22193
22858
  } else if (ch === 40) {
22194
22859
  depth++;
22195
- result += "(";
22860
+ parts.push("(");
22196
22861
  this.pos++;
22197
22862
  } else if (ch === 41) {
22198
22863
  depth--;
22199
- if (depth > 0) result += ")";
22864
+ if (depth > 0) parts.push(")");
22200
22865
  this.pos++;
22201
22866
  } else {
22202
- result += String.fromCharCode(ch);
22867
+ parts.push(String.fromCharCode(ch));
22203
22868
  this.pos++;
22204
22869
  }
22205
22870
  }
22206
22871
  return {
22207
22872
  type: TokenType.String,
22208
- value: result
22873
+ value: parts.join("")
22209
22874
  };
22210
22875
  }
22211
22876
  /**
@@ -22213,7 +22878,8 @@ var ContentStreamLexer = class {
22213
22878
  */
22214
22879
  readHexString() {
22215
22880
  this.pos++;
22216
- let hex = "";
22881
+ const bytes = [];
22882
+ let hi = -1;
22217
22883
  while (this.pos < this.data.length) {
22218
22884
  const ch = this.data[this.pos];
22219
22885
  if (ch === 62) {
@@ -22224,18 +22890,22 @@ var ContentStreamLexer = class {
22224
22890
  this.pos++;
22225
22891
  continue;
22226
22892
  }
22227
- hex += String.fromCharCode(ch);
22893
+ const v = hexVal[ch];
22894
+ if (v === -1) {
22895
+ this.pos++;
22896
+ continue;
22897
+ }
22898
+ if (hi === -1) hi = v;
22899
+ else {
22900
+ bytes.push(hi << 4 | v);
22901
+ hi = -1;
22902
+ }
22228
22903
  this.pos++;
22229
22904
  }
22230
- if (hex.length % 2 !== 0) hex += "0";
22231
- let result = "";
22232
- for (let i = 0; i < hex.length; i += 2) {
22233
- const byte = parseInt(hex.substring(i, i + 2), 16);
22234
- if (!isNaN(byte)) result += String.fromCharCode(byte);
22235
- }
22905
+ if (hi !== -1) bytes.push(hi << 4);
22236
22906
  return {
22237
22907
  type: TokenType.HexString,
22238
- value: result
22908
+ value: String.fromCharCode.apply(null, bytes)
22239
22909
  };
22240
22910
  }
22241
22911
  /**
@@ -22243,27 +22913,25 @@ var ContentStreamLexer = class {
22243
22913
  */
22244
22914
  readName() {
22245
22915
  this.pos++;
22246
- let name = "/";
22916
+ const parts = ["/"];
22247
22917
  while (this.pos < this.data.length) {
22248
22918
  const ch = this.data[this.pos];
22249
22919
  if (this.isWhitespace(ch) || this.isDelimiter(ch)) break;
22250
22920
  if (ch === 35 && this.pos + 2 < this.data.length) {
22251
- const hi = this.data[this.pos + 1];
22252
- const lo = this.data[this.pos + 2];
22253
- const hex = String.fromCharCode(hi) + String.fromCharCode(lo);
22254
- const code = parseInt(hex, 16);
22255
- if (!isNaN(code)) {
22256
- name += String.fromCharCode(code);
22921
+ const hi = hexVal[this.data[this.pos + 1]];
22922
+ const lo = hexVal[this.data[this.pos + 2]];
22923
+ if (hi !== -1 && lo !== -1) {
22924
+ parts.push(String.fromCharCode(hi << 4 | lo));
22257
22925
  this.pos += 3;
22258
22926
  continue;
22259
22927
  }
22260
22928
  }
22261
- name += String.fromCharCode(ch);
22929
+ parts.push(String.fromCharCode(ch));
22262
22930
  this.pos++;
22263
22931
  }
22264
22932
  return {
22265
22933
  type: TokenType.Name,
22266
- value: require_pdfCatalog.PdfName.of(name)
22934
+ value: require_pdfCatalog.PdfName.of(parts.join(""))
22267
22935
  };
22268
22936
  }
22269
22937
  /**
@@ -22357,9 +23025,7 @@ var ContentStreamLexer = class {
22357
23025
  * Decode a slice of the data as ASCII text.
22358
23026
  */
22359
23027
  decodeAscii(start, end) {
22360
- let s = "";
22361
- for (let i = start; i < end; i++) s += String.fromCharCode(this.data[i]);
22362
- return s;
23028
+ return String.fromCharCode.apply(null, this.data.subarray(start, end));
22363
23029
  }
22364
23030
  };
22365
23031
 
@@ -23355,10 +24021,10 @@ async function initWasm(options) {
23355
24021
  if (options === void 0 || typeof options === "string" || options instanceof URL) return;
23356
24022
  if (wasmInitialized) return;
23357
24023
  const inits = [];
23358
- if (options.deflate || options.deflateWasm) inits.push(Promise.resolve().then(() => require("./libdeflateWasm-DeU6cupL.cjs")).then((n) => n.libdeflateWasm_exports).then(async ({ initDeflateWasm }) => {
24024
+ if (options.deflate || options.deflateWasm) inits.push(Promise.resolve().then(() => require("./libdeflateWasm-OkNoqBnO.cjs")).then((n) => n.libdeflateWasm_exports).then(async ({ initDeflateWasm }) => {
23359
24025
  await initDeflateWasm(options.deflateWasm);
23360
24026
  }));
23361
- if (options.png || options.pngWasm) inits.push(Promise.resolve().then(() => require("./pngEmbed-1RWu6KsO.cjs")).then((n) => n.pngEmbed_exports).then(async ({ initPngWasm }) => {
24027
+ if (options.png || options.pngWasm) inits.push(Promise.resolve().then(() => require("./pngEmbed-OYyOe_W0.cjs")).then((n) => n.pngEmbed_exports).then(async ({ initPngWasm }) => {
23362
24028
  await initPngWasm(options.pngWasm);
23363
24029
  }));
23364
24030
  if (options.fonts || options.fontWasm) inits.push(Promise.resolve().then(() => require("./fontSubset-pFc8Dueu.cjs")).then((n) => n.fontSubset_exports).then(async ({ initSubsetWasm }) => {
@@ -23417,6 +24083,7 @@ exports.PdfObjectRegistry = require_pdfCatalog.PdfObjectRegistry;
23417
24083
  exports.PdfOutlineItem = PdfOutlineItem;
23418
24084
  exports.PdfOutlineTree = PdfOutlineTree;
23419
24085
  exports.PdfPage = require_pdfPage.PdfPage;
24086
+ exports.PdfParseError = PdfParseError;
23420
24087
  exports.PdfPolyLineAnnotation = PdfPolyLineAnnotation;
23421
24088
  exports.PdfPolygonAnnotation = PdfPolygonAnnotation;
23422
24089
  exports.PdfRadioGroup = PdfRadioGroup;
@@ -23468,8 +24135,10 @@ exports.buildAnnotationDict = require_pdfPage.buildAnnotationDict;
23468
24135
  exports.buildCatalog = require_pdfCatalog.buildCatalog;
23469
24136
  exports.buildDocumentStructure = require_pdfCatalog.buildDocumentStructure;
23470
24137
  exports.buildEmbeddedFilesNameTree = buildEmbeddedFilesNameTree;
24138
+ exports.buildGradientObjects = require_pdfPage.buildGradientObjects;
23471
24139
  exports.buildInfoDict = require_pdfCatalog.buildInfoDict;
23472
24140
  exports.buildPageTree = require_pdfCatalog.buildPageTree;
24141
+ exports.buildPatternObjects = require_pdfPage.buildPatternObjects;
23473
24142
  exports.buildPkcs7Signature = buildPkcs7Signature;
23474
24143
  exports.buildTimestampRequest = buildTimestampRequest;
23475
24144
  exports.buildViewerPreferencesDict = buildViewerPreferencesDict;
@@ -23536,6 +24205,7 @@ exports.fillEvenOdd = require_pdfPage.fillEvenOdd;
23536
24205
  exports.fillEvenOddAndStroke = require_pdfPage.fillEvenOddAndStroke;
23537
24206
  exports.fillOp = require_pdfPage.fill;
23538
24207
  exports.findSignatures = findSignatures;
24208
+ exports.formatHexContext = formatHexContext;
23539
24209
  exports.formatPdfDate = require_pdfCatalog.formatPdfDate;
23540
24210
  exports.generateButtonAppearance = generateButtonAppearance;
23541
24211
  exports.generateCheckboxAppearance = generateCheckboxAppearance;
@@ -23568,6 +24238,7 @@ exports.layoutCombedText = layoutCombedText;
23568
24238
  exports.layoutMultilineText = layoutMultilineText;
23569
24239
  exports.layoutSinglelineText = layoutSinglelineText;
23570
24240
  exports.lineToOp = require_pdfPage.lineTo;
24241
+ exports.linearGradient = require_pdfPage.linearGradient;
23571
24242
  exports.linearizePdf = linearizePdf;
23572
24243
  exports.loadPdf = loadPdf;
23573
24244
  exports.markForRedaction = require_pdfPage.markForRedaction;
@@ -23589,6 +24260,7 @@ exports.parseXmpMetadata = parseXmpMetadata;
23589
24260
  exports.popGraphicsState = require_pdfPage.restoreState;
23590
24261
  exports.prepareForSigning = prepareForSigning;
23591
24262
  exports.pushGraphicsState = require_pdfPage.saveState;
24263
+ exports.radialGradient = require_pdfPage.radialGradient;
23592
24264
  exports.radians = require_pdfPage.radians;
23593
24265
  exports.radiansToDegrees = require_pdfPage.radiansToDegrees;
23594
24266
  exports.rc4 = rc4;
@@ -23653,6 +24325,7 @@ exports.splitPdf = splitPdf;
23653
24325
  exports.strokeOp = require_pdfPage.stroke;
23654
24326
  exports.summarizeIssues = summarizeIssues;
23655
24327
  exports.svgToPdfOperators = require_pdfPage.svgToPdfOperators;
24328
+ exports.tilingPattern = require_pdfPage.tilingPattern;
23656
24329
  exports.translateOp = require_pdfPage.translate;
23657
24330
  exports.validatePdfA = validatePdfA;
23658
24331
  exports.verifyOwnerPassword = verifyOwnerPassword;