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