@web-ts-toolkit/pdf-reader 0.43.0 → 0.48.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 +172 -38
- package/index.d.mts +163 -12
- package/index.mjs +642 -153
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -22,6 +22,41 @@ import { getDocument } from "pdfjs-dist";
|
|
|
22
22
|
// src/embeddedImages.ts
|
|
23
23
|
import { OPS, Util } from "pdfjs-dist";
|
|
24
24
|
|
|
25
|
+
// src/canvasGuards.ts
|
|
26
|
+
var MAX_TIMER_MS = 2147483647;
|
|
27
|
+
function resolveSafeCanvasDimensions(width, height, limit, code, subject) {
|
|
28
|
+
const pixelWidth = typeof width === "number" ? Math.ceil(width) : Number.NaN;
|
|
29
|
+
const pixelHeight = typeof height === "number" ? Math.ceil(height) : Number.NaN;
|
|
30
|
+
if (!Number.isSafeInteger(pixelWidth) || pixelWidth <= 0 || !Number.isSafeInteger(pixelHeight) || pixelHeight <= 0) {
|
|
31
|
+
throw new PdfReaderError(code, `${subject} has invalid canvas dimensions.`);
|
|
32
|
+
}
|
|
33
|
+
const pixels = pixelWidth * pixelHeight;
|
|
34
|
+
if (!Number.isSafeInteger(pixels) || pixels <= 0 || pixels > limit) {
|
|
35
|
+
const detail = Number.isSafeInteger(pixels) ? `${pixels}` : "unsafe";
|
|
36
|
+
throw new PdfReaderError(code, `${subject} requires ${detail} pixels; limit is ${limit}.`);
|
|
37
|
+
}
|
|
38
|
+
return { pixelWidth, pixelHeight, pixels };
|
|
39
|
+
}
|
|
40
|
+
function isValidDataUrlForMime(dataUrl, mimeType) {
|
|
41
|
+
if (typeof dataUrl !== "string") return false;
|
|
42
|
+
if (dataUrl === "data:,") return false;
|
|
43
|
+
if (!dataUrl.startsWith(`data:${mimeType}`)) return false;
|
|
44
|
+
const comma = dataUrl.indexOf(",");
|
|
45
|
+
if (comma === -1) return false;
|
|
46
|
+
if (comma === dataUrl.length - 1) return false;
|
|
47
|
+
const prefix = `data:${mimeType}`;
|
|
48
|
+
if (dataUrl.length <= prefix.length + 1) return false;
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
function isValidBlobForMime(blob, mimeType) {
|
|
52
|
+
if (blob === null || typeof blob !== "object") return false;
|
|
53
|
+
const candidate = blob;
|
|
54
|
+
if (typeof candidate.size !== "number" || typeof candidate.type !== "string") return false;
|
|
55
|
+
if (candidate.size <= 0) return false;
|
|
56
|
+
if (candidate.type !== mimeType) return false;
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
|
|
25
60
|
// src/geometry.ts
|
|
26
61
|
function getTransformedUnitBounds(transform) {
|
|
27
62
|
const [a, b, c, d, e, f] = transform;
|
|
@@ -50,8 +85,13 @@ var propagatedErrorCodes = /* @__PURE__ */ new Set([
|
|
|
50
85
|
"IMAGE_TOTAL_PIXELS_LIMIT_EXCEEDED",
|
|
51
86
|
"OPERATOR_LIMIT_EXCEEDED"
|
|
52
87
|
]);
|
|
88
|
+
var ImageKind = {
|
|
89
|
+
GRAYSCALE_1BPP: 1,
|
|
90
|
+
RGB_24BPP: 2,
|
|
91
|
+
RGBA_32BPP: 3
|
|
92
|
+
};
|
|
53
93
|
async function extractEmbeddedImages(page, viewport, options) {
|
|
54
|
-
const operators = await page.getOperatorList();
|
|
94
|
+
const operators = await options.awaitWithCancellation(page.getOperatorList());
|
|
55
95
|
enforceOperatorLimit(operators.fnArray.length, options.maxOperators);
|
|
56
96
|
const images = [];
|
|
57
97
|
const stack = [];
|
|
@@ -96,12 +136,12 @@ async function extractEmbeddedImages(page, viewport, options) {
|
|
|
96
136
|
if (encoded) {
|
|
97
137
|
enforceNextImageLimits(images.length, totalPixels, encoded.dimensions.pixels, options);
|
|
98
138
|
} else {
|
|
99
|
-
const paintedImage = await resolvePaintedImage(page, operation, args, index);
|
|
139
|
+
const paintedImage = await resolvePaintedImage(page, operation, args, index, options);
|
|
100
140
|
options.throwIfDestroyed();
|
|
101
141
|
options.throwIfAborted(options.signal);
|
|
102
142
|
if (!paintedImage) continue;
|
|
103
143
|
const dimensions = readImageDimensions(paintedImage.image, options.maxPixels);
|
|
104
|
-
if (!dimensions
|
|
144
|
+
if (!dimensions) {
|
|
105
145
|
warn(
|
|
106
146
|
options.logger,
|
|
107
147
|
`Skipped embedded image ${paintedImage.label}: unsupported PDF.js image shape or data layout.`
|
|
@@ -109,7 +149,15 @@ async function extractEmbeddedImages(page, viewport, options) {
|
|
|
109
149
|
continue;
|
|
110
150
|
}
|
|
111
151
|
enforceNextImageLimits(images.length, totalPixels, dimensions.pixels, options);
|
|
112
|
-
const
|
|
152
|
+
const normalized = normalizeImageSource(paintedImage.image, dimensions);
|
|
153
|
+
if (!normalized) {
|
|
154
|
+
warn(
|
|
155
|
+
options.logger,
|
|
156
|
+
`Skipped embedded image ${paintedImage.label}: unsupported PDF.js image shape or data layout.`
|
|
157
|
+
);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
const dataUrl = imageToDataUrl(normalized, dimensions, options);
|
|
113
161
|
if (!dataUrl) {
|
|
114
162
|
warn(
|
|
115
163
|
options.logger,
|
|
@@ -151,7 +199,7 @@ function readImageReference(args) {
|
|
|
151
199
|
const reference = Array.isArray(args) ? args[0] : void 0;
|
|
152
200
|
return typeof reference === "string" ? reference : void 0;
|
|
153
201
|
}
|
|
154
|
-
async function resolvePaintedImage(page, operation, args, index) {
|
|
202
|
+
async function resolvePaintedImage(page, operation, args, index, options) {
|
|
155
203
|
if (operation === OPS.paintInlineImageXObject) {
|
|
156
204
|
const inlineImage = Array.isArray(args) ? args[0] : void 0;
|
|
157
205
|
if (!inlineImage || typeof inlineImage !== "object") return void 0;
|
|
@@ -159,47 +207,126 @@ async function resolvePaintedImage(page, operation, args, index) {
|
|
|
159
207
|
}
|
|
160
208
|
const reference = readImageReference(args);
|
|
161
209
|
if (!reference) return void 0;
|
|
162
|
-
const image = await page
|
|
210
|
+
const image = await awaitResolvedImageObject(selectImageStore(page, reference), reference, options);
|
|
211
|
+
if (!image || typeof image !== "object") return void 0;
|
|
163
212
|
return { image, label: reference, reference };
|
|
164
213
|
}
|
|
165
|
-
function
|
|
214
|
+
function selectImageStore(page, reference) {
|
|
215
|
+
if (reference.startsWith("g_") && page.commonObjs) return page.commonObjs;
|
|
216
|
+
return page.objs;
|
|
217
|
+
}
|
|
218
|
+
async function awaitResolvedImageObject(store, reference, options) {
|
|
219
|
+
if (typeof store?.has === "function" && store.has(reference)) {
|
|
220
|
+
return store.get(reference);
|
|
221
|
+
}
|
|
222
|
+
if (typeof store?.has !== "function") {
|
|
223
|
+
return store.get(reference);
|
|
224
|
+
}
|
|
225
|
+
return options.awaitWithCancellation(
|
|
226
|
+
new Promise((resolve, reject) => {
|
|
227
|
+
try {
|
|
228
|
+
store.get(reference, (data) => resolve(data));
|
|
229
|
+
} catch (error) {
|
|
230
|
+
reject(error);
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
function imageToDataUrl(normalized, dimensions, options) {
|
|
166
236
|
const canvas = allocateCanvas(dimensions.width, dimensions.height, options.maxPixels, options.createCanvas);
|
|
167
237
|
try {
|
|
168
238
|
const context = canvas.getContext("2d");
|
|
169
239
|
if (!context) return void 0;
|
|
170
|
-
if (
|
|
171
|
-
context.drawImage(
|
|
172
|
-
|
|
240
|
+
if (normalized.format === "bitmap") {
|
|
241
|
+
context.drawImage(normalized.bitmap, 0, 0);
|
|
242
|
+
const dataUrl2 = canvas.toDataURL("image/png");
|
|
243
|
+
return isValidDataUrlForMime(dataUrl2, "image/png") ? dataUrl2 : void 0;
|
|
173
244
|
}
|
|
174
|
-
if (!ArrayBuffer.isView(image.data)) return void 0;
|
|
175
|
-
const source = new Uint8ClampedArray(image.data.buffer, image.data.byteOffset, image.data.byteLength);
|
|
176
|
-
const rgba = toRgba(source, dimensions);
|
|
177
|
-
if (!rgba) return void 0;
|
|
178
245
|
const pixels = context.createImageData(dimensions.width, dimensions.height);
|
|
179
|
-
pixels.data.set(rgba);
|
|
246
|
+
pixels.data.set(normalized.rgba);
|
|
180
247
|
context.putImageData(pixels, 0, 0);
|
|
181
|
-
|
|
248
|
+
const dataUrl = canvas.toDataURL("image/png");
|
|
249
|
+
return isValidDataUrlForMime(dataUrl, "image/png") ? dataUrl : void 0;
|
|
182
250
|
} finally {
|
|
183
251
|
releaseCanvas(canvas);
|
|
184
252
|
}
|
|
185
253
|
}
|
|
186
|
-
function
|
|
254
|
+
function normalizeImageSource(image, dimensions) {
|
|
255
|
+
if (typeof ImageBitmap !== "undefined" && image.bitmap instanceof ImageBitmap) {
|
|
256
|
+
return { format: "bitmap", bitmap: image.bitmap };
|
|
257
|
+
}
|
|
258
|
+
if (!ArrayBuffer.isView(image.data)) return void 0;
|
|
259
|
+
const source = new Uint8ClampedArray(image.data.buffer, image.data.byteOffset, image.data.byteLength);
|
|
260
|
+
const kind = typeof image.kind === "number" ? image.kind : void 0;
|
|
261
|
+
if (kind === ImageKind.RGBA_32BPP) {
|
|
262
|
+
const rgbaLength2 = multiplySafe(dimensions.pixels, 4);
|
|
263
|
+
if (rgbaLength2 === void 0 || source.length !== rgbaLength2) return void 0;
|
|
264
|
+
return { format: "rgba", rgba: source };
|
|
265
|
+
}
|
|
266
|
+
if (kind === ImageKind.RGB_24BPP) {
|
|
267
|
+
const rgbLength2 = multiplySafe(dimensions.pixels, 3);
|
|
268
|
+
const rgbaLength2 = multiplySafe(dimensions.pixels, 4);
|
|
269
|
+
if (rgbLength2 === void 0 || rgbaLength2 === void 0 || source.length !== rgbLength2) return void 0;
|
|
270
|
+
return { format: "rgba", rgba: expandRgbToRgba(source, dimensions.pixels, rgbaLength2) };
|
|
271
|
+
}
|
|
272
|
+
if (kind === ImageKind.GRAYSCALE_1BPP) {
|
|
273
|
+
const rowBytes = Math.ceil(dimensions.width / 8);
|
|
274
|
+
const packedLength = multiplySafe(rowBytes, dimensions.height);
|
|
275
|
+
const rgbaLength2 = multiplySafe(dimensions.pixels, 4);
|
|
276
|
+
if (packedLength === void 0 || rgbaLength2 === void 0 || source.length !== packedLength) return void 0;
|
|
277
|
+
return { format: "rgba", rgba: unpackOneBitToRgba(source, dimensions, rowBytes, rgbaLength2) };
|
|
278
|
+
}
|
|
279
|
+
if (kind !== void 0) return void 0;
|
|
187
280
|
const rgbaLength = multiplySafe(dimensions.pixels, 4);
|
|
188
281
|
const rgbLength = multiplySafe(dimensions.pixels, 3);
|
|
189
282
|
if (rgbaLength === void 0 || rgbLength === void 0) {
|
|
190
283
|
throw new PdfReaderError("IMAGE_LIMIT_EXCEEDED", "embedded image has unsafe decoded pixel dimensions.");
|
|
191
284
|
}
|
|
192
|
-
if (
|
|
193
|
-
if (
|
|
194
|
-
|
|
285
|
+
if (source.length === rgbaLength) return { format: "rgba", rgba: source };
|
|
286
|
+
if (source.length === rgbLength)
|
|
287
|
+
return { format: "rgba", rgba: expandRgbToRgba(source, dimensions.pixels, rgbaLength) };
|
|
288
|
+
if (source.length === dimensions.pixels) {
|
|
289
|
+
return { format: "rgba", rgba: expandGray8ToRgba(source, dimensions.pixels, rgbaLength) };
|
|
290
|
+
}
|
|
291
|
+
return void 0;
|
|
292
|
+
}
|
|
293
|
+
function expandRgbToRgba(source, pixels, rgbaLength) {
|
|
294
|
+
const rgba = new Uint8ClampedArray(rgbaLength);
|
|
295
|
+
for (let pixel = 0; pixel < pixels; pixel += 1) {
|
|
296
|
+
const input = pixel * 3;
|
|
297
|
+
const output = pixel * 4;
|
|
298
|
+
rgba[output] = source[input] ?? 0;
|
|
299
|
+
rgba[output + 1] = source[input + 1] ?? 0;
|
|
300
|
+
rgba[output + 2] = source[input + 2] ?? 0;
|
|
301
|
+
rgba[output + 3] = 255;
|
|
302
|
+
}
|
|
303
|
+
return rgba;
|
|
304
|
+
}
|
|
305
|
+
function expandGray8ToRgba(source, pixels, rgbaLength) {
|
|
195
306
|
const rgba = new Uint8ClampedArray(rgbaLength);
|
|
196
|
-
for (let pixel = 0; pixel <
|
|
197
|
-
const input = pixel * channels;
|
|
307
|
+
for (let pixel = 0; pixel < pixels; pixel += 1) {
|
|
198
308
|
const output = pixel * 4;
|
|
199
|
-
|
|
200
|
-
rgba[output
|
|
201
|
-
rgba[output +
|
|
202
|
-
rgba[output +
|
|
309
|
+
const gray = source[pixel] ?? 0;
|
|
310
|
+
rgba[output] = gray;
|
|
311
|
+
rgba[output + 1] = gray;
|
|
312
|
+
rgba[output + 2] = gray;
|
|
313
|
+
rgba[output + 3] = 255;
|
|
314
|
+
}
|
|
315
|
+
return rgba;
|
|
316
|
+
}
|
|
317
|
+
function unpackOneBitToRgba(packed, dimensions, rowBytes, rgbaLength) {
|
|
318
|
+
const rgba = new Uint8ClampedArray(rgbaLength);
|
|
319
|
+
for (let row = 0; row < dimensions.height; row += 1) {
|
|
320
|
+
for (let column = 0; column < dimensions.width; column += 1) {
|
|
321
|
+
const byte = packed[row * rowBytes + (column >> 3)] ?? 0;
|
|
322
|
+
const bit = byte >> 7 - (column & 7) & 1;
|
|
323
|
+
const value = bit === 1 ? 255 : 0;
|
|
324
|
+
const output = (row * dimensions.width + column) * 4;
|
|
325
|
+
rgba[output] = value;
|
|
326
|
+
rgba[output + 1] = value;
|
|
327
|
+
rgba[output + 2] = value;
|
|
328
|
+
rgba[output + 3] = 255;
|
|
329
|
+
}
|
|
203
330
|
}
|
|
204
331
|
return rgba;
|
|
205
332
|
}
|
|
@@ -228,32 +355,39 @@ function readImageDimensions(image, limit) {
|
|
|
228
355
|
const { width, height } = image;
|
|
229
356
|
if (width === void 0 || height === void 0) return void 0;
|
|
230
357
|
if (typeof width !== "number" || typeof height !== "number") return void 0;
|
|
231
|
-
const pixelWidth =
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
358
|
+
const { pixelWidth, pixelHeight, pixels } = resolveSafeCanvasDimensions(
|
|
359
|
+
width,
|
|
360
|
+
height,
|
|
361
|
+
limit,
|
|
362
|
+
"IMAGE_LIMIT_EXCEEDED",
|
|
363
|
+
"embedded image"
|
|
364
|
+
);
|
|
237
365
|
return { width: pixelWidth, height: pixelHeight, pixels };
|
|
238
366
|
}
|
|
239
|
-
function isSupportedImageSource(image) {
|
|
240
|
-
return typeof ImageBitmap !== "undefined" && image.bitmap instanceof ImageBitmap || ArrayBuffer.isView(image.data);
|
|
241
|
-
}
|
|
242
367
|
function multiplySafe(left, right) {
|
|
243
368
|
if (!Number.isSafeInteger(left) || !Number.isSafeInteger(right)) return void 0;
|
|
244
369
|
const product = left * right;
|
|
245
370
|
return Number.isSafeInteger(product) ? product : void 0;
|
|
246
371
|
}
|
|
247
372
|
function allocateCanvas(width, height, limit, createCanvas) {
|
|
248
|
-
const pixelWidth =
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
373
|
+
const { pixelWidth, pixelHeight } = resolveSafeCanvasDimensions(
|
|
374
|
+
width,
|
|
375
|
+
height,
|
|
376
|
+
limit,
|
|
377
|
+
"IMAGE_LIMIT_EXCEEDED",
|
|
378
|
+
"embedded image"
|
|
379
|
+
);
|
|
254
380
|
const canvas = createCanvas();
|
|
255
|
-
|
|
256
|
-
|
|
381
|
+
try {
|
|
382
|
+
canvas.width = pixelWidth;
|
|
383
|
+
canvas.height = pixelHeight;
|
|
384
|
+
} catch (error) {
|
|
385
|
+
try {
|
|
386
|
+
releaseCanvas(canvas);
|
|
387
|
+
} catch {
|
|
388
|
+
}
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
257
391
|
return canvas;
|
|
258
392
|
}
|
|
259
393
|
function imageByteLength(image) {
|
|
@@ -299,8 +433,34 @@ function warn(logger, message, error) {
|
|
|
299
433
|
logger?.warn(message, error);
|
|
300
434
|
}
|
|
301
435
|
|
|
436
|
+
// src/signal.ts
|
|
437
|
+
function resolveSignal(value) {
|
|
438
|
+
if (value === void 0) return void 0;
|
|
439
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
440
|
+
const candidate = value;
|
|
441
|
+
if (typeof candidate.aborted === "boolean" && typeof candidate.addEventListener === "function" && typeof candidate.removeEventListener === "function") {
|
|
442
|
+
return candidate;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
throw new PdfReaderError(
|
|
446
|
+
"INVALID_OPTION",
|
|
447
|
+
"signal must have a boolean aborted and callable addEventListener/removeEventListener methods; omit it or use undefined for no signal."
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
302
451
|
// src/options.ts
|
|
303
452
|
function resolveConvertOptions(options) {
|
|
453
|
+
if (options === null || typeof options !== "object" || Array.isArray(options)) {
|
|
454
|
+
throw new PdfReaderError("INVALID_OPTION", "Convert options must be an object.");
|
|
455
|
+
}
|
|
456
|
+
const raw = options;
|
|
457
|
+
if (raw.pageRange !== void 0) validatePageRange(raw.pageRange);
|
|
458
|
+
if (raw.viewportScale !== void 0) validateViewportScaleShape(raw.viewportScale);
|
|
459
|
+
if (raw.imageFormat !== void 0) validateImageFormat(raw.imageFormat);
|
|
460
|
+
if (raw.pageImageOutput !== void 0) validatePageImageOutput(raw.pageImageOutput);
|
|
461
|
+
validateBooleanFlag(raw.includePageImage, "includePageImage");
|
|
462
|
+
validateBooleanFlag(raw.includeText, "includeText");
|
|
463
|
+
validateBooleanFlag(raw.includeEmbeddedImages, "includeEmbeddedImages");
|
|
304
464
|
const resolved = {
|
|
305
465
|
pageRange: options.pageRange,
|
|
306
466
|
viewportScale: options.viewportScale ?? 1.5,
|
|
@@ -310,10 +470,12 @@ function resolveConvertOptions(options) {
|
|
|
310
470
|
pageImageOutput: options.pageImageOutput ?? "data-url",
|
|
311
471
|
includeText: options.includeText ?? true,
|
|
312
472
|
includeEmbeddedImages: options.includeEmbeddedImages ?? false,
|
|
313
|
-
signal:
|
|
473
|
+
signal: resolveSignal(raw.signal)
|
|
314
474
|
};
|
|
315
475
|
if (typeof resolved.viewportScale === "number") {
|
|
316
476
|
assertPositiveFinite(resolved.viewportScale, "viewportScale");
|
|
477
|
+
} else if (typeof resolved.viewportScale !== "function") {
|
|
478
|
+
throw new PdfReaderError("INVALID_OPTION", "viewportScale must be a positive finite number or a function.");
|
|
317
479
|
}
|
|
318
480
|
if (!Number.isFinite(resolved.jpegQuality) || resolved.jpegQuality < 0 || resolved.jpegQuality > 1) {
|
|
319
481
|
throw new PdfReaderError("INVALID_OPTION", "jpegQuality must be a finite number from 0 through 1.");
|
|
@@ -321,13 +483,22 @@ function resolveConvertOptions(options) {
|
|
|
321
483
|
if (resolved.pageImageOutput !== "data-url" && resolved.pageImageOutput !== "blob") {
|
|
322
484
|
throw new PdfReaderError("INVALID_OPTION", 'pageImageOutput must be either "data-url" or "blob".');
|
|
323
485
|
}
|
|
486
|
+
if (resolved.imageFormat !== "image/png" && resolved.imageFormat !== "image/jpeg") {
|
|
487
|
+
throw new PdfReaderError("INVALID_OPTION", 'imageFormat must be either "image/png" or "image/jpeg".');
|
|
488
|
+
}
|
|
324
489
|
validatePageRange(resolved.pageRange);
|
|
325
490
|
return resolved;
|
|
326
491
|
}
|
|
327
492
|
function resolvePageNumbers(pageRange, numPages) {
|
|
328
493
|
if (pageRange === void 0) return [1, numPages];
|
|
329
494
|
if (typeof pageRange === "number") return [pageRange, pageRange];
|
|
330
|
-
|
|
495
|
+
if (!Array.isArray(pageRange) || pageRange.length !== 2) {
|
|
496
|
+
throw new PdfReaderError("INVALID_OPTION", "pageRange tuple must have exactly two page numbers.");
|
|
497
|
+
}
|
|
498
|
+
return [
|
|
499
|
+
Math.min(pageRange[0], pageRange[1]),
|
|
500
|
+
Math.max(pageRange[0], pageRange[1])
|
|
501
|
+
];
|
|
331
502
|
}
|
|
332
503
|
function assertPositiveFinite(value, option) {
|
|
333
504
|
if (!Number.isFinite(value) || value <= 0) {
|
|
@@ -336,11 +507,130 @@ function assertPositiveFinite(value, option) {
|
|
|
336
507
|
}
|
|
337
508
|
function validatePageRange(pageRange) {
|
|
338
509
|
if (pageRange === void 0) return;
|
|
339
|
-
|
|
340
|
-
|
|
510
|
+
if (typeof pageRange === "number") {
|
|
511
|
+
if (!Number.isSafeInteger(pageRange) || pageRange < 1) {
|
|
512
|
+
throw new PdfReaderError("INVALID_OPTION", "pageRange values must be positive safe integers.");
|
|
513
|
+
}
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (!Array.isArray(pageRange)) {
|
|
517
|
+
throw new PdfReaderError("INVALID_OPTION", "pageRange must be a page number or a two-element tuple.");
|
|
518
|
+
}
|
|
519
|
+
if (pageRange.length !== 2) {
|
|
520
|
+
throw new PdfReaderError("INVALID_OPTION", "pageRange tuple must have exactly two page numbers.");
|
|
521
|
+
}
|
|
522
|
+
if (!(0 in pageRange) || !(1 in pageRange)) {
|
|
523
|
+
throw new PdfReaderError("INVALID_OPTION", "pageRange tuple must not be sparse.");
|
|
524
|
+
}
|
|
525
|
+
if (pageRange.some((value) => !Number.isSafeInteger(value) || value < 1)) {
|
|
341
526
|
throw new PdfReaderError("INVALID_OPTION", "pageRange values must be positive safe integers.");
|
|
342
527
|
}
|
|
343
528
|
}
|
|
529
|
+
function validateViewportScaleShape(value) {
|
|
530
|
+
if (typeof value === "number" || typeof value === "function") return;
|
|
531
|
+
throw new PdfReaderError("INVALID_OPTION", "viewportScale must be a positive finite number or a function.");
|
|
532
|
+
}
|
|
533
|
+
function validateImageFormat(value) {
|
|
534
|
+
if (value === "image/png" || value === "image/jpeg") return;
|
|
535
|
+
throw new PdfReaderError("INVALID_OPTION", 'imageFormat must be either "image/png" or "image/jpeg".');
|
|
536
|
+
}
|
|
537
|
+
function validatePageImageOutput(value) {
|
|
538
|
+
if (value === "data-url" || value === "blob") return;
|
|
539
|
+
throw new PdfReaderError("INVALID_OPTION", 'pageImageOutput must be either "data-url" or "blob".');
|
|
540
|
+
}
|
|
541
|
+
function validateBooleanFlag(value, option) {
|
|
542
|
+
if (value === void 0) return;
|
|
543
|
+
if (typeof value !== "boolean") {
|
|
544
|
+
throw new PdfReaderError("INVALID_OPTION", `${option} must be a boolean.`);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// src/pageResources.ts
|
|
549
|
+
var _owners, _closed, _pages, _cleanedAfterClose, _PageLifetime_instances, cleanup_fn;
|
|
550
|
+
var PageLifetime = class {
|
|
551
|
+
constructor(onIdle) {
|
|
552
|
+
this.onIdle = onIdle;
|
|
553
|
+
__privateAdd(this, _PageLifetime_instances);
|
|
554
|
+
__privateAdd(this, _owners, 0);
|
|
555
|
+
__privateAdd(this, _closed, false);
|
|
556
|
+
__privateAdd(this, _pages, /* @__PURE__ */ new Set());
|
|
557
|
+
__privateAdd(this, _cleanedAfterClose, /* @__PURE__ */ new WeakSet());
|
|
558
|
+
}
|
|
559
|
+
retain() {
|
|
560
|
+
__privateSet(this, _owners, __privateGet(this, _owners) + 1);
|
|
561
|
+
let released = false;
|
|
562
|
+
return () => {
|
|
563
|
+
if (released) return;
|
|
564
|
+
released = true;
|
|
565
|
+
__privateSet(this, _owners, __privateGet(this, _owners) - 1);
|
|
566
|
+
if (__privateGet(this, _owners) === 0 && !__privateGet(this, _closed)) {
|
|
567
|
+
this.onIdle();
|
|
568
|
+
this.close();
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
/** Observe the original promise, not the caller's cancellation race. */
|
|
573
|
+
track(pending, accept) {
|
|
574
|
+
const release = this.retain();
|
|
575
|
+
pending.then((value) => {
|
|
576
|
+
try {
|
|
577
|
+
accept?.(value);
|
|
578
|
+
} finally {
|
|
579
|
+
release();
|
|
580
|
+
}
|
|
581
|
+
}, release).catch(() => void 0);
|
|
582
|
+
return pending;
|
|
583
|
+
}
|
|
584
|
+
acquire(start) {
|
|
585
|
+
return this.track(start(), (page) => {
|
|
586
|
+
if (__privateGet(this, _closed)) __privateMethod(this, _PageLifetime_instances, cleanup_fn).call(this, page);
|
|
587
|
+
else __privateGet(this, _pages).add(page);
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
close() {
|
|
591
|
+
__privateSet(this, _closed, true);
|
|
592
|
+
for (const page of __privateGet(this, _pages)) __privateMethod(this, _PageLifetime_instances, cleanup_fn).call(this, page);
|
|
593
|
+
__privateGet(this, _pages).clear();
|
|
594
|
+
}
|
|
595
|
+
};
|
|
596
|
+
_owners = new WeakMap();
|
|
597
|
+
_closed = new WeakMap();
|
|
598
|
+
_pages = new WeakMap();
|
|
599
|
+
_cleanedAfterClose = new WeakMap();
|
|
600
|
+
_PageLifetime_instances = new WeakSet();
|
|
601
|
+
cleanup_fn = function(page) {
|
|
602
|
+
if (__privateGet(this, _cleanedAfterClose).has(page)) return;
|
|
603
|
+
__privateGet(this, _cleanedAfterClose).add(page);
|
|
604
|
+
try {
|
|
605
|
+
page.cleanup();
|
|
606
|
+
} catch {
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
var _pages2;
|
|
610
|
+
var PageResources = class {
|
|
611
|
+
constructor() {
|
|
612
|
+
__privateAdd(this, _pages2, /* @__PURE__ */ new Map());
|
|
613
|
+
}
|
|
614
|
+
acquire(pageNumber) {
|
|
615
|
+
let lifetime = __privateGet(this, _pages2).get(pageNumber);
|
|
616
|
+
if (!lifetime) {
|
|
617
|
+
lifetime = new PageLifetime(() => __privateGet(this, _pages2).delete(pageNumber));
|
|
618
|
+
__privateGet(this, _pages2).set(pageNumber, lifetime);
|
|
619
|
+
}
|
|
620
|
+
const release = lifetime.retain();
|
|
621
|
+
return {
|
|
622
|
+
acquire: (start) => lifetime.acquire(start),
|
|
623
|
+
track: (pending) => lifetime.track(pending),
|
|
624
|
+
release
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
/** Document destruction is authoritative; do not await orphaned promises. */
|
|
628
|
+
destroy() {
|
|
629
|
+
for (const lifetime of __privateGet(this, _pages2).values()) lifetime.close();
|
|
630
|
+
__privateGet(this, _pages2).clear();
|
|
631
|
+
}
|
|
632
|
+
};
|
|
633
|
+
_pages2 = new WeakMap();
|
|
344
634
|
|
|
345
635
|
// src/PDFReader.ts
|
|
346
636
|
var defaultLimits = {
|
|
@@ -353,7 +643,31 @@ var defaultLimits = {
|
|
|
353
643
|
maxEmbeddedImages: 1e3,
|
|
354
644
|
maxEmbeddedImagePixelsTotal: 1e8
|
|
355
645
|
};
|
|
356
|
-
|
|
646
|
+
function resolveLimits(limits) {
|
|
647
|
+
const resolved = { ...defaultLimits };
|
|
648
|
+
if (limits === void 0 || limits === null) return resolved;
|
|
649
|
+
for (const name of Object.keys(defaultLimits)) {
|
|
650
|
+
const supplied = limits[name];
|
|
651
|
+
if (supplied === void 0) continue;
|
|
652
|
+
if (!Number.isSafeInteger(supplied) || supplied <= 0) {
|
|
653
|
+
throw new PdfReaderError("INVALID_OPTION", `${name} must be a positive safe integer.`);
|
|
654
|
+
}
|
|
655
|
+
resolved[name] = supplied;
|
|
656
|
+
}
|
|
657
|
+
const maxSourceBytes = limits.maxSourceBytes;
|
|
658
|
+
if (maxSourceBytes === void 0) return resolved;
|
|
659
|
+
if (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0) {
|
|
660
|
+
throw new PdfReaderError("INVALID_OPTION", "maxSourceBytes must be a positive safe integer.");
|
|
661
|
+
}
|
|
662
|
+
resolved.maxSourceBytes = maxSourceBytes;
|
|
663
|
+
return resolved;
|
|
664
|
+
}
|
|
665
|
+
var InterruptedRender = class {
|
|
666
|
+
constructor(reason) {
|
|
667
|
+
this.reason = reason;
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
var _source, _createCanvas, _logger, _limits, _sourcePolicy, _loadingState, _loadingTask, _document, _destroyPromise, _destroyController, _activeRenderTasks, _pageResources, _activePageOperation, _activePageWorkCount, _destroyed, _lastLoadFailed, _PDFReader_instances, load_fn, processPage_fn, enforceTextLimits_fn, encodePageImage_fn, resolveViewport_fn, encodeCanvasToBlob_fn, createCanvasWithSignal_fn, allocateCanvas_fn, waitForRender_fn, releaseCanvas_fn, acquirePageOperation_fn, releasePageOperation_fn, getOrCreateLoadState_fn, destroyLoadStateTask_fn, awaitWithSignal_fn, awaitWithDestroy_fn, createAbortedError_fn, createDestroyedError_fn, createDeadlineExceededError_fn, createUnsupportedEnvironmentError_fn, rethrowLifecycleError_fn, throwIfDestroyed_fn, throwIfAborted_fn, resolveLoadOptions_fn, enforceSourcePolicy_fn, throwIfOverSourceLimit_fn, createSourceSnapshot_fn, inspectSource_fn, sourceKind_fn, toPdfJsSource_fn, freezeSource_fn, isFetchHeaders_fn, isPdfTypedArray_fn, knownByteLength_fn, readUrl_fn, readRawHttpHeaders_fn, snapshotHttpHeaders_fn;
|
|
357
671
|
var PDFReader = class {
|
|
358
672
|
constructor(source, options = {}) {
|
|
359
673
|
__privateAdd(this, _PDFReader_instances);
|
|
@@ -368,6 +682,7 @@ var PDFReader = class {
|
|
|
368
682
|
__privateAdd(this, _destroyPromise);
|
|
369
683
|
__privateAdd(this, _destroyController, new AbortController());
|
|
370
684
|
__privateAdd(this, _activeRenderTasks, /* @__PURE__ */ new Set());
|
|
685
|
+
__privateAdd(this, _pageResources, new PageResources());
|
|
371
686
|
__privateAdd(this, _activePageOperation, false);
|
|
372
687
|
__privateAdd(this, _activePageWorkCount, 0);
|
|
373
688
|
__privateAdd(this, _destroyed, false);
|
|
@@ -375,9 +690,8 @@ var PDFReader = class {
|
|
|
375
690
|
__privateSet(this, _source, source);
|
|
376
691
|
__privateSet(this, _createCanvas, options.canvasFactory ?? (() => document.createElement("canvas")));
|
|
377
692
|
__privateSet(this, _logger, options.logger);
|
|
378
|
-
__privateSet(this, _limits,
|
|
693
|
+
__privateSet(this, _limits, resolveLimits(options.limits));
|
|
379
694
|
__privateSet(this, _sourcePolicy, options.sourcePolicy);
|
|
380
|
-
__privateMethod(this, _PDFReader_instances, validateLimits_fn).call(this);
|
|
381
695
|
}
|
|
382
696
|
get numPages() {
|
|
383
697
|
return __privateGet(this, _document)?.numPages;
|
|
@@ -392,13 +706,37 @@ var PDFReader = class {
|
|
|
392
706
|
return "new";
|
|
393
707
|
}
|
|
394
708
|
load(options) {
|
|
709
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
395
710
|
const resolved = __privateMethod(this, _PDFReader_instances, resolveLoadOptions_fn).call(this, options);
|
|
396
711
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, resolved.signal);
|
|
397
|
-
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
398
712
|
if (__privateGet(this, _document)) return Promise.resolve(__privateGet(this, _document));
|
|
399
713
|
return __privateMethod(this, _PDFReader_instances, load_fn).call(this, resolved);
|
|
400
714
|
}
|
|
401
|
-
/**
|
|
715
|
+
/**
|
|
716
|
+
* Streams page results so callers do not need to retain the entire document conversion in memory.
|
|
717
|
+
*
|
|
718
|
+
* Page-stage waits (`getPage`, text, operator list, render, encoding) settle
|
|
719
|
+
* promptly with `ABORTED`/`DESTROYED` via the shared cancellation/wait
|
|
720
|
+
* contract. Active renders are cancelled; racing other PDF.js work does not
|
|
721
|
+
* stop it. Already-started promises remain observed even if a synchronous
|
|
722
|
+
* callback aborts/destroys before wait registration. Late `getPage()` values
|
|
723
|
+
* are never processed; late text/operator values are dropped. Page cleanup
|
|
724
|
+
* is deferred until package-owned acquisitions, processing, and upstream
|
|
725
|
+
* stage promises for that cached page are idle, including safe retries.
|
|
726
|
+
* Canvas factories and viewport callbacks are followed by lifecycle checks
|
|
727
|
+
* before subsequent allocation/rendering. Caller settlement releases the
|
|
728
|
+
* operation lock, but does not imply upstream work has finished.
|
|
729
|
+
* Cancellation/failure of an already-created render permanently closes the
|
|
730
|
+
* reader and starts public PDF.js teardown. The initiating call retains
|
|
731
|
+
* `ABORTED` or the native error; later operations reject `DESTROYED`. Retry
|
|
732
|
+
* with a fresh reader and fresh bytes (PDF.js may have transferred the input).
|
|
733
|
+
* Pre-render and non-render failures, and encoding cancellation/failure after
|
|
734
|
+
* successful rendering, do not automatically close the reader.
|
|
735
|
+
* A suspended generator only observes abort/destroy on the next
|
|
736
|
+
* `next()`/`return()`; destruction cannot force suspended consumer code to run.
|
|
737
|
+
* Malformed signals (including `null`) reject with `INVALID_OPTION` before
|
|
738
|
+
* page acquisition. Omitted/`undefined` signals are accepted.
|
|
739
|
+
*/
|
|
402
740
|
async *pages(options = {}) {
|
|
403
741
|
let ownsPageOperation = false;
|
|
404
742
|
try {
|
|
@@ -416,23 +754,27 @@ var PDFReader = class {
|
|
|
416
754
|
for (let pageNumber = start; pageNumber <= Math.min(end, documentProxy.numPages); pageNumber += 1) {
|
|
417
755
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
418
756
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, resolved.signal);
|
|
419
|
-
|
|
757
|
+
const lease = __privateGet(this, _pageResources).acquire(pageNumber);
|
|
420
758
|
let ownsActivePageWork = false;
|
|
421
759
|
try {
|
|
422
760
|
__privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) + 1);
|
|
423
761
|
ownsActivePageWork = true;
|
|
424
|
-
page = await documentProxy.getPage(pageNumber);
|
|
425
|
-
const result = await __privateMethod(this, _PDFReader_instances, processPage_fn).call(this, page, pageNumber, documentProxy.numPages, resolved);
|
|
426
|
-
|
|
427
|
-
page = void 0;
|
|
762
|
+
const page = await __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, lease.acquire(() => documentProxy.getPage(pageNumber)), resolved.signal);
|
|
763
|
+
const result = await __privateMethod(this, _PDFReader_instances, processPage_fn).call(this, page, pageNumber, documentProxy.numPages, resolved, lease);
|
|
764
|
+
lease.release();
|
|
428
765
|
__privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) - 1);
|
|
429
766
|
ownsActivePageWork = false;
|
|
430
767
|
yield result;
|
|
431
768
|
} catch (error) {
|
|
769
|
+
if (error instanceof InterruptedRender) {
|
|
770
|
+
const reason = __privateGet(this, _destroyed) ? __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this) : resolved.signal?.aborted ? __privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this) : error.reason;
|
|
771
|
+
void this.destroy().catch(() => void 0);
|
|
772
|
+
throw reason;
|
|
773
|
+
}
|
|
432
774
|
__privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, resolved.signal);
|
|
433
775
|
} finally {
|
|
434
776
|
if (ownsActivePageWork) __privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) - 1);
|
|
435
|
-
|
|
777
|
+
lease.release();
|
|
436
778
|
}
|
|
437
779
|
}
|
|
438
780
|
} finally {
|
|
@@ -445,17 +787,45 @@ var PDFReader = class {
|
|
|
445
787
|
for await (const page of this.pages(options)) results.push(page);
|
|
446
788
|
return results;
|
|
447
789
|
}
|
|
448
|
-
/**
|
|
449
|
-
|
|
790
|
+
/**
|
|
791
|
+
* Terminates the loading task and document resources. The reader cannot be reused afterwards.
|
|
792
|
+
*
|
|
793
|
+
* A caller-created PDF.js `PDFWorker` passed on the source stays
|
|
794
|
+
* caller-owned: neither `destroy()` nor PDF.js task teardown destroys it.
|
|
795
|
+
* Destroy it explicitly in your own `finally` block, even if this method
|
|
796
|
+
* rejects.
|
|
797
|
+
*
|
|
798
|
+
* In-flight page-stage waiters settle promptly with `DESTROYED`, but their
|
|
799
|
+
* uncancellable getPage/text/operator work stays observed in the background.
|
|
800
|
+
* Active renders are cancelled. This method waits for PDF.js loading/document
|
|
801
|
+
* destruction, not for orphaned `getPage`/text/operator/image-object
|
|
802
|
+
* continuations, which never start later processing. It clears retained
|
|
803
|
+
* page ownership; late acquisitions receive best-effort cleanup. Await
|
|
804
|
+
* active operations to observe their temporary canvas release. It cannot
|
|
805
|
+
* force a suspended `pages()` consumer to resume; that consumer observes
|
|
806
|
+
* destruction on next resume.
|
|
807
|
+
* Render cancellation/failure also starts this teardown automatically without
|
|
808
|
+
* awaiting it or replacing the initiating error. This method always returns
|
|
809
|
+
* the same teardown promise, including its rejection; call it to observe that
|
|
810
|
+
* outcome. Automatic teardown rejection is observed even if you never do.
|
|
811
|
+
*/
|
|
812
|
+
destroy() {
|
|
450
813
|
if (__privateGet(this, _destroyPromise)) return __privateGet(this, _destroyPromise);
|
|
814
|
+
let resolveDestroy;
|
|
815
|
+
let rejectDestroy;
|
|
816
|
+
__privateSet(this, _destroyPromise, new Promise((resolve, reject) => {
|
|
817
|
+
resolveDestroy = resolve;
|
|
818
|
+
rejectDestroy = reject;
|
|
819
|
+
}));
|
|
451
820
|
__privateSet(this, _destroyed, true);
|
|
452
|
-
__privateGet(this, _destroyController).abort();
|
|
453
821
|
const loadingTask = __privateGet(this, _loadingTask);
|
|
454
822
|
const loadingState = __privateGet(this, _loadingState);
|
|
455
823
|
__privateSet(this, _loadingTask, void 0);
|
|
456
824
|
__privateSet(this, _document, void 0);
|
|
457
825
|
__privateSet(this, _loadingState, void 0);
|
|
458
|
-
|
|
826
|
+
void (async () => {
|
|
827
|
+
__privateGet(this, _destroyController).abort();
|
|
828
|
+
__privateGet(this, _pageResources).destroy();
|
|
459
829
|
for (const renderTask of __privateGet(this, _activeRenderTasks)) renderTask.cancel();
|
|
460
830
|
if (loadingTask) {
|
|
461
831
|
await loadingTask.destroy();
|
|
@@ -464,8 +834,8 @@ var PDFReader = class {
|
|
|
464
834
|
if (!loadingState) return;
|
|
465
835
|
loadingState.destroyed = true;
|
|
466
836
|
await __privateMethod(this, _PDFReader_instances, destroyLoadStateTask_fn).call(this, loadingState);
|
|
467
|
-
})());
|
|
468
|
-
|
|
837
|
+
})().then(resolveDestroy, rejectDestroy);
|
|
838
|
+
return __privateGet(this, _destroyPromise);
|
|
469
839
|
}
|
|
470
840
|
};
|
|
471
841
|
_source = new WeakMap();
|
|
@@ -479,6 +849,7 @@ _document = new WeakMap();
|
|
|
479
849
|
_destroyPromise = new WeakMap();
|
|
480
850
|
_destroyController = new WeakMap();
|
|
481
851
|
_activeRenderTasks = new WeakMap();
|
|
852
|
+
_pageResources = new WeakMap();
|
|
482
853
|
_activePageOperation = new WeakMap();
|
|
483
854
|
_activePageWorkCount = new WeakMap();
|
|
484
855
|
_destroyed = new WeakMap();
|
|
@@ -497,8 +868,10 @@ load_fn = async function(options) {
|
|
|
497
868
|
throw error;
|
|
498
869
|
}
|
|
499
870
|
};
|
|
500
|
-
processPage_fn = async function(page, pageNumber, numPages, options) {
|
|
501
|
-
|
|
871
|
+
processPage_fn = async function(page, pageNumber, numPages, options, lease) {
|
|
872
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
873
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
|
|
874
|
+
const viewport = __privateMethod(this, _PDFReader_instances, resolveViewport_fn).call(this, page, options.viewportScale, options.signal);
|
|
502
875
|
const result = {
|
|
503
876
|
numPages,
|
|
504
877
|
pageNumber,
|
|
@@ -510,7 +883,7 @@ processPage_fn = async function(page, pageNumber, numPages, options) {
|
|
|
510
883
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
511
884
|
if (options.includeText) {
|
|
512
885
|
try {
|
|
513
|
-
const text = await page.getTextContent();
|
|
886
|
+
const text = await __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, lease.track(page.getTextContent()), options.signal);
|
|
514
887
|
__privateMethod(this, _PDFReader_instances, enforceTextLimits_fn).call(this, text);
|
|
515
888
|
result.text = text;
|
|
516
889
|
} catch (error) {
|
|
@@ -523,14 +896,17 @@ processPage_fn = async function(page, pageNumber, numPages, options) {
|
|
|
523
896
|
try {
|
|
524
897
|
result.images = await extractEmbeddedImages(page, viewport, {
|
|
525
898
|
signal: options.signal,
|
|
526
|
-
createCanvas:
|
|
899
|
+
createCanvas: () => __privateMethod(this, _PDFReader_instances, createCanvasWithSignal_fn).call(this, options.signal),
|
|
527
900
|
maxPixels: __privateGet(this, _limits).maxEmbeddedImagePixels,
|
|
528
901
|
maxImages: __privateGet(this, _limits).maxEmbeddedImages,
|
|
529
902
|
maxTotalPixels: __privateGet(this, _limits).maxEmbeddedImagePixelsTotal,
|
|
530
903
|
maxOperators: __privateGet(this, _limits).maxOperatorCount,
|
|
531
904
|
logger: __privateGet(this, _logger),
|
|
532
905
|
throwIfAborted: (signal) => __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal),
|
|
533
|
-
throwIfDestroyed: () => __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this)
|
|
906
|
+
throwIfDestroyed: () => __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this),
|
|
907
|
+
// Reuses the reader's single cancellation/wait contract so operator
|
|
908
|
+
// retrieval settles promptly without cancelling upstream PDF.js work.
|
|
909
|
+
awaitWithCancellation: (pending) => __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, lease.track(pending), options.signal)
|
|
534
910
|
});
|
|
535
911
|
} catch (error) {
|
|
536
912
|
__privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, options.signal);
|
|
@@ -539,14 +915,18 @@ processPage_fn = async function(page, pageNumber, numPages, options) {
|
|
|
539
915
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
|
|
540
916
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
541
917
|
if (options.includePageImage) {
|
|
542
|
-
const canvas = __privateMethod(this, _PDFReader_instances, allocateCanvas_fn).call(this, viewport.width, viewport.height, __privateGet(this, _limits).maxCanvasPixels, "page");
|
|
918
|
+
const canvas = __privateMethod(this, _PDFReader_instances, allocateCanvas_fn).call(this, viewport.width, viewport.height, __privateGet(this, _limits).maxCanvasPixels, "page", options.signal);
|
|
543
919
|
try {
|
|
920
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
921
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
|
|
544
922
|
const context = canvas.getContext("2d");
|
|
923
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
924
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
|
|
545
925
|
if (!context) {
|
|
546
926
|
throw __privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, `Failed to create a 2D canvas context for page ${pageNumber}.`);
|
|
547
927
|
}
|
|
548
928
|
const renderTask = page.render({ canvas, canvasContext: context, viewport });
|
|
549
|
-
await __privateMethod(this, _PDFReader_instances, waitForRender_fn).call(this, renderTask, options.signal);
|
|
929
|
+
await __privateMethod(this, _PDFReader_instances, waitForRender_fn).call(this, renderTask, lease, options.signal);
|
|
550
930
|
result.pageImage = await __privateMethod(this, _PDFReader_instances, encodePageImage_fn).call(this, canvas, options.imageFormat, options.pageImageOutput, options.jpegQuality, options.signal);
|
|
551
931
|
} finally {
|
|
552
932
|
__privateMethod(this, _PDFReader_instances, releaseCanvas_fn).call(this, canvas);
|
|
@@ -586,17 +966,27 @@ encodePageImage_fn = async function(canvas, mimeType, output, jpegQuality, signa
|
|
|
586
966
|
const dataUrl = quality === void 0 ? canvas.toDataURL(mimeType) : canvas.toDataURL(mimeType, quality);
|
|
587
967
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
588
968
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
969
|
+
if (!isValidDataUrlForMime(dataUrl, mimeType)) {
|
|
970
|
+
throw __privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, `Canvas encoding produced an empty or mismatched result for ${mimeType}.`);
|
|
971
|
+
}
|
|
589
972
|
return { kind: "data-url", mimeType, dataUrl };
|
|
590
973
|
}
|
|
591
974
|
const blob = await __privateMethod(this, _PDFReader_instances, encodeCanvasToBlob_fn).call(this, canvas, mimeType, quality, signal);
|
|
592
975
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
593
976
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
977
|
+
if (!isValidBlobForMime(blob, mimeType)) {
|
|
978
|
+
throw __privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, `Canvas Blob encoding produced an empty or mismatched result for ${mimeType}.`);
|
|
979
|
+
}
|
|
594
980
|
return { kind: "blob", mimeType, blob };
|
|
595
981
|
};
|
|
596
|
-
resolveViewport_fn = function(page, viewportScale) {
|
|
982
|
+
resolveViewport_fn = function(page, viewportScale, signal) {
|
|
597
983
|
if (typeof viewportScale === "number") return page.getViewport({ scale: viewportScale });
|
|
598
984
|
const base = page.getViewport({ scale: 1 });
|
|
985
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
986
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
599
987
|
const scale = viewportScale(base.width, base.height);
|
|
988
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
989
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
600
990
|
assertPositiveFinite(scale, "viewportScale callback result");
|
|
601
991
|
return page.getViewport({ scale });
|
|
602
992
|
};
|
|
@@ -642,29 +1032,58 @@ encodeCanvasToBlob_fn = async function(canvas, mimeType, quality, signal) {
|
|
|
642
1032
|
}
|
|
643
1033
|
});
|
|
644
1034
|
};
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
const pixels = pixelWidth * pixelHeight;
|
|
649
|
-
if (!Number.isSafeInteger(pixels) || pixels > limit) {
|
|
650
|
-
const code = subject === "page" ? "CANVAS_LIMIT_EXCEEDED" : "IMAGE_LIMIT_EXCEEDED";
|
|
651
|
-
throw new PdfReaderError(code, `${subject} requires ${pixels} pixels; limit is ${limit}.`);
|
|
652
|
-
}
|
|
1035
|
+
createCanvasWithSignal_fn = function(signal) {
|
|
1036
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
1037
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
653
1038
|
const canvas = __privateGet(this, _createCanvas).call(this);
|
|
654
|
-
|
|
655
|
-
|
|
1039
|
+
try {
|
|
1040
|
+
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
1041
|
+
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
try {
|
|
1044
|
+
__privateMethod(this, _PDFReader_instances, releaseCanvas_fn).call(this, canvas);
|
|
1045
|
+
} catch {
|
|
1046
|
+
}
|
|
1047
|
+
throw error;
|
|
1048
|
+
}
|
|
656
1049
|
return canvas;
|
|
657
1050
|
};
|
|
658
|
-
|
|
1051
|
+
allocateCanvas_fn = function(width, height, limit, subject, signal) {
|
|
1052
|
+
const { pixelWidth, pixelHeight } = resolveSafeCanvasDimensions(
|
|
1053
|
+
width,
|
|
1054
|
+
height,
|
|
1055
|
+
limit,
|
|
1056
|
+
"CANVAS_LIMIT_EXCEEDED",
|
|
1057
|
+
subject
|
|
1058
|
+
);
|
|
1059
|
+
const canvas = __privateMethod(this, _PDFReader_instances, createCanvasWithSignal_fn).call(this, signal);
|
|
1060
|
+
try {
|
|
1061
|
+
canvas.width = pixelWidth;
|
|
1062
|
+
canvas.height = pixelHeight;
|
|
1063
|
+
} catch (error) {
|
|
1064
|
+
try {
|
|
1065
|
+
__privateMethod(this, _PDFReader_instances, releaseCanvas_fn).call(this, canvas);
|
|
1066
|
+
} catch {
|
|
1067
|
+
}
|
|
1068
|
+
throw error;
|
|
1069
|
+
}
|
|
1070
|
+
return canvas;
|
|
1071
|
+
};
|
|
1072
|
+
waitForRender_fn = async function(renderTask, lease, signal) {
|
|
659
1073
|
const abort = () => renderTask.cancel();
|
|
660
1074
|
__privateGet(this, _activeRenderTasks).add(renderTask);
|
|
661
1075
|
signal?.addEventListener("abort", abort, { once: true });
|
|
662
1076
|
try {
|
|
663
|
-
|
|
1077
|
+
const waiting = __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, lease.track(renderTask.promise), signal);
|
|
1078
|
+
try {
|
|
1079
|
+
if (signal?.aborted || __privateGet(this, _destroyed)) abort();
|
|
1080
|
+
} finally {
|
|
1081
|
+
await waiting;
|
|
1082
|
+
}
|
|
664
1083
|
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
665
1084
|
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
666
1085
|
} catch (error) {
|
|
667
|
-
|
|
1086
|
+
throw new InterruptedRender(error);
|
|
668
1087
|
} finally {
|
|
669
1088
|
signal?.removeEventListener("abort", abort);
|
|
670
1089
|
__privateGet(this, _activeRenderTasks).delete(renderTask);
|
|
@@ -692,11 +1111,20 @@ getOrCreateLoadState_fn = function() {
|
|
|
692
1111
|
if (existing) return existing;
|
|
693
1112
|
__privateSet(this, _lastLoadFailed, false);
|
|
694
1113
|
const state = { destroyed: false };
|
|
695
|
-
|
|
1114
|
+
let resolveLoad;
|
|
1115
|
+
let rejectLoad;
|
|
1116
|
+
state.promise = new Promise((resolve, reject) => {
|
|
1117
|
+
resolveLoad = resolve;
|
|
1118
|
+
rejectLoad = reject;
|
|
1119
|
+
});
|
|
1120
|
+
state.promise.catch(() => void 0);
|
|
1121
|
+
__privateSet(this, _loadingState, state);
|
|
1122
|
+
const taskPromise = (async () => {
|
|
696
1123
|
try {
|
|
697
1124
|
const source = __privateMethod(this, _PDFReader_instances, createSourceSnapshot_fn).call(this);
|
|
698
1125
|
const policyResult = __privateMethod(this, _PDFReader_instances, enforceSourcePolicy_fn).call(this, source.info);
|
|
699
1126
|
if (policyResult) await __privateMethod(this, _PDFReader_instances, awaitWithDestroy_fn).call(this, policyResult);
|
|
1127
|
+
__privateMethod(this, _PDFReader_instances, throwIfOverSourceLimit_fn).call(this, source.pdfJsSource.data);
|
|
700
1128
|
if (state.destroyed || __privateGet(this, _destroyed)) {
|
|
701
1129
|
throw __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this);
|
|
702
1130
|
}
|
|
@@ -742,8 +1170,7 @@ getOrCreateLoadState_fn = function() {
|
|
|
742
1170
|
if (__privateGet(this, _loadingState) === state) __privateSet(this, _loadingState, void 0);
|
|
743
1171
|
}
|
|
744
1172
|
})();
|
|
745
|
-
|
|
746
|
-
__privateSet(this, _loadingState, state);
|
|
1173
|
+
taskPromise.then(resolveLoad, rejectLoad);
|
|
747
1174
|
return state;
|
|
748
1175
|
};
|
|
749
1176
|
destroyLoadStateTask_fn = function(state) {
|
|
@@ -754,10 +1181,9 @@ destroyLoadStateTask_fn = function(state) {
|
|
|
754
1181
|
return state.destroyPromise;
|
|
755
1182
|
};
|
|
756
1183
|
awaitWithSignal_fn = async function(promise, signal, deadlineMs) {
|
|
757
|
-
__privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
|
|
758
|
-
__privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
|
|
759
1184
|
return await new Promise((resolve, reject) => {
|
|
760
1185
|
let settled = false;
|
|
1186
|
+
let timer;
|
|
761
1187
|
const onAbort = () => settle(() => reject(__privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this)));
|
|
762
1188
|
const onDestroy = () => settle(() => reject(__privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this)));
|
|
763
1189
|
const cleanup = () => {
|
|
@@ -771,33 +1197,27 @@ awaitWithSignal_fn = async function(promise, signal, deadlineMs) {
|
|
|
771
1197
|
cleanup();
|
|
772
1198
|
callback();
|
|
773
1199
|
};
|
|
774
|
-
const timer = deadlineMs === void 0 ? void 0 : setTimeout(() => settle(() => reject(__privateMethod(this, _PDFReader_instances, createDeadlineExceededError_fn).call(this))), deadlineMs);
|
|
775
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
776
|
-
__privateGet(this, _destroyController).signal.addEventListener("abort", onDestroy, { once: true });
|
|
777
1200
|
promise.then(
|
|
778
|
-
(value) =>
|
|
779
|
-
|
|
1201
|
+
(value) => {
|
|
1202
|
+
if (settled) return;
|
|
1203
|
+
settle(() => resolve(value));
|
|
1204
|
+
},
|
|
1205
|
+
(error) => {
|
|
1206
|
+
if (settled) return;
|
|
1207
|
+
settle(() => reject(error));
|
|
1208
|
+
}
|
|
780
1209
|
).catch(() => void 0);
|
|
1210
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1211
|
+
__privateGet(this, _destroyController).signal.addEventListener("abort", onDestroy, { once: true });
|
|
1212
|
+
if (signal?.aborted) onAbort();
|
|
1213
|
+
else if (__privateGet(this, _destroyed)) onDestroy();
|
|
1214
|
+
if (!settled && deadlineMs !== void 0) {
|
|
1215
|
+
timer = setTimeout(() => settle(() => reject(__privateMethod(this, _PDFReader_instances, createDeadlineExceededError_fn).call(this))), deadlineMs);
|
|
1216
|
+
}
|
|
781
1217
|
});
|
|
782
1218
|
};
|
|
783
1219
|
awaitWithDestroy_fn = async function(promise) {
|
|
784
|
-
__privateMethod(this, _PDFReader_instances,
|
|
785
|
-
return await new Promise((resolve, reject) => {
|
|
786
|
-
let settled = false;
|
|
787
|
-
const onDestroy = () => settle(() => reject(__privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this)));
|
|
788
|
-
const cleanup = () => __privateGet(this, _destroyController).signal.removeEventListener("abort", onDestroy);
|
|
789
|
-
const settle = (callback) => {
|
|
790
|
-
if (settled) return;
|
|
791
|
-
settled = true;
|
|
792
|
-
cleanup();
|
|
793
|
-
callback();
|
|
794
|
-
};
|
|
795
|
-
__privateGet(this, _destroyController).signal.addEventListener("abort", onDestroy, { once: true });
|
|
796
|
-
Promise.resolve(promise).then(
|
|
797
|
-
(value) => settle(() => resolve(value)),
|
|
798
|
-
(error) => settle(() => reject(error))
|
|
799
|
-
);
|
|
800
|
-
});
|
|
1220
|
+
return __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, Promise.resolve(promise));
|
|
801
1221
|
};
|
|
802
1222
|
createAbortedError_fn = function() {
|
|
803
1223
|
return new PdfReaderError("ABORTED", "PDF operation was aborted.");
|
|
@@ -823,23 +1243,28 @@ throwIfAborted_fn = function(signal) {
|
|
|
823
1243
|
if (signal?.aborted) throw __privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this);
|
|
824
1244
|
};
|
|
825
1245
|
resolveLoadOptions_fn = function(options) {
|
|
826
|
-
if (
|
|
827
|
-
if (
|
|
828
|
-
|
|
829
|
-
throw new PdfReaderError("INVALID_OPTION", "deadlineMs must be a positive finite number.");
|
|
1246
|
+
if (options === void 0) return {};
|
|
1247
|
+
if (options === null || typeof options !== "object" || Array.isArray(options)) {
|
|
1248
|
+
throw new PdfReaderError("INVALID_OPTION", "Load options must be an object or an AbortSignal.");
|
|
830
1249
|
}
|
|
831
|
-
|
|
832
|
-
};
|
|
833
|
-
|
|
834
|
-
|
|
1250
|
+
if ("aborted" in options || "addEventListener" in options || "removeEventListener" in options) {
|
|
1251
|
+
return { signal: resolveSignal(options) };
|
|
1252
|
+
}
|
|
1253
|
+
const candidate = options;
|
|
1254
|
+
const signal = resolveSignal(candidate.signal);
|
|
1255
|
+
const deadlineMs = candidate.deadlineMs;
|
|
1256
|
+
if (deadlineMs !== void 0) {
|
|
1257
|
+
if (!Number.isFinite(deadlineMs) || deadlineMs <= 0 || deadlineMs > MAX_TIMER_MS) {
|
|
1258
|
+
throw new PdfReaderError(
|
|
1259
|
+
"INVALID_OPTION",
|
|
1260
|
+
`deadlineMs must be a positive finite number not exceeding ${MAX_TIMER_MS}.`
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return { signal, deadlineMs };
|
|
835
1265
|
};
|
|
836
1266
|
enforceSourcePolicy_fn = function(source) {
|
|
837
|
-
|
|
838
|
-
throw new PdfReaderError(
|
|
839
|
-
"SOURCE_LIMIT_EXCEEDED",
|
|
840
|
-
`PDF source is ${source.byteLength} bytes; limit is ${__privateGet(this, _limits).maxSourceBytes}.`
|
|
841
|
-
);
|
|
842
|
-
}
|
|
1267
|
+
__privateMethod(this, _PDFReader_instances, throwIfOverSourceLimit_fn).call(this, source.rawSource.data);
|
|
843
1268
|
if (!__privateGet(this, _sourcePolicy)) return;
|
|
844
1269
|
try {
|
|
845
1270
|
const result = __privateGet(this, _sourcePolicy).call(this, source);
|
|
@@ -853,14 +1278,30 @@ enforceSourcePolicy_fn = function(source) {
|
|
|
853
1278
|
throw new PdfReaderError("SOURCE_POLICY_VIOLATION", "PDF source rejected by sourcePolicy.");
|
|
854
1279
|
}
|
|
855
1280
|
};
|
|
1281
|
+
/**
|
|
1282
|
+
* Rejects a synchronously measurable over-limit byte source.
|
|
1283
|
+
*
|
|
1284
|
+
* Length is read without scanning or copying element content, so an
|
|
1285
|
+
* oversized array fails on its `length` before any entry is visited.
|
|
1286
|
+
*/
|
|
1287
|
+
throwIfOverSourceLimit_fn = function(data) {
|
|
1288
|
+
if (__privateGet(this, _limits).maxSourceBytes === void 0) return;
|
|
1289
|
+
const byteLength = __privateMethod(this, _PDFReader_instances, knownByteLength_fn).call(this, data);
|
|
1290
|
+
if (byteLength !== void 0 && byteLength > __privateGet(this, _limits).maxSourceBytes) {
|
|
1291
|
+
throw new PdfReaderError(
|
|
1292
|
+
"SOURCE_LIMIT_EXCEEDED",
|
|
1293
|
+
`PDF source is ${byteLength} bytes; limit is ${__privateGet(this, _limits).maxSourceBytes}.`
|
|
1294
|
+
);
|
|
1295
|
+
}
|
|
1296
|
+
};
|
|
856
1297
|
createSourceSnapshot_fn = function() {
|
|
857
1298
|
const kind = __privateMethod(this, _PDFReader_instances, sourceKind_fn).call(this, __privateGet(this, _source));
|
|
858
|
-
const
|
|
859
|
-
const
|
|
1299
|
+
const headers = __privateMethod(this, _PDFReader_instances, snapshotHttpHeaders_fn).call(this, __privateMethod(this, _PDFReader_instances, readRawHttpHeaders_fn).call(this, __privateGet(this, _source)));
|
|
1300
|
+
const pdfJsSource = __privateMethod(this, _PDFReader_instances, toPdfJsSource_fn).call(this, __privateGet(this, _source), headers);
|
|
1301
|
+
const info = __privateMethod(this, _PDFReader_instances, inspectSource_fn).call(this, pdfJsSource, kind, headers);
|
|
860
1302
|
return { pdfJsSource, info };
|
|
861
1303
|
};
|
|
862
|
-
inspectSource_fn = function(source, kind) {
|
|
863
|
-
const headers = __privateMethod(this, _PDFReader_instances, readHttpHeaders_fn).call(this, source.httpHeaders);
|
|
1304
|
+
inspectSource_fn = function(source, kind, headers) {
|
|
864
1305
|
const info = {
|
|
865
1306
|
rawSource: source,
|
|
866
1307
|
kind,
|
|
@@ -878,7 +1319,7 @@ sourceKind_fn = function(source) {
|
|
|
878
1319
|
if (source instanceof ArrayBuffer || __privateMethod(this, _PDFReader_instances, isPdfTypedArray_fn).call(this, source) || Array.isArray(source)) return "bytes";
|
|
879
1320
|
return "document-init-parameters";
|
|
880
1321
|
};
|
|
881
|
-
toPdfJsSource_fn = function(source) {
|
|
1322
|
+
toPdfJsSource_fn = function(source, headers) {
|
|
882
1323
|
if (typeof source === "string") {
|
|
883
1324
|
return __privateMethod(this, _PDFReader_instances, freezeSource_fn).call(this, { url: source });
|
|
884
1325
|
}
|
|
@@ -890,23 +1331,47 @@ toPdfJsSource_fn = function(source) {
|
|
|
890
1331
|
}
|
|
891
1332
|
const snapshot = {};
|
|
892
1333
|
for (const key of Reflect.ownKeys(source)) {
|
|
1334
|
+
if (key === "httpHeaders") continue;
|
|
893
1335
|
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
894
1336
|
if (!descriptor?.enumerable) continue;
|
|
895
|
-
|
|
1337
|
+
const value = source[key];
|
|
1338
|
+
Object.defineProperty(snapshot, key, {
|
|
1339
|
+
value,
|
|
1340
|
+
writable: true,
|
|
1341
|
+
enumerable: true,
|
|
1342
|
+
configurable: true
|
|
1343
|
+
});
|
|
896
1344
|
}
|
|
897
1345
|
if (typeof URL !== "undefined" && snapshot.url instanceof URL) snapshot.url = snapshot.url.toString();
|
|
1346
|
+
if (headers.httpHeaders !== void 0) {
|
|
1347
|
+
Object.defineProperty(snapshot, "httpHeaders", {
|
|
1348
|
+
value: headers.httpHeaders,
|
|
1349
|
+
writable: false,
|
|
1350
|
+
enumerable: true,
|
|
1351
|
+
configurable: false
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
898
1354
|
return __privateMethod(this, _PDFReader_instances, freezeSource_fn).call(this, snapshot);
|
|
899
1355
|
};
|
|
900
1356
|
freezeSource_fn = function(source) {
|
|
901
1357
|
return Object.freeze(source);
|
|
902
1358
|
};
|
|
1359
|
+
isFetchHeaders_fn = function(value) {
|
|
1360
|
+
if (typeof Headers !== "undefined" && value instanceof Headers) return true;
|
|
1361
|
+
try {
|
|
1362
|
+
if (Object.prototype.toString.call(value) === "[object Headers]") return true;
|
|
1363
|
+
} catch {
|
|
1364
|
+
}
|
|
1365
|
+
return false;
|
|
1366
|
+
};
|
|
903
1367
|
isPdfTypedArray_fn = function(source) {
|
|
904
1368
|
return ArrayBuffer.isView(source) && !(source instanceof DataView);
|
|
905
1369
|
};
|
|
906
1370
|
knownByteLength_fn = function(value) {
|
|
1371
|
+
if (typeof value === "string") return value.length;
|
|
907
1372
|
if (value instanceof ArrayBuffer) return value.byteLength;
|
|
908
1373
|
if (ArrayBuffer.isView(value)) return value.byteLength;
|
|
909
|
-
if (Array.isArray(value)
|
|
1374
|
+
if (Array.isArray(value)) return value.length;
|
|
910
1375
|
return void 0;
|
|
911
1376
|
};
|
|
912
1377
|
readUrl_fn = function(value) {
|
|
@@ -914,34 +1379,57 @@ readUrl_fn = function(value) {
|
|
|
914
1379
|
if (typeof URL !== "undefined" && value instanceof URL) return value.toString();
|
|
915
1380
|
return void 0;
|
|
916
1381
|
};
|
|
917
|
-
|
|
918
|
-
if (
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1382
|
+
readRawHttpHeaders_fn = function(source) {
|
|
1383
|
+
if (typeof source !== "object" || source === null) return void 0;
|
|
1384
|
+
if (source instanceof ArrayBuffer || ArrayBuffer.isView(source) || Array.isArray(source)) return void 0;
|
|
1385
|
+
return source.httpHeaders;
|
|
1386
|
+
};
|
|
1387
|
+
/**
|
|
1388
|
+
* Stabilizes effective HTTP headers into one owned, frozen record.
|
|
1389
|
+
*
|
|
1390
|
+
* Enumeration mirrors the installed PDF.js `createHeaders` transport
|
|
1391
|
+
* (`for...in`, inherited enumerable string keys, `undefined` skipped) so
|
|
1392
|
+
* the approved diagnostic and the value handed to `getDocument()` agree.
|
|
1393
|
+
* Remaining values are coerced with `String()` as `Headers.append` would.
|
|
1394
|
+
* Non-plain containers (`Headers`, `Map`, class instances) intentionally
|
|
1395
|
+
* yield no value entries — matching what PDF.js `for...in` consumption
|
|
1396
|
+
* observes — while `hasHttpHeaders` stays `true` so policies gating only
|
|
1397
|
+
* on header presence keep blocking. A throwing getter propagates so the
|
|
1398
|
+
* load fails closed before policy approval. The caller's container is
|
|
1399
|
+
* never frozen or mutated.
|
|
1400
|
+
*/
|
|
1401
|
+
snapshotHttpHeaders_fn = function(value) {
|
|
1402
|
+
if (value === null || value === void 0) return { hasHttpHeaders: false };
|
|
1403
|
+
if (typeof value !== "object" && typeof value !== "function") return { hasHttpHeaders: false };
|
|
1404
|
+
if (__privateMethod(this, _PDFReader_instances, isFetchHeaders_fn).call(this, value)) {
|
|
930
1405
|
return { hasHttpHeaders: true };
|
|
931
1406
|
}
|
|
1407
|
+
const entries = [];
|
|
1408
|
+
for (const name in value) {
|
|
1409
|
+
const headerValue = value[name];
|
|
1410
|
+
if (headerValue === void 0) continue;
|
|
1411
|
+
entries.push([name, String(headerValue)]);
|
|
1412
|
+
}
|
|
932
1413
|
return {
|
|
933
1414
|
hasHttpHeaders: true,
|
|
1415
|
+
// Object.fromEntries installs `__proto__` as an own data property
|
|
1416
|
+
// (no prototype mutation); the frozen record is shared by policy info
|
|
1417
|
+
// and PDF.js loading params. Opaque worker/factory fields elsewhere in
|
|
1418
|
+
// the snapshot stay borrowed by reference — only headers stabilize.
|
|
934
1419
|
httpHeaders: entries.length > 0 ? Object.freeze(Object.fromEntries(entries)) : void 0
|
|
935
1420
|
};
|
|
936
1421
|
};
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1422
|
+
|
|
1423
|
+
// src/pdfTextToString.ts
|
|
1424
|
+
function pdfTextToString(content) {
|
|
1425
|
+
const fragments = [];
|
|
1426
|
+
for (const item of content.items) {
|
|
1427
|
+
if (!("str" in item)) continue;
|
|
1428
|
+
fragments.push(item.str);
|
|
1429
|
+
if (item.hasEOL === true) fragments.push("\n");
|
|
943
1430
|
}
|
|
944
|
-
|
|
1431
|
+
return fragments.join("");
|
|
1432
|
+
}
|
|
945
1433
|
|
|
946
1434
|
// src/source.ts
|
|
947
1435
|
function pdfUrlSource(url, options = {}) {
|
|
@@ -963,5 +1451,6 @@ export {
|
|
|
963
1451
|
PDFReader,
|
|
964
1452
|
PdfReaderError,
|
|
965
1453
|
configurePdfWorker,
|
|
1454
|
+
pdfTextToString,
|
|
966
1455
|
pdfUrlSource
|
|
967
1456
|
};
|