modern-pdf-lib 0.12.1 → 0.13.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');
2
+ const require_pdfPage = require('./pdfPage-BebMv6fN.cjs');
3
3
  const require_pdfCatalog = require('./pdfCatalog-y_XG8Hq1.cjs');
4
- const require_libdeflateWasm = require('./libdeflateWasm-DeU6cupL.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
 
@@ -3236,7 +3236,7 @@ function extractMetricsWasm(fontData) {
3236
3236
  * Tracks which glyphs have been used so that subsetting can be
3237
3237
  * performed at save time, and provides text measurement methods.
3238
3238
  *
3239
- * Create via {@link embedFont}.
3239
+ * Create via `PdfDocument.embedFont()`.
3240
3240
  */
3241
3241
  var EmbeddedFont = class {
3242
3242
  /** The raw font file bytes. */
@@ -3581,6 +3581,53 @@ function findTable(data, tag) {
3581
3581
  }
3582
3582
  }
3583
3583
 
3584
+ //#endregion
3585
+ //#region src/parser/parseError.ts
3586
+ /**
3587
+ * @module parser/parseError
3588
+ * Structured error class for PDF parsing failures.
3589
+ * @packageDocumentation
3590
+ */
3591
+ var PdfParseError = class extends Error {
3592
+ name = "PdfParseError";
3593
+ offset;
3594
+ expected;
3595
+ actual;
3596
+ hexContext;
3597
+ constructor(options) {
3598
+ const hexCtx = options.data ? formatHexContext(options.data, options.offset) : "";
3599
+ const parts = [options.message];
3600
+ if (options.expected) parts.push(` Expected: ${options.expected}`);
3601
+ if (options.actual) parts.push(` Got: ${options.actual}`);
3602
+ if (hexCtx) parts.push(` Context:\n${hexCtx}`);
3603
+ super(parts.join("\n"), options.cause ? { cause: options.cause } : void 0);
3604
+ this.offset = options.offset;
3605
+ this.expected = options.expected ?? "";
3606
+ this.actual = options.actual ?? "";
3607
+ this.hexContext = hexCtx;
3608
+ }
3609
+ };
3610
+ function formatHexContext(data, offset, windowSize = 16) {
3611
+ const start = Math.max(0, offset - windowSize);
3612
+ const end = Math.min(data.length, offset + windowSize);
3613
+ const slice = data.subarray(start, end);
3614
+ const hexParts = [];
3615
+ const asciiParts = [];
3616
+ for (let i = 0; i < slice.length; i++) {
3617
+ const byte = slice[i];
3618
+ const isErrorByte = start + i === offset;
3619
+ const hex = byte.toString(16).padStart(2, "0");
3620
+ hexParts.push(isErrorByte ? `[${hex}]` : ` ${hex} `);
3621
+ asciiParts.push(byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : ".");
3622
+ }
3623
+ return [
3624
+ ` Offset ${start}:`,
3625
+ ` Hex: ${hexParts.join("")}`,
3626
+ ` ASCII: ${asciiParts.join(" ")}`,
3627
+ ` Error at offset ${offset} (marked with [])`
3628
+ ].join("\n");
3629
+ }
3630
+
3584
3631
  //#endregion
3585
3632
  //#region src/parser/lexer.ts
3586
3633
  /**
@@ -3736,7 +3783,7 @@ const hexVal = /* @__PURE__ */ (() => {
3736
3783
  */
3737
3784
  var PdfLexer = class {
3738
3785
  /** The raw PDF bytes being tokenized. */
3739
- data;
3786
+ _data;
3740
3787
  /** Total length of the input (cached for hot loops). */
3741
3788
  len;
3742
3789
  /** Current read position (byte offset). */
@@ -3759,11 +3806,20 @@ var PdfLexer = class {
3759
3806
  * must not mutate it while the lexer is in use.
3760
3807
  */
3761
3808
  constructor(data) {
3762
- this.data = data;
3809
+ this._data = data;
3763
3810
  this.len = data.length;
3764
3811
  this.position = 0;
3765
3812
  }
3766
3813
  /**
3814
+ * Public accessor for the raw PDF byte buffer.
3815
+ *
3816
+ * This allows other parsers (e.g. object parser, xref parser) to
3817
+ * include hex-context dumps in structured error messages.
3818
+ */
3819
+ get rawData() {
3820
+ return this._data;
3821
+ }
3822
+ /**
3767
3823
  * Consume and return the next token.
3768
3824
  *
3769
3825
  * Returns a token with `type === TokenType.EOF` when the input is
@@ -3799,8 +3855,14 @@ var PdfLexer = class {
3799
3855
  * @throws If there are not enough bytes remaining.
3800
3856
  */
3801
3857
  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);
3858
+ if (this.position + length > this.len) throw new PdfParseError({
3859
+ message: `PdfLexer.readStreamData: requested ${length} bytes at offset ${this.position}, but only ${this.len - this.position} remain`,
3860
+ offset: this.position,
3861
+ expected: `${length} bytes available`,
3862
+ actual: `${this.len - this.position} bytes remaining`,
3863
+ data: this._data
3864
+ });
3865
+ const slice = this._data.subarray(this.position, this.position + length);
3804
3866
  this.position += length;
3805
3867
  return slice;
3806
3868
  }
@@ -3813,7 +3875,13 @@ var PdfLexer = class {
3813
3875
  * @throws If the offset is out of range.
3814
3876
  */
3815
3877
  seek(offset) {
3816
- if (offset < 0 || offset > this.len) throw new RangeError(`PdfLexer.seek: offset ${offset} is outside [0, ${this.len}]`);
3878
+ if (offset < 0 || offset > this.len) throw new PdfParseError({
3879
+ message: `PdfLexer.seek: offset ${offset} is outside [0, ${this.len}]`,
3880
+ offset,
3881
+ expected: `offset in range [0, ${this.len}]`,
3882
+ actual: `${offset}`,
3883
+ data: this._data
3884
+ });
3817
3885
  this.position = offset;
3818
3886
  this.peeked = null;
3819
3887
  }
@@ -3826,7 +3894,7 @@ var PdfLexer = class {
3826
3894
  */
3827
3895
  byteAt(offset) {
3828
3896
  if (offset < 0 || offset >= this.len) return -1;
3829
- return this.data[offset];
3897
+ return this._data[offset];
3830
3898
  }
3831
3899
  /**
3832
3900
  * Return the total length of the input buffer (in bytes).
@@ -3842,7 +3910,7 @@ var PdfLexer = class {
3842
3910
  * extracting stream data.
3843
3911
  */
3844
3912
  skipWhitespace() {
3845
- const d = this.data;
3913
+ const d = this._data;
3846
3914
  let pos = this.position;
3847
3915
  while (pos < this.len) {
3848
3916
  const b = d[pos];
@@ -3876,7 +3944,7 @@ var PdfLexer = class {
3876
3944
  value: null,
3877
3945
  offset: this.position
3878
3946
  };
3879
- const d = this.data;
3947
+ const d = this._data;
3880
3948
  const startPos = this.position;
3881
3949
  const b = d[startPos];
3882
3950
  if (b === CH_LBRACKET) {
@@ -3916,7 +3984,13 @@ var PdfLexer = class {
3916
3984
  };
3917
3985
  }
3918
3986
  this.position++;
3919
- throw new Error(`PdfLexer: unexpected '>' at offset ${startPos} (expected '>>' for dict end)`);
3987
+ throw new PdfParseError({
3988
+ message: `PdfLexer: unexpected '>' at offset ${startPos} (expected '>>' for dict end)`,
3989
+ offset: startPos,
3990
+ expected: "'>>' (dict end delimiter)",
3991
+ actual: "'>' (lone angle bracket)",
3992
+ data: this._data
3993
+ });
3920
3994
  }
3921
3995
  if (b === CH_LPAREN) return this.readLiteralString(startPos);
3922
3996
  if (b === CH_SLASH) return this.readName(startPos);
@@ -3931,7 +4005,7 @@ var PdfLexer = class {
3931
4005
  * `-.002`, `+.5`). Scientific notation is **not** permitted.
3932
4006
  */
3933
4007
  readNumber(startPos) {
3934
- const d = this.data;
4008
+ const d = this._data;
3935
4009
  let pos = startPos;
3936
4010
  let hasSign = false;
3937
4011
  let hasDot = false;
@@ -3975,7 +4049,7 @@ var PdfLexer = class {
3975
4049
  * parentheses.
3976
4050
  */
3977
4051
  readLiteralString(startPos) {
3978
- const d = this.data;
4052
+ const d = this._data;
3979
4053
  let pos = startPos + 1;
3980
4054
  let depth = 1;
3981
4055
  let result = "";
@@ -4067,7 +4141,13 @@ var PdfLexer = class {
4067
4141
  result += String.fromCharCode(c);
4068
4142
  pos++;
4069
4143
  }
4070
- if (depth !== 0) throw new Error(`PdfLexer: unterminated literal string starting at offset ${startPos}`);
4144
+ if (depth !== 0) throw new PdfParseError({
4145
+ message: `PdfLexer: unterminated literal string starting at offset ${startPos}`,
4146
+ offset: startPos,
4147
+ expected: "closing ')' for literal string",
4148
+ actual: "end of input",
4149
+ data: this._data
4150
+ });
4071
4151
  this.position = pos;
4072
4152
  return {
4073
4153
  type: TokenType$1.LiteralString,
@@ -4082,7 +4162,7 @@ var PdfLexer = class {
4082
4162
  * odd, a trailing `0` is assumed (per spec SS 7.3.4.3).
4083
4163
  */
4084
4164
  readHexString(startPos) {
4085
- const d = this.data;
4165
+ const d = this._data;
4086
4166
  let pos = startPos + 1;
4087
4167
  let hex = "";
4088
4168
  while (pos < this.len) {
@@ -4095,7 +4175,13 @@ 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}`);
4178
+ if (hexVal[c] === -1) throw new PdfParseError({
4179
+ message: `PdfLexer: invalid hex digit 0x${c.toString(16).padStart(2, "0")} at offset ${pos} in hex string starting at ${startPos}`,
4180
+ offset: pos,
4181
+ expected: "hex digit (0-9, a-f, A-F)",
4182
+ actual: `0x${c.toString(16).padStart(2, "0")}`,
4183
+ data: this._data
4184
+ });
4099
4185
  hex += String.fromCharCode(c);
4100
4186
  pos++;
4101
4187
  }
@@ -4120,17 +4206,29 @@ var PdfLexer = class {
4120
4206
  * **includes** the leading `/`.
4121
4207
  */
4122
4208
  readName(startPos) {
4123
- const d = this.data;
4209
+ const d = this._data;
4124
4210
  let pos = startPos + 1;
4125
4211
  let name = "/";
4126
4212
  while (pos < this.len) {
4127
4213
  const c = d[pos];
4128
4214
  if (isWhitespace[c] || isDelimiter[c]) break;
4129
4215
  if (c === CH_HASH) {
4130
- if (pos + 2 >= this.len) throw new Error(`PdfLexer: incomplete #XX escape in name at offset ${pos}`);
4216
+ if (pos + 2 >= this.len) throw new PdfParseError({
4217
+ message: `PdfLexer: incomplete #XX escape in name at offset ${pos}`,
4218
+ offset: pos,
4219
+ expected: "two hex digits after # in name",
4220
+ actual: "end of input",
4221
+ data: this._data
4222
+ });
4131
4223
  const hi = hexVal[d[pos + 1]];
4132
4224
  const lo = hexVal[d[pos + 2]];
4133
- if (hi === -1 || lo === -1) throw new Error(`PdfLexer: invalid #XX escape in name at offset ${pos}`);
4225
+ if (hi === -1 || lo === -1) throw new PdfParseError({
4226
+ message: `PdfLexer: invalid #XX escape in name at offset ${pos}`,
4227
+ offset: pos,
4228
+ expected: "valid hex digits after # in name",
4229
+ actual: `#${String.fromCharCode(d[pos + 1])}${String.fromCharCode(d[pos + 2])}`,
4230
+ data: this._data
4231
+ });
4134
4232
  name += String.fromCharCode(hi << 4 | lo);
4135
4233
  pos += 3;
4136
4234
  continue;
@@ -4152,7 +4250,7 @@ var PdfLexer = class {
4152
4250
  * available for callers that want to preserve them.
4153
4251
  */
4154
4252
  readComment(startPos) {
4155
- const d = this.data;
4253
+ const d = this._data;
4156
4254
  let pos = startPos + 1;
4157
4255
  const begin = pos;
4158
4256
  while (pos < this.len) {
@@ -4177,7 +4275,7 @@ var PdfLexer = class {
4177
4275
  * handle them.
4178
4276
  */
4179
4277
  readKeyword(startPos) {
4180
- const d = this.data;
4278
+ const d = this._data;
4181
4279
  let pos = startPos;
4182
4280
  while (pos < this.len) {
4183
4281
  const c = d[pos];
@@ -4256,7 +4354,7 @@ var PdfLexer = class {
4256
4354
  * because it avoids the per-call overhead of the streaming decoder.
4257
4355
  */
4258
4356
  bytesToAscii(from, to) {
4259
- const d = this.data;
4357
+ const d = this._data;
4260
4358
  let s = "";
4261
4359
  for (let i = from; i < to; i++) s += String.fromCharCode(d[i]);
4262
4360
  return s;
@@ -4332,13 +4430,31 @@ var PdfObjectParser = class {
4332
4430
  */
4333
4431
  parseIndirectObject() {
4334
4432
  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)})`);
4433
+ if (objNumToken.type !== TokenType$1.Number || !Number.isInteger(objNumToken.value)) throw new PdfParseError({
4434
+ message: `PdfObjectParser.parseIndirectObject: expected integer object number at offset ${objNumToken.offset}, got ${TokenType$1[objNumToken.type]} (${String(objNumToken.value)})`,
4435
+ offset: objNumToken.offset,
4436
+ expected: "integer object number",
4437
+ actual: `${TokenType$1[objNumToken.type]} (${String(objNumToken.value)})`,
4438
+ data: this.lexer.rawData
4439
+ });
4336
4440
  const objNum = objNumToken.value;
4337
4441
  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)})`);
4442
+ if (genNumToken.type !== TokenType$1.Number || !Number.isInteger(genNumToken.value)) throw new PdfParseError({
4443
+ message: `PdfObjectParser.parseIndirectObject: expected integer generation number at offset ${genNumToken.offset}, got ${TokenType$1[genNumToken.type]} (${String(genNumToken.value)})`,
4444
+ offset: genNumToken.offset,
4445
+ expected: "integer generation number",
4446
+ actual: `${TokenType$1[genNumToken.type]} (${String(genNumToken.value)})`,
4447
+ data: this.lexer.rawData
4448
+ });
4339
4449
  const genNum = genNumToken.value;
4340
4450
  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)})`);
4451
+ if (objKw.type !== TokenType$1.ObjKeyword) throw new PdfParseError({
4452
+ message: `PdfObjectParser.parseIndirectObject: expected 'obj' keyword at offset ${objKw.offset}, got ${TokenType$1[objKw.type]} (${String(objKw.value)})`,
4453
+ offset: objKw.offset,
4454
+ expected: "'obj' keyword",
4455
+ actual: `${TokenType$1[objKw.type]} (${String(objKw.value)})`,
4456
+ data: this.lexer.rawData
4457
+ });
4342
4458
  return this.parseIndirectObjectBody(objNum, genNum);
4343
4459
  }
4344
4460
  /**
@@ -4383,8 +4499,20 @@ var PdfObjectParser = class {
4383
4499
  case TokenType$1.Name: return require_pdfCatalog.PdfName.of(token.value);
4384
4500
  case TokenType$1.ArrayStart: return this.parseArray();
4385
4501
  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}`);
4502
+ case TokenType$1.EOF: throw new PdfParseError({
4503
+ message: `PdfObjectParser: unexpected end of input at offset ${token.offset}`,
4504
+ offset: token.offset,
4505
+ expected: "a PDF object (number, string, name, array, dict, etc.)",
4506
+ actual: "end of input",
4507
+ data: this.lexer.rawData
4508
+ });
4509
+ default: throw new PdfParseError({
4510
+ message: `PdfObjectParser: unexpected token ${TokenType$1[token.type]} (${String(token.value)}) at offset ${token.offset}`,
4511
+ offset: token.offset,
4512
+ expected: "a PDF object (number, string, name, array, dict, etc.)",
4513
+ actual: `${TokenType$1[token.type]} (${String(token.value)})`,
4514
+ data: this.lexer.rawData
4515
+ });
4388
4516
  }
4389
4517
  }
4390
4518
  /**
@@ -4430,7 +4558,13 @@ var PdfObjectParser = class {
4430
4558
  if (this.lexer.peekToken().type === TokenType$1.StreamKeyword) finalObject = this.readStream(object);
4431
4559
  }
4432
4560
  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)})`);
4561
+ if (endToken.type !== TokenType$1.EndObjKeyword) throw new PdfParseError({
4562
+ message: `PdfObjectParser: expected 'endobj' for object ${objNum} ${genNum} at offset ${endToken.offset}, got ${TokenType$1[endToken.type]} (${String(endToken.value)})`,
4563
+ offset: endToken.offset,
4564
+ expected: `'endobj' keyword for object ${objNum} ${genNum}`,
4565
+ actual: `${TokenType$1[endToken.type]} (${String(endToken.value)})`,
4566
+ data: this.lexer.rawData
4567
+ });
4434
4568
  this.registry.registerWithRef(ref, finalObject);
4435
4569
  return {
4436
4570
  ref,
@@ -4450,7 +4584,13 @@ var PdfObjectParser = class {
4450
4584
  this.lexer.nextToken();
4451
4585
  break;
4452
4586
  }
4453
- if (peek.type === TokenType$1.EOF) throw new Error(`PdfObjectParser: unterminated array at offset ${peek.offset}`);
4587
+ if (peek.type === TokenType$1.EOF) throw new PdfParseError({
4588
+ message: `PdfObjectParser: unterminated array at offset ${peek.offset}`,
4589
+ offset: peek.offset,
4590
+ expected: "']' to close array",
4591
+ actual: "end of input",
4592
+ data: this.lexer.rawData
4593
+ });
4454
4594
  items.push(this.parseObject());
4455
4595
  }
4456
4596
  return new require_pdfCatalog.PdfArray(items);
@@ -4479,9 +4619,21 @@ var PdfObjectParser = class {
4479
4619
  this.lexer.nextToken();
4480
4620
  break;
4481
4621
  }
4482
- if (peek.type === TokenType$1.EOF) throw new Error(`PdfObjectParser: unterminated dictionary at offset ${peek.offset}`);
4622
+ if (peek.type === TokenType$1.EOF) throw new PdfParseError({
4623
+ message: `PdfObjectParser: unterminated dictionary at offset ${peek.offset}`,
4624
+ offset: peek.offset,
4625
+ expected: "'>>' to close dictionary",
4626
+ actual: "end of input",
4627
+ data: this.lexer.rawData
4628
+ });
4483
4629
  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)})`);
4630
+ if (keyToken.type !== TokenType$1.Name) throw new PdfParseError({
4631
+ message: `PdfObjectParser: expected name as dictionary key at offset ${keyToken.offset}, got ${TokenType$1[keyToken.type]} (${String(keyToken.value)})`,
4632
+ offset: keyToken.offset,
4633
+ expected: "name token as dictionary key",
4634
+ actual: `${TokenType$1[keyToken.type]} (${String(keyToken.value)})`,
4635
+ data: this.lexer.rawData
4636
+ });
4485
4637
  const key = keyToken.value;
4486
4638
  const value = this.parseObject();
4487
4639
  dict.set(key, value);
@@ -4500,13 +4652,25 @@ var PdfObjectParser = class {
4500
4652
  */
4501
4653
  readStream(dict) {
4502
4654
  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]}`);
4655
+ if (streamKw.type !== TokenType$1.StreamKeyword) throw new PdfParseError({
4656
+ message: `PdfObjectParser.readStream: expected 'stream' keyword at offset ${streamKw.offset}, got ${TokenType$1[streamKw.type]}`,
4657
+ offset: streamKw.offset,
4658
+ expected: "'stream' keyword",
4659
+ actual: `${TokenType$1[streamKw.type]}`,
4660
+ data: this.lexer.rawData
4661
+ });
4504
4662
  this.skipStreamEol();
4505
4663
  const length = this.resolveStreamLength(dict);
4506
4664
  const data = this.lexer.readStreamData(length);
4507
4665
  this.skipEndstreamWhitespace();
4508
4666
  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)})`);
4667
+ if (endKw.type !== TokenType$1.EndStreamKeyword) throw new PdfParseError({
4668
+ message: `PdfObjectParser.readStream: expected 'endstream' keyword at offset ${endKw.offset}, got ${TokenType$1[endKw.type]} (${String(endKw.value)})`,
4669
+ offset: endKw.offset,
4670
+ expected: "'endstream' keyword",
4671
+ actual: `${TokenType$1[endKw.type]} (${String(endKw.value)})`,
4672
+ data: this.lexer.rawData
4673
+ });
4510
4674
  return new require_pdfCatalog.PdfStream(dict, data);
4511
4675
  }
4512
4676
  /**
@@ -4551,18 +4715,42 @@ var PdfObjectParser = class {
4551
4715
  */
4552
4716
  resolveStreamLength(dict) {
4553
4717
  const lengthObj = dict.get("/Length");
4554
- if (lengthObj === void 0) throw new Error("PdfObjectParser.resolveStreamLength: stream dictionary is missing /Length");
4718
+ if (lengthObj === void 0) throw new PdfParseError({
4719
+ message: "PdfObjectParser.resolveStreamLength: stream dictionary is missing /Length",
4720
+ offset: this.lexer.position,
4721
+ expected: "/Length entry in stream dictionary",
4722
+ actual: "no /Length entry",
4723
+ data: this.lexer.rawData
4724
+ });
4555
4725
  if (lengthObj.kind === "number") return lengthObj.value;
4556
4726
  if (lengthObj.kind === "ref") {
4557
4727
  const ref = lengthObj;
4558
4728
  const resolved = this.registry.resolve(ref);
4559
4729
  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`);
4730
+ if (resolved.kind !== "number") throw new PdfParseError({
4731
+ message: `PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R resolved to ${resolved.kind}, expected number`,
4732
+ offset: this.lexer.position,
4733
+ expected: "number for /Length reference",
4734
+ actual: `${resolved.kind}`,
4735
+ data: this.lexer.rawData
4736
+ });
4561
4737
  return resolved.value;
4562
4738
  }
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.`);
4739
+ throw new PdfParseError({
4740
+ message: `PdfObjectParser.resolveStreamLength: /Length reference ${ref.objectNumber} ${ref.generationNumber} R is not yet resolved in the registry. Parse the referenced object first.`,
4741
+ offset: this.lexer.position,
4742
+ expected: "resolved /Length reference",
4743
+ actual: `unresolved reference ${ref.objectNumber} ${ref.generationNumber} R`,
4744
+ data: this.lexer.rawData
4745
+ });
4564
4746
  }
4565
- throw new Error(`PdfObjectParser.resolveStreamLength: /Length must be a number or indirect reference, got ${lengthObj.kind}`);
4747
+ throw new PdfParseError({
4748
+ message: `PdfObjectParser.resolveStreamLength: /Length must be a number or indirect reference, got ${lengthObj.kind}`,
4749
+ offset: this.lexer.position,
4750
+ expected: "number or indirect reference for /Length",
4751
+ actual: `${lengthObj.kind}`,
4752
+ data: this.lexer.rawData
4753
+ });
4566
4754
  }
4567
4755
  };
4568
4756
 
@@ -4643,10 +4831,10 @@ async function tryLoadLibdeflate() {
4643
4831
  if (libdeflateAttempted) return libdeflateEngine;
4644
4832
  libdeflateAttempted = true;
4645
4833
  try {
4646
- const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await Promise.resolve().then(() => require("./libdeflateWasm-DeU6cupL.cjs")).then((n) => n.libdeflateWasm_exports);
4834
+ const { LibdeflateWasm: LibdeflateCtor, initDeflateWasm } = await Promise.resolve().then(() => require("./libdeflateWasm-OkNoqBnO.cjs")).then((n) => n.libdeflateWasm_exports);
4647
4835
  let customBytes;
4648
4836
  try {
4649
- const { getWasmLoaderConfig } = await Promise.resolve().then(() => require("./loader-DWwMj8jZ.cjs"));
4837
+ const { getWasmLoaderConfig } = await Promise.resolve().then(() => require("./loader-_fqS-TmT.cjs"));
4650
4838
  customBytes = getWasmLoaderConfig().moduleBytes?.["libdeflate"];
4651
4839
  } catch {}
4652
4840
  await initDeflateWasm(customBytes);
@@ -4764,9 +4952,19 @@ function stringToLatin1Bytes(str) {
4764
4952
  */
4765
4953
  function extractTrailer(dict) {
4766
4954
  const sizeVal = numVal$2(dict.get("/Size"));
4767
- if (sizeVal === void 0) throw new Error("Invalid PDF: trailer dictionary missing /Size entry");
4955
+ if (sizeVal === void 0) throw new PdfParseError({
4956
+ message: "Invalid PDF: trailer dictionary missing /Size entry",
4957
+ offset: 0,
4958
+ expected: "/Size entry in trailer dictionary",
4959
+ actual: "no /Size entry"
4960
+ });
4768
4961
  const rootRef = refVal(dict.get("/Root"));
4769
- if (rootRef === void 0) throw new Error("Invalid PDF: trailer dictionary missing /Root entry");
4962
+ if (rootRef === void 0) throw new PdfParseError({
4963
+ message: "Invalid PDF: trailer dictionary missing /Root entry",
4964
+ offset: 0,
4965
+ expected: "/Root entry in trailer dictionary",
4966
+ actual: "no /Root entry"
4967
+ });
4770
4968
  const trailer = {
4771
4969
  size: sizeVal,
4772
4970
  rootRef
@@ -4805,7 +5003,12 @@ async function decodeStream$1(streamData, dict) {
4805
5003
  const arr = filter;
4806
5004
  if (arr.length > 0 && arr.items[0].kind === "name") filterName = arr.items[0].value;
4807
5005
  }
4808
- if (filterName !== "/FlateDecode") throw new Error(`Unsupported xref stream filter: ${filterName ?? "unknown"}. Only /FlateDecode is supported for cross-reference streams.`);
5006
+ if (filterName !== "/FlateDecode") throw new PdfParseError({
5007
+ message: `Unsupported xref stream filter: ${filterName ?? "unknown"}. Only /FlateDecode is supported for cross-reference streams.`,
5008
+ offset: 0,
5009
+ expected: "/FlateDecode filter",
5010
+ actual: `${filterName ?? "unknown"} filter`
5011
+ });
4809
5012
  let decompressed = await decompress(streamData);
4810
5013
  const decodeParms = dict.get("/DecodeParms");
4811
5014
  if (decodeParms !== void 0 && decodeParms.kind === "dict") {
@@ -4939,11 +5142,30 @@ var XrefParser = class {
4939
5142
  const startPos = this.data.length - searchWindow;
4940
5143
  const tail = TEXT_DECODER$1.decode(this.data.subarray(startPos, this.data.length));
4941
5144
  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.");
5145
+ if (idx === -1) throw new PdfParseError({
5146
+ message: "Invalid PDF: could not find \"startxref\" marker in the last 2048 bytes. The file may be truncated or corrupt.",
5147
+ offset: startPos,
5148
+ expected: "\"startxref\" marker near end of file",
5149
+ actual: "no \"startxref\" found",
5150
+ data: this.data
5151
+ });
5152
+ const afterKeyword = tail.substring(idx + 9).trim();
5153
+ const match = afterKeyword.match(/^(\d+)/);
5154
+ if (!match) throw new PdfParseError({
5155
+ message: "Invalid PDF: \"startxref\" found but no valid offset follows it.",
5156
+ offset: startPos + idx,
5157
+ expected: "decimal offset after \"startxref\"",
5158
+ actual: `"${afterKeyword.substring(0, 20)}"`,
5159
+ data: this.data
5160
+ });
4945
5161
  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}).`);
5162
+ if (offset < 0 || offset >= this.data.length) throw new PdfParseError({
5163
+ message: `Invalid PDF: startxref offset ${offset} is out of range (file size: ${this.data.length}).`,
5164
+ offset: startPos + idx,
5165
+ expected: `offset in range [0, ${this.data.length})`,
5166
+ actual: `${offset}`,
5167
+ data: this.data
5168
+ });
4947
5169
  return offset;
4948
5170
  }
4949
5171
  /**
@@ -4996,7 +5218,13 @@ var XrefParser = class {
4996
5218
  const prevVal = numVal$2(trailerDict.get("/Prev"));
4997
5219
  currentOffset = prevVal !== void 0 && prevVal >= 0 ? prevVal : void 0;
4998
5220
  }
4999
- if (primaryTrailer === void 0) throw new Error("Invalid PDF: could not extract a valid trailer from the cross-reference structure.");
5221
+ if (primaryTrailer === void 0) throw new PdfParseError({
5222
+ message: "Invalid PDF: could not extract a valid trailer from the cross-reference structure.",
5223
+ offset: startOffset,
5224
+ expected: "valid trailer dictionary in cross-reference structure",
5225
+ actual: "no valid trailer found",
5226
+ data: this.data
5227
+ });
5000
5228
  return {
5001
5229
  entries,
5002
5230
  trailer: primaryTrailer
@@ -5024,14 +5252,26 @@ var XrefParser = class {
5024
5252
  const entries = [];
5025
5253
  let pos = offset;
5026
5254
  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}".`);
5255
+ if (xrefTag !== "xref") throw new PdfParseError({
5256
+ message: `Invalid PDF: expected "xref" keyword at offset ${offset}, found "${xrefTag}".`,
5257
+ offset,
5258
+ expected: "\"xref\" keyword",
5259
+ actual: `"${xrefTag}"`,
5260
+ data: this.data
5261
+ });
5028
5262
  pos += 4;
5029
5263
  pos = this.skipWhitespaceAt(pos);
5030
5264
  while (pos < this.data.length) {
5031
5265
  if (TEXT_DECODER$1.decode(this.data.subarray(pos, Math.min(pos + 7, this.data.length))).startsWith("trailer")) break;
5032
5266
  const headerLine = this.readLineAt(pos);
5033
5267
  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()}"`);
5268
+ if (!headerMatch) throw new PdfParseError({
5269
+ message: `Invalid PDF: malformed xref subsection header at offset ${pos}: "${headerLine.text.trim()}"`,
5270
+ offset: pos,
5271
+ expected: "xref subsection header \"firstObjNum count\"",
5272
+ actual: `"${headerLine.text.trim()}"`,
5273
+ data: this.data
5274
+ });
5035
5275
  const firstObjNum = parseInt(headerMatch[1], 10);
5036
5276
  const count = parseInt(headerMatch[2], 10);
5037
5277
  pos = headerLine.nextPos;
@@ -5039,7 +5279,13 @@ var XrefParser = class {
5039
5279
  const objectNumber = firstObjNum + i;
5040
5280
  const entryText = this.readXrefEntryAt(pos);
5041
5281
  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()}"`);
5282
+ if (!entryMatch) throw new PdfParseError({
5283
+ message: `Invalid PDF: malformed xref entry at offset ${pos} for object ${objectNumber}: "${entryText.text.trim()}"`,
5284
+ offset: pos,
5285
+ expected: "xref entry \"OOOOOOOOOO GGGGG f/n\"",
5286
+ actual: `"${entryText.text.trim()}"`,
5287
+ data: this.data
5288
+ });
5043
5289
  const entryOffset = parseInt(entryMatch[1], 10);
5044
5290
  const gen = parseInt(entryMatch[2], 10);
5045
5291
  const marker = entryMatch[3];
@@ -5053,10 +5299,22 @@ var XrefParser = class {
5053
5299
  }
5054
5300
  }
5055
5301
  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}".`);
5302
+ if (trailerTag !== "trailer") throw new PdfParseError({
5303
+ message: `Invalid PDF: expected "trailer" keyword at offset ${pos}, found "${trailerTag}".`,
5304
+ offset: pos,
5305
+ expected: "\"trailer\" keyword",
5306
+ actual: `"${trailerTag}"`,
5307
+ data: this.data
5308
+ });
5057
5309
  pos += 7;
5058
5310
  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}.`);
5311
+ if (trailerObj.kind !== "dict") throw new PdfParseError({
5312
+ message: `Invalid PDF: expected dictionary after "trailer" keyword at offset ${pos}, got ${trailerObj.kind}.`,
5313
+ offset: pos,
5314
+ expected: "dictionary after \"trailer\" keyword",
5315
+ actual: `${trailerObj.kind}`,
5316
+ data: this.data
5317
+ });
5060
5318
  return {
5061
5319
  entries,
5062
5320
  trailerDict: trailerObj
@@ -5075,22 +5333,58 @@ var XrefParser = class {
5075
5333
  */
5076
5334
  async parseXrefStream(offset) {
5077
5335
  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}.`);
5336
+ if (object.kind !== "stream") throw new PdfParseError({
5337
+ message: `Invalid PDF: expected stream object at offset ${offset} for xref stream, got ${object.kind}.`,
5338
+ offset,
5339
+ expected: "stream object for xref stream",
5340
+ actual: `${object.kind}`,
5341
+ data: this.data
5342
+ });
5079
5343
  const stream = object;
5080
5344
  const dict = stream.dict;
5081
5345
  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.`);
5346
+ if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/XRef") throw new PdfParseError({
5347
+ message: `Invalid PDF: cross-reference stream at offset ${offset} does not have /Type /XRef.`,
5348
+ offset,
5349
+ expected: "/Type /XRef in cross-reference stream dictionary",
5350
+ actual: typeObj ? `${typeObj.kind}` : "no /Type entry",
5351
+ data: this.data
5352
+ });
5083
5353
  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.");
5354
+ if (wObj === void 0 || wObj.kind !== "array") throw new PdfParseError({
5355
+ message: "Invalid PDF: cross-reference stream missing /W (field widths) array.",
5356
+ offset,
5357
+ expected: "/W array in cross-reference stream",
5358
+ actual: wObj ? `${wObj.kind}` : "no /W entry",
5359
+ data: this.data
5360
+ });
5085
5361
  const wArr = wObj;
5086
- if (wArr.length < 3) throw new Error("Invalid PDF: cross-reference stream /W array must have at least 3 elements.");
5362
+ if (wArr.length < 3) throw new PdfParseError({
5363
+ message: "Invalid PDF: cross-reference stream /W array must have at least 3 elements.",
5364
+ offset,
5365
+ expected: "/W array with at least 3 elements",
5366
+ actual: `/W array with ${wArr.length} element(s)`,
5367
+ data: this.data
5368
+ });
5087
5369
  const w0 = numVal$2(wArr.items[0]) ?? 0;
5088
5370
  const w1 = numVal$2(wArr.items[1]) ?? 0;
5089
5371
  const w2 = numVal$2(wArr.items[2]) ?? 0;
5090
5372
  const entryWidth = w0 + w1 + w2;
5091
- if (entryWidth === 0) throw new Error("Invalid PDF: cross-reference stream /W widths sum to 0.");
5373
+ if (entryWidth === 0) throw new PdfParseError({
5374
+ message: "Invalid PDF: cross-reference stream /W widths sum to 0.",
5375
+ offset,
5376
+ expected: "non-zero sum of /W widths",
5377
+ actual: "0",
5378
+ data: this.data
5379
+ });
5092
5380
  const size = numVal$2(dict.get("/Size"));
5093
- if (size === void 0) throw new Error("Invalid PDF: cross-reference stream missing /Size.");
5381
+ if (size === void 0) throw new PdfParseError({
5382
+ message: "Invalid PDF: cross-reference stream missing /Size.",
5383
+ offset,
5384
+ expected: "/Size entry in cross-reference stream",
5385
+ actual: "no /Size entry",
5386
+ data: this.data
5387
+ });
5094
5388
  let subsections;
5095
5389
  const indexObj = dict.get("/Index");
5096
5390
  if (indexObj !== void 0 && indexObj.kind === "array") {
@@ -5180,7 +5474,13 @@ var XrefParser = class {
5180
5474
  type: "in-use"
5181
5475
  });
5182
5476
  }
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.");
5477
+ if (entries.size === 0) throw new PdfParseError({
5478
+ message: "Invalid PDF: could not find any indirect objects during recovery scan. The file may not be a valid PDF.",
5479
+ offset: 0,
5480
+ expected: "at least one \"N G obj\" pattern in file",
5481
+ actual: "no indirect objects found",
5482
+ data: this.data
5483
+ });
5184
5484
  let rootRef;
5185
5485
  let infoRef;
5186
5486
  const trailerIdx = fileText.lastIndexOf("trailer");
@@ -5203,7 +5503,13 @@ var XrefParser = class {
5203
5503
  }
5204
5504
  }
5205
5505
  } 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.");
5506
+ if (rootRef === void 0) throw new PdfParseError({
5507
+ message: "Invalid PDF: recovery scan could not locate the document catalog (/Root). The file appears to be severely corrupt.",
5508
+ offset: 0,
5509
+ expected: "document catalog (/Type /Catalog) in recovery scan",
5510
+ actual: "no /Root or /Catalog found",
5511
+ data: this.data
5512
+ });
5207
5513
  const trailer = {
5208
5514
  size: (entries.size > 0 ? entries.keys().reduce((max, n) => Math.max(max, n), 0) : 0) + 1,
5209
5515
  rootRef
@@ -6916,7 +7222,13 @@ var PdfDocumentParser = class {
6916
7222
  * @param data The raw PDF file bytes as a Uint8Array.
6917
7223
  */
6918
7224
  constructor(data) {
6919
- if (data.length < 8) throw new Error("Invalid PDF: file is too short to contain a valid PDF header.");
7225
+ if (data.length < 8) throw new PdfParseError({
7226
+ message: "Invalid PDF: file is too short to contain a valid PDF header.",
7227
+ offset: 0,
7228
+ expected: "at least 8 bytes for a valid PDF header",
7229
+ actual: `${data.length} bytes`,
7230
+ data
7231
+ });
6920
7232
  this.data = data;
6921
7233
  }
6922
7234
  /**
@@ -6967,7 +7279,14 @@ var PdfDocumentParser = class {
6967
7279
  const { object } = this.objectParser.parseIndirectObjectAt(entry.offset);
6968
7280
  resolved = object;
6969
7281
  } catch (err) {
6970
- throw new Error(`Failed to parse indirect object ${objNum} ${entry.generationNumber} at offset ${entry.offset}`, { cause: err });
7282
+ throw new PdfParseError({
7283
+ message: `Failed to parse indirect object ${objNum} ${entry.generationNumber} at offset ${entry.offset}`,
7284
+ offset: entry.offset,
7285
+ expected: `valid indirect object ${objNum} ${entry.generationNumber}`,
7286
+ actual: "parse failure",
7287
+ data: this.data,
7288
+ cause: err instanceof Error ? err : void 0
7289
+ });
6971
7290
  }
6972
7291
  this.objectCache.set(objNum, resolved);
6973
7292
  return resolved;
@@ -6991,7 +7310,13 @@ var PdfDocumentParser = class {
6991
7310
  const encryptRef = this.trailer.encryptRef;
6992
7311
  this.encryptDictObjNum = encryptRef.objectNumber;
6993
7312
  const encryptObj = this.resolveRef(encryptRef);
6994
- if (encryptObj.kind !== "dict") throw new Error("Invalid PDF: /Encrypt entry is not a dictionary.");
7313
+ if (encryptObj.kind !== "dict") throw new PdfParseError({
7314
+ message: "Invalid PDF: /Encrypt entry is not a dictionary.",
7315
+ offset: 0,
7316
+ expected: "dictionary for /Encrypt entry",
7317
+ actual: `${encryptObj.kind}`,
7318
+ data: this.data
7319
+ });
6995
7320
  const encryptDict = encryptObj;
6996
7321
  const fileId = this.trailer.id?.[0] ?? new Uint8Array(0);
6997
7322
  const passwordsToTry = [];
@@ -7006,8 +7331,21 @@ var PdfDocumentParser = class {
7006
7331
  } catch (err) {
7007
7332
  lastError = err instanceof Error ? err : new Error(String(err));
7008
7333
  }
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.");
7334
+ if (password !== void 0) throw new PdfParseError({
7335
+ message: `Failed to decrypt PDF: the provided password is incorrect. ${lastError?.message ?? ""}`,
7336
+ offset: 0,
7337
+ expected: "valid decryption password",
7338
+ actual: "incorrect password",
7339
+ data: this.data,
7340
+ cause: lastError
7341
+ });
7342
+ else throw new PdfParseError({
7343
+ message: "This PDF is encrypted and requires a password. Pass { password: \"...\" } in the options to decrypt it.",
7344
+ offset: 0,
7345
+ expected: "unencrypted PDF or password option",
7346
+ actual: "encrypted PDF without password",
7347
+ data: this.data
7348
+ });
7011
7349
  }
7012
7350
  /**
7013
7351
  * Decrypt all resolved objects in the object cache.
@@ -7103,7 +7441,12 @@ var PdfDocumentParser = class {
7103
7441
  * @throws If the page index is out of range.
7104
7442
  */
7105
7443
  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).`);
7444
+ if (pageIndex < 0 || pageIndex >= this.flattenedPages.length) throw new PdfParseError({
7445
+ message: `Page index ${pageIndex} is out of range. The document has ${this.flattenedPages.length} page(s).`,
7446
+ offset: 0,
7447
+ expected: `page index in range [0, ${this.flattenedPages.length})`,
7448
+ actual: `${pageIndex}`
7449
+ });
7107
7450
  return this.flattenedPages[pageIndex].dict;
7108
7451
  }
7109
7452
  /**
@@ -7123,16 +7466,34 @@ var PdfDocumentParser = class {
7123
7466
  validateHeader() {
7124
7467
  const header = TEXT_DECODER.decode(this.data.subarray(0, Math.min(1024, this.data.length)));
7125
7468
  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.");
7469
+ if (pdfIdx === -1 || pdfIdx > 1024) throw new PdfParseError({
7470
+ message: "Invalid PDF: file does not start with \"%PDF-\" header. This may not be a PDF file.",
7471
+ offset: 0,
7472
+ expected: "\"%PDF-\" header near start of file",
7473
+ actual: "no \"%PDF-\" marker found",
7474
+ data: this.data
7475
+ });
7127
7476
  const versionMatch = header.substring(pdfIdx).match(/%PDF-(\d+\.\d+)/);
7128
- if (!versionMatch) throw new Error("Invalid PDF: could not parse version from header.");
7477
+ if (!versionMatch) throw new PdfParseError({
7478
+ message: "Invalid PDF: could not parse version from header.",
7479
+ offset: pdfIdx,
7480
+ expected: "\"%PDF-X.Y\" version string",
7481
+ actual: `"${header.substring(pdfIdx, pdfIdx + 10)}"`,
7482
+ data: this.data
7483
+ });
7129
7484
  this.pdfVersion = versionMatch[1];
7130
7485
  const majorMinor = this.pdfVersion.split(".");
7131
7486
  const major = parseInt(majorMinor[0], 10);
7132
7487
  const minor = parseInt(majorMinor[1], 10);
7133
7488
  if (major === 1 && minor >= 0 && minor <= 9) return;
7134
7489
  if (major === 2 && minor >= 0) return;
7135
- throw new Error(`Unsupported PDF version: ${this.pdfVersion}. Expected PDF 1.0-1.9 or 2.0+.`);
7490
+ throw new PdfParseError({
7491
+ message: `Unsupported PDF version: ${this.pdfVersion}. Expected PDF 1.0-1.9 or 2.0+.`,
7492
+ offset: 0,
7493
+ expected: "PDF version 1.0-1.9 or 2.0+",
7494
+ actual: `PDF version ${this.pdfVersion}`,
7495
+ data: this.data
7496
+ });
7136
7497
  }
7137
7498
  /**
7138
7499
  * Resolve the document catalog dictionary from the trailer's /Root
@@ -7140,12 +7501,24 @@ var PdfDocumentParser = class {
7140
7501
  */
7141
7502
  resolveCatalog() {
7142
7503
  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}).`);
7504
+ if (rootObj.kind !== "dict") throw new PdfParseError({
7505
+ message: `Invalid PDF: /Root (catalog) at object ${this.trailer.rootRef.objectNumber} is not a dictionary (got ${rootObj.kind}).`,
7506
+ offset: 0,
7507
+ expected: "dictionary for /Root (catalog)",
7508
+ actual: `${rootObj.kind}`,
7509
+ data: this.data
7510
+ });
7144
7511
  const catalog = rootObj;
7145
7512
  const typeObj = catalog.get("/Type");
7146
7513
  if (typeObj !== void 0 && typeObj.kind === "name") {
7147
7514
  const typeName = typeObj.value;
7148
- if (typeName !== "/Catalog") throw new Error(`Invalid PDF: /Root dictionary has /Type "${typeName}", expected "/Catalog".`);
7515
+ if (typeName !== "/Catalog") throw new PdfParseError({
7516
+ message: `Invalid PDF: /Root dictionary has /Type "${typeName}", expected "/Catalog".`,
7517
+ offset: 0,
7518
+ expected: "/Type /Catalog in /Root dictionary",
7519
+ actual: `/Type "${typeName}"`,
7520
+ data: this.data
7521
+ });
7149
7522
  }
7150
7523
  return catalog;
7151
7524
  }
@@ -7159,9 +7532,21 @@ var PdfDocumentParser = class {
7159
7532
  */
7160
7533
  resolvePageTree(catalog) {
7161
7534
  const pagesRef = catalog.get("/Pages");
7162
- if (pagesRef === void 0) throw new Error("Invalid PDF: catalog dictionary missing /Pages entry.");
7535
+ if (pagesRef === void 0) throw new PdfParseError({
7536
+ message: "Invalid PDF: catalog dictionary missing /Pages entry.",
7537
+ offset: 0,
7538
+ expected: "/Pages entry in catalog dictionary",
7539
+ actual: "no /Pages entry",
7540
+ data: this.data
7541
+ });
7163
7542
  const pagesObj = this.resolveObject(pagesRef);
7164
- if (pagesObj.kind !== "dict") throw new Error(`Invalid PDF: /Pages entry is not a dictionary (got ${pagesObj.kind}).`);
7543
+ if (pagesObj.kind !== "dict") throw new PdfParseError({
7544
+ message: `Invalid PDF: /Pages entry is not a dictionary (got ${pagesObj.kind}).`,
7545
+ offset: 0,
7546
+ expected: "dictionary for /Pages entry",
7547
+ actual: `${pagesObj.kind}`,
7548
+ data: this.data
7549
+ });
7165
7550
  const pages = [];
7166
7551
  this.traversePageTree(pagesObj, {}, pages, /* @__PURE__ */ new Set());
7167
7552
  return pages;
@@ -7198,7 +7583,13 @@ var PdfDocumentParser = class {
7198
7583
  }
7199
7584
  if (typeName === "/Page") {
7200
7585
  const mediaBox = currentInherited.mediaBox;
7201
- if (mediaBox === void 0) throw new Error("Invalid PDF: /Page node has no /MediaBox (not even inherited).");
7586
+ if (mediaBox === void 0) throw new PdfParseError({
7587
+ message: "Invalid PDF: /Page node has no /MediaBox (not even inherited).",
7588
+ offset: 0,
7589
+ expected: "/MediaBox on page node or inherited from parent",
7590
+ actual: "no /MediaBox found",
7591
+ data: this.data
7592
+ });
7202
7593
  result.push({
7203
7594
  dict: node,
7204
7595
  mediaBox,
@@ -7210,7 +7601,13 @@ var PdfDocumentParser = class {
7210
7601
  const kidsObj = node.get("/Kids");
7211
7602
  if (kidsObj === void 0) return;
7212
7603
  const kids = this.resolveObject(kidsObj);
7213
- if (kids.kind !== "array") throw new Error(`Invalid PDF: /Pages /Kids is not an array (got ${kids.kind}).`);
7604
+ if (kids.kind !== "array") throw new PdfParseError({
7605
+ message: `Invalid PDF: /Pages /Kids is not an array (got ${kids.kind}).`,
7606
+ offset: 0,
7607
+ expected: "array for /Pages /Kids",
7608
+ actual: `${kids.kind}`,
7609
+ data: this.data
7610
+ });
7214
7611
  const kidsArr = kids;
7215
7612
  for (let i = 0; i < kidsArr.length; i++) {
7216
7613
  const kidRef = kidsArr.items[i];
@@ -7246,22 +7643,53 @@ var PdfDocumentParser = class {
7246
7643
  return require_pdfCatalog.PdfNull.instance;
7247
7644
  }
7248
7645
  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.`);
7646
+ if (containerEntry === void 0 || containerEntry.type !== "in-use") throw new PdfParseError({
7647
+ message: `Invalid PDF: object stream ${containerNum} referenced by compressed object ${entry.objectNumber} not found in xref table.`,
7648
+ offset: 0,
7649
+ expected: `in-use xref entry for object stream ${containerNum}`,
7650
+ actual: containerEntry ? `${containerEntry.type} entry` : "no entry",
7651
+ data: this.data
7652
+ });
7250
7653
  let containerObj;
7251
7654
  try {
7252
7655
  const { object } = this.objectParser.parseIndirectObjectAt(containerEntry.offset);
7253
7656
  containerObj = object;
7254
7657
  } catch (err) {
7255
- throw new Error(`Failed to parse object stream ${containerNum} at offset ${containerEntry.offset}`, { cause: err });
7658
+ throw new PdfParseError({
7659
+ message: `Failed to parse object stream ${containerNum} at offset ${containerEntry.offset}`,
7660
+ offset: containerEntry.offset,
7661
+ expected: `valid object stream ${containerNum}`,
7662
+ actual: "parse failure",
7663
+ data: this.data,
7664
+ cause: err instanceof Error ? err : void 0
7665
+ });
7256
7666
  }
7257
- if (containerObj.kind !== "stream") throw new Error(`Invalid PDF: object ${containerNum} expected to be an object stream but is ${containerObj.kind}.`);
7667
+ if (containerObj.kind !== "stream") throw new PdfParseError({
7668
+ message: `Invalid PDF: object ${containerNum} expected to be an object stream but is ${containerObj.kind}.`,
7669
+ offset: containerEntry.offset,
7670
+ expected: "stream object for object stream",
7671
+ actual: `${containerObj.kind}`,
7672
+ data: this.data
7673
+ });
7258
7674
  const containerStream = containerObj;
7259
7675
  const containerDict = containerStream.dict;
7260
7676
  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).`);
7677
+ if (typeObj === void 0 || typeObj.kind !== "name" || typeObj.value !== "/ObjStm") throw new PdfParseError({
7678
+ message: `Invalid PDF: object ${containerNum} is not an object stream (/Type /ObjStm).`,
7679
+ offset: containerEntry.offset,
7680
+ expected: "/Type /ObjStm in object stream dictionary",
7681
+ actual: typeObj ? `${typeObj.kind}` : "no /Type entry",
7682
+ data: this.data
7683
+ });
7262
7684
  const n = numVal$1(containerDict.get("/N"));
7263
7685
  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.`);
7686
+ if (n === void 0 || first === void 0) throw new PdfParseError({
7687
+ message: `Invalid PDF: object stream ${containerNum} missing /N or /First entries.`,
7688
+ offset: containerEntry.offset,
7689
+ expected: "/N and /First entries in object stream",
7690
+ actual: `${n === void 0 ? "no /N" : "/N present"}, ${first === void 0 ? "no /First" : "/First present"}`,
7691
+ data: this.data
7692
+ });
7265
7693
  const decompressedData = this.decompressStreamSync(containerStream);
7266
7694
  const headerTokens = TEXT_DECODER.decode(decompressedData.subarray(0, first)).trim().split(/\s+/);
7267
7695
  const objEntries = [];
@@ -7658,7 +8086,7 @@ function undoPngPredictorSync(data, columns) {
7658
8086
  * string.
7659
8087
  *
7660
8088
  * This is the primary entry point for parsing existing PDFs. It creates
7661
- * a {@link PdfDocumentParser}, runs the full parse pipeline, and returns
8089
+ * a `PdfDocumentParser`, runs the full parse pipeline, and returns
7662
8090
  * a populated {@link PdfDocument}.
7663
8091
  *
7664
8092
  * @param data The PDF data as a `Uint8Array`, `ArrayBuffer`, or a
@@ -14212,6 +14640,9 @@ function packBits(pixels, columns, blackIs1) {
14212
14640
  /**
14213
14641
  * Decode JBIG2Decode stream data.
14214
14642
  *
14643
+ * Uses the pure-JS decoder (synchronous). For optional WASM
14644
+ * acceleration, use {@link decodeJBIG2Async}.
14645
+ *
14215
14646
  * @param data - The JBIG2-encoded content stream bytes.
14216
14647
  * @param parms - Optional `/DecodeParms` dictionary. May contain a
14217
14648
  * `/JBIG2Globals` key with a PdfDict/stream holding
@@ -17536,6 +17967,93 @@ function embedPageAsFormXObject(page, sourceRegistry, targetRegistry, xObjectNam
17536
17967
  };
17537
17968
  }
17538
17969
 
17970
+ //#endregion
17971
+ //#region src/core/pdfDocumentEmbed.ts
17972
+ /**
17973
+ * @module core/pdfDocumentEmbed
17974
+ *
17975
+ * Pure helper functions for font CMap generation and image format
17976
+ * validation/parsing. Extracted from {@link pdfDocument} to keep the
17977
+ * PdfDocument class focused on high-level document management.
17978
+ */
17979
+ /**
17980
+ * Build a /ToUnicode CMap from a font's cmap table.
17981
+ * Maps glyph IDs (used as CIDs with Identity-H) to Unicode codepoints.
17982
+ *
17983
+ * @param cmapTable Mapping from Unicode codepoint to glyph ID.
17984
+ * @returns A CMap string suitable for a PDF /ToUnicode stream.
17985
+ */
17986
+ function buildToUnicodeCmap(cmapTable) {
17987
+ const gidToUnicode = /* @__PURE__ */ new Map();
17988
+ for (const [codepoint, gid] of cmapTable) if (!gidToUnicode.has(gid)) gidToUnicode.set(gid, codepoint);
17989
+ const entries = gidToUnicode.entries().toArray().sort((a, b) => a[0] - b[0]);
17990
+ const lines = [];
17991
+ lines.push("/CIDInit /ProcSet findresource begin");
17992
+ lines.push("12 dict begin");
17993
+ lines.push("begincmap");
17994
+ lines.push("/CIDSystemInfo");
17995
+ lines.push("<< /Registry (Adobe)");
17996
+ lines.push("/Ordering (UCS)");
17997
+ lines.push("/Supplement 0");
17998
+ lines.push(">> def");
17999
+ lines.push("/CMapName /Adobe-Identity-UCS def");
18000
+ lines.push("/CMapType 2 def");
18001
+ lines.push("1 begincodespacerange");
18002
+ lines.push("<0000> <FFFF>");
18003
+ lines.push("endcodespacerange");
18004
+ const CHUNK_SIZE = 100;
18005
+ for (let i = 0; i < entries.length; i += CHUNK_SIZE) {
18006
+ const chunk = entries.slice(i, i + CHUNK_SIZE);
18007
+ lines.push(`${chunk.length} beginbfchar`);
18008
+ for (const [gid, codepoint] of chunk) {
18009
+ const gidHex = gid.toString(16).padStart(4, "0").toUpperCase();
18010
+ const uniHex = codepoint.toString(16).padStart(4, "0").toUpperCase();
18011
+ lines.push(`<${gidHex}> <${uniHex}>`);
18012
+ }
18013
+ lines.push("endbfchar");
18014
+ }
18015
+ lines.push("endcmap");
18016
+ lines.push("CMapName currentdict /CMap defineresource pop");
18017
+ lines.push("end");
18018
+ lines.push("end");
18019
+ return lines.join("\n");
18020
+ }
18021
+ /**
18022
+ * Validate a JPEG file signature (SOI marker).
18023
+ *
18024
+ * @param data The raw file bytes.
18025
+ * @throws If the data is too short or the SOI marker is invalid.
18026
+ */
18027
+ function validateJpegSignature(data) {
18028
+ if (data.length < 2 || data[0] !== 255 || data[1] !== 216) throw new Error("Invalid JPEG: bad SOI marker");
18029
+ }
18030
+ /**
18031
+ * Parse width, height, and component count from a JPEG's SOF marker.
18032
+ *
18033
+ * @param data The raw JPEG file bytes.
18034
+ * @returns Width, height, and number of color components.
18035
+ */
18036
+ function parseJpegDimensions(data) {
18037
+ validateJpegSignature(data);
18038
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
18039
+ let offset = 2;
18040
+ while (offset < data.length - 1) {
18041
+ if (data[offset] !== 255) throw new Error("Invalid JPEG: expected marker");
18042
+ const marker = data[offset + 1];
18043
+ if (marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207) {
18044
+ const height = view.getUint16(offset + 5, false);
18045
+ return {
18046
+ width: view.getUint16(offset + 7, false),
18047
+ height,
18048
+ components: data[offset + 9]
18049
+ };
18050
+ }
18051
+ const segmentLength = view.getUint16(offset + 2, false);
18052
+ offset += 2 + segmentLength;
18053
+ }
18054
+ throw new Error("Invalid JPEG: SOF marker not found");
18055
+ }
18056
+
17539
18057
  //#endregion
17540
18058
  //#region src/core/pdfDocument.ts
17541
18059
  /**
@@ -17939,7 +18457,7 @@ var PdfDocument = class PdfDocument {
17939
18457
  cidFontDict.set("/DW", require_pdfCatalog.PdfNumber.of(Math.round(metrics.defaultWidth * scale)));
17940
18458
  cidFontDict.set("/CIDToGIDMap", require_pdfCatalog.PdfName.of("Identity"));
17941
18459
  const cidFontRef = this.registry.register(cidFontDict);
17942
- const toUnicodeCmapStr = this.buildToUnicodeCmap(metrics.cmapTable);
18460
+ const toUnicodeCmapStr = buildToUnicodeCmap(metrics.cmapTable);
17943
18461
  const toUnicodeStream = require_pdfCatalog.PdfStream.fromString(toUnicodeCmapStr);
17944
18462
  const toUnicodeRef = this.registry.register(toUnicodeStream);
17945
18463
  const type0Dict = new require_pdfCatalog.PdfDict();
@@ -18056,7 +18574,7 @@ var PdfDocument = class PdfDocument {
18056
18574
  cidFontDict.set("/W", wArray);
18057
18575
  cidFontDict.set("/DW", require_pdfCatalog.PdfNumber.of(Math.round(metrics.defaultWidth * scale)));
18058
18576
  const cidFontRef = this.registry.register(cidFontDict);
18059
- const toUnicodeCmapStr = this.buildToUnicodeCmap(metrics.cmapTable);
18577
+ const toUnicodeCmapStr = buildToUnicodeCmap(metrics.cmapTable);
18060
18578
  const toUnicodeStream = require_pdfCatalog.PdfStream.fromString(toUnicodeCmapStr);
18061
18579
  const toUnicodeRef = this.registry.register(toUnicodeStream);
18062
18580
  const type0Dict = new require_pdfCatalog.PdfDict();
@@ -18102,46 +18620,6 @@ var PdfDocument = class PdfDocument {
18102
18620
  return fontRef;
18103
18621
  }
18104
18622
  /**
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
18623
  * Embed a PNG image.
18146
18624
  *
18147
18625
  * Fully decodes the PNG (including filter reconstruction and alpha
@@ -18810,6 +19288,79 @@ var PdfDocument = class PdfDocument {
18810
19288
  addWatermark(this, options);
18811
19289
  }
18812
19290
  /**
19291
+ * Create a soft mask Form XObject that can be used with
19292
+ * {@link PdfPage.applySoftMask}.
19293
+ *
19294
+ * The builder callback receives a {@link SoftMaskBuilder} with methods
19295
+ * for generating grayscale content where white (`1`) represents fully
19296
+ * opaque regions and black (`0`) represents fully transparent regions.
19297
+ *
19298
+ * The returned {@link SoftMaskRef} is passed to
19299
+ * {@link PdfPage.applySoftMask} to activate the mask for subsequent
19300
+ * drawing operations on that page.
19301
+ *
19302
+ * @param width Width of the mask in points.
19303
+ * @param height Height of the mask in points.
19304
+ * @param builder Callback that draws the mask content.
19305
+ * @returns A reference to the soft mask Form XObject.
19306
+ *
19307
+ * @example
19308
+ * ```ts
19309
+ * const mask = doc.createSoftMask(200, 200, (b) => {
19310
+ * // White background = fully opaque
19311
+ * b.drawRectangle(0, 0, 200, 200, 1);
19312
+ * // Black circle = fully transparent hole
19313
+ * b.drawCircle(100, 100, 80, 0);
19314
+ * });
19315
+ * page.applySoftMask(mask);
19316
+ * page.drawRectangle({ x: 50, y: 50, width: 200, height: 200, color: rgb(1, 0, 0) });
19317
+ * page.clearSoftMask();
19318
+ * ```
19319
+ */
19320
+ createSoftMask(width, height, builder) {
19321
+ const maskOps = [];
19322
+ const kappa = .5522847498;
19323
+ builder({
19324
+ drawRectangle(x, y, w, h, gray) {
19325
+ maskOps.push(`${gray} g`);
19326
+ maskOps.push(`${x} ${y} ${w} ${h} re`);
19327
+ maskOps.push("f");
19328
+ },
19329
+ drawCircle(cx, cy, r, gray) {
19330
+ maskOps.push(`${gray} g`);
19331
+ const ox = r * kappa;
19332
+ const oy = r * kappa;
19333
+ maskOps.push(`${cx - r} ${cy} m`);
19334
+ maskOps.push(`${cx - r} ${cy + oy} ${cx - ox} ${cy + r} ${cx} ${cy + r} c`);
19335
+ maskOps.push(`${cx + ox} ${cy + r} ${cx + r} ${cy + oy} ${cx + r} ${cy} c`);
19336
+ maskOps.push(`${cx + r} ${cy - oy} ${cx + ox} ${cy - r} ${cx} ${cy - r} c`);
19337
+ maskOps.push(`${cx - ox} ${cy - r} ${cx - r} ${cy - oy} ${cx - r} ${cy} c`);
19338
+ maskOps.push("f");
19339
+ },
19340
+ pushRawOperators(ops) {
19341
+ maskOps.push(ops);
19342
+ }
19343
+ });
19344
+ const groupDict = new require_pdfCatalog.PdfDict();
19345
+ groupDict.set("/S", require_pdfCatalog.PdfName.of("Transparency"));
19346
+ groupDict.set("/CS", require_pdfCatalog.PdfName.of("DeviceGray"));
19347
+ const formDict = new require_pdfCatalog.PdfDict();
19348
+ formDict.set("/Type", require_pdfCatalog.PdfName.of("XObject"));
19349
+ formDict.set("/Subtype", require_pdfCatalog.PdfName.of("Form"));
19350
+ formDict.set("/BBox", require_pdfCatalog.PdfArray.fromNumbers([
19351
+ 0,
19352
+ 0,
19353
+ width,
19354
+ height
19355
+ ]));
19356
+ formDict.set("/Group", groupDict);
19357
+ const stream = require_pdfCatalog.PdfStream.fromString(maskOps.join("\n"), formDict);
19358
+ return {
19359
+ _tag: "softMask",
19360
+ ref: this.registry.register(stream)
19361
+ };
19362
+ }
19363
+ /**
18813
19364
  * Apply all pending redactions across all pages.
18814
19365
  *
18815
19366
  * Redaction marks are added to individual pages using
@@ -19044,30 +19595,6 @@ var PdfDocument = class PdfDocument {
19044
19595
  function createPdf() {
19045
19596
  return new PdfDocument();
19046
19597
  }
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
19598
 
19072
19599
  //#endregion
19073
19600
  //#region src/utils/pdfValueHelpers.ts
@@ -19811,7 +20338,7 @@ function compressStream(stream, level) {
19811
20338
  */
19812
20339
  async function saveDocumentIncremental(originalBytes, doc, options) {
19813
20340
  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);
20341
+ const { PdfPage: _PdfPage } = await Promise.resolve().then(() => require("./pdfPage-BebMv6fN.cjs")).then((n) => n.pdfPage_exports);
19815
20342
  const registry = doc.getRegistry();
19816
20343
  const structure = buildDocumentStructure(doc.getInternalPages().map((p) => p.finalize()), {
19817
20344
  producer: doc.getProducer(),
@@ -23355,10 +23882,10 @@ async function initWasm(options) {
23355
23882
  if (options === void 0 || typeof options === "string" || options instanceof URL) return;
23356
23883
  if (wasmInitialized) return;
23357
23884
  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 }) => {
23885
+ if (options.deflate || options.deflateWasm) inits.push(Promise.resolve().then(() => require("./libdeflateWasm-OkNoqBnO.cjs")).then((n) => n.libdeflateWasm_exports).then(async ({ initDeflateWasm }) => {
23359
23886
  await initDeflateWasm(options.deflateWasm);
23360
23887
  }));
23361
- if (options.png || options.pngWasm) inits.push(Promise.resolve().then(() => require("./pngEmbed-1RWu6KsO.cjs")).then((n) => n.pngEmbed_exports).then(async ({ initPngWasm }) => {
23888
+ if (options.png || options.pngWasm) inits.push(Promise.resolve().then(() => require("./pngEmbed-OYyOe_W0.cjs")).then((n) => n.pngEmbed_exports).then(async ({ initPngWasm }) => {
23362
23889
  await initPngWasm(options.pngWasm);
23363
23890
  }));
23364
23891
  if (options.fonts || options.fontWasm) inits.push(Promise.resolve().then(() => require("./fontSubset-pFc8Dueu.cjs")).then((n) => n.fontSubset_exports).then(async ({ initSubsetWasm }) => {
@@ -23417,6 +23944,7 @@ exports.PdfObjectRegistry = require_pdfCatalog.PdfObjectRegistry;
23417
23944
  exports.PdfOutlineItem = PdfOutlineItem;
23418
23945
  exports.PdfOutlineTree = PdfOutlineTree;
23419
23946
  exports.PdfPage = require_pdfPage.PdfPage;
23947
+ exports.PdfParseError = PdfParseError;
23420
23948
  exports.PdfPolyLineAnnotation = PdfPolyLineAnnotation;
23421
23949
  exports.PdfPolygonAnnotation = PdfPolygonAnnotation;
23422
23950
  exports.PdfRadioGroup = PdfRadioGroup;
@@ -23468,8 +23996,10 @@ exports.buildAnnotationDict = require_pdfPage.buildAnnotationDict;
23468
23996
  exports.buildCatalog = require_pdfCatalog.buildCatalog;
23469
23997
  exports.buildDocumentStructure = require_pdfCatalog.buildDocumentStructure;
23470
23998
  exports.buildEmbeddedFilesNameTree = buildEmbeddedFilesNameTree;
23999
+ exports.buildGradientObjects = require_pdfPage.buildGradientObjects;
23471
24000
  exports.buildInfoDict = require_pdfCatalog.buildInfoDict;
23472
24001
  exports.buildPageTree = require_pdfCatalog.buildPageTree;
24002
+ exports.buildPatternObjects = require_pdfPage.buildPatternObjects;
23473
24003
  exports.buildPkcs7Signature = buildPkcs7Signature;
23474
24004
  exports.buildTimestampRequest = buildTimestampRequest;
23475
24005
  exports.buildViewerPreferencesDict = buildViewerPreferencesDict;
@@ -23536,6 +24066,7 @@ exports.fillEvenOdd = require_pdfPage.fillEvenOdd;
23536
24066
  exports.fillEvenOddAndStroke = require_pdfPage.fillEvenOddAndStroke;
23537
24067
  exports.fillOp = require_pdfPage.fill;
23538
24068
  exports.findSignatures = findSignatures;
24069
+ exports.formatHexContext = formatHexContext;
23539
24070
  exports.formatPdfDate = require_pdfCatalog.formatPdfDate;
23540
24071
  exports.generateButtonAppearance = generateButtonAppearance;
23541
24072
  exports.generateCheckboxAppearance = generateCheckboxAppearance;
@@ -23568,6 +24099,7 @@ exports.layoutCombedText = layoutCombedText;
23568
24099
  exports.layoutMultilineText = layoutMultilineText;
23569
24100
  exports.layoutSinglelineText = layoutSinglelineText;
23570
24101
  exports.lineToOp = require_pdfPage.lineTo;
24102
+ exports.linearGradient = require_pdfPage.linearGradient;
23571
24103
  exports.linearizePdf = linearizePdf;
23572
24104
  exports.loadPdf = loadPdf;
23573
24105
  exports.markForRedaction = require_pdfPage.markForRedaction;
@@ -23589,6 +24121,7 @@ exports.parseXmpMetadata = parseXmpMetadata;
23589
24121
  exports.popGraphicsState = require_pdfPage.restoreState;
23590
24122
  exports.prepareForSigning = prepareForSigning;
23591
24123
  exports.pushGraphicsState = require_pdfPage.saveState;
24124
+ exports.radialGradient = require_pdfPage.radialGradient;
23592
24125
  exports.radians = require_pdfPage.radians;
23593
24126
  exports.radiansToDegrees = require_pdfPage.radiansToDegrees;
23594
24127
  exports.rc4 = rc4;
@@ -23653,6 +24186,7 @@ exports.splitPdf = splitPdf;
23653
24186
  exports.strokeOp = require_pdfPage.stroke;
23654
24187
  exports.summarizeIssues = summarizeIssues;
23655
24188
  exports.svgToPdfOperators = require_pdfPage.svgToPdfOperators;
24189
+ exports.tilingPattern = require_pdfPage.tilingPattern;
23656
24190
  exports.translateOp = require_pdfPage.translate;
23657
24191
  exports.validatePdfA = validatePdfA;
23658
24192
  exports.verifyOwnerPassword = verifyOwnerPassword;