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/README.md +7 -5
- package/dist/index.cjs +686 -152
- package/dist/index.d.cts +393 -10
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +393 -10
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +680 -153
- package/dist/{libdeflateWasm-CRFwmrSl.mjs → libdeflateWasm-DlHgU5oy.mjs} +2 -2
- package/dist/{libdeflateWasm-DeU6cupL.cjs → libdeflateWasm-OkNoqBnO.cjs} +2 -2
- package/dist/{loader-CZMj0gBy.mjs → loader-CQfoGFp9.mjs} +4 -3
- package/dist/{loader-DWwMj8jZ.cjs → loader-_fqS-TmT.cjs} +4 -3
- package/dist/{pdfPage-JiCJLV3x.mjs → pdfPage-B7vA518n.mjs} +644 -216
- package/dist/{pdfPage-BMGFx7Xd.cjs → pdfPage-BebMv6fN.cjs} +672 -214
- package/dist/{pngEmbed-CHyesD7i.mjs → pngEmbed-DTOqgEUC.mjs} +2 -2
- package/dist/{pngEmbed-1RWu6KsO.cjs → pngEmbed-OYyOe_W0.cjs} +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
-
const require_pdfPage = require('./pdfPage-
|
|
2
|
+
const require_pdfPage = require('./pdfPage-BebMv6fN.cjs');
|
|
3
3
|
const require_pdfCatalog = require('./pdfCatalog-y_XG8Hq1.cjs');
|
|
4
|
-
const require_libdeflateWasm = require('./libdeflateWasm-
|
|
4
|
+
const require_libdeflateWasm = require('./libdeflateWasm-OkNoqBnO.cjs');
|
|
5
5
|
const require_fontSubset = require('./fontSubset-pFc8Dueu.cjs');
|
|
6
|
-
const require_pngEmbed = require('./pngEmbed-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
3803
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
4387
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
4943
|
-
|
|
4944
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
7010
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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-
|
|
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-
|
|
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-
|
|
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;
|