@web-ts-toolkit/pdf-reader 0.37.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.
Files changed (5) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +253 -0
  3. package/index.d.mts +192 -0
  4. package/index.mjs +760 -0
  5. package/package.json +45 -0
package/index.mjs ADDED
@@ -0,0 +1,760 @@
1
+ var __typeError = (msg) => {
2
+ throw TypeError(msg);
3
+ };
4
+ var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
5
+ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
6
+ var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
7
+ var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
8
+ var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
9
+
10
+ // src/errors.ts
11
+ var PdfReaderError = class extends Error {
12
+ constructor(code, message) {
13
+ super(message);
14
+ this.name = "PdfReaderError";
15
+ this.code = code;
16
+ }
17
+ };
18
+
19
+ // src/PDFReader.ts
20
+ import { getDocument } from "pdfjs-dist";
21
+
22
+ // src/embeddedImages.ts
23
+ import { OPS, Util } from "pdfjs-dist";
24
+
25
+ // src/geometry.ts
26
+ function getTransformedUnitBounds(transform) {
27
+ const [a, b, c, d, e, f] = transform;
28
+ const points = [
29
+ [e, f],
30
+ [a + e, b + f],
31
+ [c + e, d + f],
32
+ [a + c + e, b + d + f]
33
+ ];
34
+ const xs = points.map(([x]) => x);
35
+ const ys = points.map(([, y]) => y);
36
+ const left = Math.min(...xs);
37
+ const right = Math.max(...xs);
38
+ const bottom = Math.min(...ys);
39
+ const top = Math.max(...ys);
40
+ return { left, right, top, bottom, width: right - left, height: top - bottom };
41
+ }
42
+
43
+ // src/embeddedImages.ts
44
+ var identityTransform = [1, 0, 0, 1, 0, 0];
45
+ var propagatedErrorCodes = /* @__PURE__ */ new Set(["ABORTED", "DESTROYED", "IMAGE_LIMIT_EXCEEDED"]);
46
+ async function extractEmbeddedImages(page, viewport, options) {
47
+ const operators = await page.getOperatorList();
48
+ const images = [];
49
+ const stack = [];
50
+ let transform = identityTransform;
51
+ for (let index = 0; index < operators.fnArray.length; index += 1) {
52
+ options.throwIfDestroyed();
53
+ options.throwIfAborted(options.signal);
54
+ const operation = operators.fnArray[index];
55
+ if (operation === OPS.save) {
56
+ stack.push([...transform]);
57
+ continue;
58
+ }
59
+ if (operation === OPS.restore || operation === OPS.paintFormXObjectEnd) {
60
+ transform = stack.pop() ?? identityTransform;
61
+ continue;
62
+ }
63
+ if (operation === OPS.transform) {
64
+ const next = readTransformArgs(operators.argsArray[index]);
65
+ if (next) transform = Util.transform(transform, next);
66
+ continue;
67
+ }
68
+ if (operation === OPS.paintFormXObjectBegin) {
69
+ stack.push([...transform]);
70
+ const next = readTransformMatrix(operators.argsArray[index]?.[0]);
71
+ if (next) transform = Util.transform(transform, next);
72
+ continue;
73
+ }
74
+ if (operation === OPS.paintImageMaskXObject) {
75
+ warn(options.logger, "Skipped embedded image operator paintImageMaskXObject: image masks are not supported.");
76
+ continue;
77
+ }
78
+ if (operation !== OPS.paintXObject && operation !== OPS.paintImageXObject && operation !== OPS.paintInlineImageXObject) {
79
+ continue;
80
+ }
81
+ try {
82
+ const paintedImage = await resolvePaintedImage(page, operation, operators.argsArray[index], index);
83
+ if (!paintedImage) continue;
84
+ const dataUrl = imageToDataUrl(paintedImage.image, options);
85
+ if (!dataUrl) {
86
+ warn(
87
+ options.logger,
88
+ `Skipped embedded image ${paintedImage.label}: unsupported PDF.js image shape or data layout.`
89
+ );
90
+ continue;
91
+ }
92
+ const bounds = getTransformedUnitBounds(transform);
93
+ images.push({
94
+ dataUrl,
95
+ x: bounds.left,
96
+ y: bounds.top,
97
+ width: bounds.width,
98
+ height: bounds.height,
99
+ size: imageByteLength(paintedImage.image),
100
+ mimeType: "image/png",
101
+ pageWidth: viewport.width / viewport.scale,
102
+ pageHeight: viewport.height / viewport.scale,
103
+ transform: [...transform]
104
+ });
105
+ } catch (error) {
106
+ options.throwIfDestroyed();
107
+ options.throwIfAborted(options.signal);
108
+ if (shouldPropagateEmbeddedImageError(error)) throw error;
109
+ const label = readOperationLabel(operation, operators.argsArray[index], index);
110
+ warn(options.logger, `Failed to extract embedded image ${label}.`, error);
111
+ }
112
+ }
113
+ return images;
114
+ }
115
+ async function resolvePaintedImage(page, operation, args, index) {
116
+ if (operation === OPS.paintInlineImageXObject) {
117
+ const inlineImage = Array.isArray(args) ? args[0] : void 0;
118
+ if (!inlineImage || typeof inlineImage !== "object") return void 0;
119
+ return { image: inlineImage, label: `inline@${index}` };
120
+ }
121
+ const reference = Array.isArray(args) ? args[0] : void 0;
122
+ if (typeof reference !== "string") return void 0;
123
+ const image = await page.objs.get(reference);
124
+ return { image, label: reference };
125
+ }
126
+ function imageToDataUrl(image, options) {
127
+ const width = image.width;
128
+ const height = image.height;
129
+ if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) {
130
+ return void 0;
131
+ }
132
+ const canvas = allocateCanvas(width, height, options.maxPixels, options.createCanvas);
133
+ try {
134
+ const context = canvas.getContext("2d");
135
+ if (!context) return void 0;
136
+ if (typeof ImageBitmap !== "undefined" && image.bitmap instanceof ImageBitmap) {
137
+ context.drawImage(image.bitmap, 0, 0);
138
+ return canvas.toDataURL("image/png");
139
+ }
140
+ if (!ArrayBuffer.isView(image.data)) return void 0;
141
+ const source = new Uint8ClampedArray(image.data.buffer, image.data.byteOffset, image.data.byteLength);
142
+ const rgba = toRgba(source, width, height);
143
+ if (!rgba) return void 0;
144
+ const pixels = context.createImageData(width, height);
145
+ pixels.data.set(rgba);
146
+ context.putImageData(pixels, 0, 0);
147
+ return canvas.toDataURL("image/png");
148
+ } finally {
149
+ releaseCanvas(canvas);
150
+ }
151
+ }
152
+ function toRgba(data, width, height) {
153
+ const pixels = width * height;
154
+ if (data.length === pixels * 4) return data;
155
+ if (data.length !== pixels && data.length !== pixels * 3) return void 0;
156
+ const channels = data.length / pixels;
157
+ const rgba = new Uint8ClampedArray(pixels * 4);
158
+ for (let pixel = 0; pixel < pixels; pixel += 1) {
159
+ const input = pixel * channels;
160
+ const output = pixel * 4;
161
+ rgba[output] = data[input];
162
+ rgba[output + 1] = channels === 1 ? data[input] : data[input + 1];
163
+ rgba[output + 2] = channels === 1 ? data[input] : data[input + 2];
164
+ rgba[output + 3] = channels === 4 ? data[input + 3] : 255;
165
+ }
166
+ return rgba;
167
+ }
168
+ function allocateCanvas(width, height, limit, createCanvas) {
169
+ const pixelWidth = Math.ceil(width);
170
+ const pixelHeight = Math.ceil(height);
171
+ const pixels = pixelWidth * pixelHeight;
172
+ if (!Number.isSafeInteger(pixels) || pixels > limit) {
173
+ throw new PdfReaderError("IMAGE_LIMIT_EXCEEDED", `embedded image requires ${pixels} pixels; limit is ${limit}.`);
174
+ }
175
+ const canvas = createCanvas();
176
+ canvas.width = pixelWidth;
177
+ canvas.height = pixelHeight;
178
+ return canvas;
179
+ }
180
+ function imageByteLength(image) {
181
+ if (typeof image.dataLen === "number" && Number.isFinite(image.dataLen)) return image.dataLen;
182
+ return ArrayBuffer.isView(image.data) ? image.data.byteLength : 0;
183
+ }
184
+ function releaseCanvas(canvas) {
185
+ canvas.width = 0;
186
+ canvas.height = 0;
187
+ }
188
+ function readTransformMatrix(value) {
189
+ const values = readNumericTuple(value, 6);
190
+ if (!values) return void 0;
191
+ return values;
192
+ }
193
+ function readTransformArgs(value) {
194
+ return readTransformMatrix(value) ?? readTransformMatrix(Array.isArray(value) ? value[0] : void 0);
195
+ }
196
+ function readNumericTuple(value, length) {
197
+ if (Array.isArray(value)) {
198
+ if (value.length !== length) return void 0;
199
+ if (value.some((entry) => typeof entry !== "number" || !Number.isFinite(entry))) return void 0;
200
+ return [...value];
201
+ }
202
+ if (!value || typeof value !== "object") return void 0;
203
+ const entries = [];
204
+ for (let index = 0; index < length; index += 1) {
205
+ const entry = value[index];
206
+ if (typeof entry !== "number" || !Number.isFinite(entry)) return void 0;
207
+ entries.push(entry);
208
+ }
209
+ return entries;
210
+ }
211
+ function readOperationLabel(operation, args, index) {
212
+ if (operation === OPS.paintInlineImageXObject) return `inline@${index}`;
213
+ const reference = Array.isArray(args) ? args[0] : void 0;
214
+ return typeof reference === "string" ? reference : `operator@${index}`;
215
+ }
216
+ function shouldPropagateEmbeddedImageError(error) {
217
+ return error instanceof PdfReaderError && propagatedErrorCodes.has(error.code);
218
+ }
219
+ function warn(logger, message, error) {
220
+ logger?.warn(message, error);
221
+ }
222
+
223
+ // src/options.ts
224
+ function resolveConvertOptions(options) {
225
+ const resolved = {
226
+ pageRange: options.pageRange,
227
+ viewportScale: options.viewportScale ?? 1.5,
228
+ imageFormat: options.imageFormat ?? "image/png",
229
+ jpegQuality: options.jpegQuality ?? 0.92,
230
+ includePageImage: options.includePageImage ?? true,
231
+ pageImageOutput: options.pageImageOutput ?? "data-url",
232
+ includeText: options.includeText ?? true,
233
+ includeEmbeddedImages: options.includeEmbeddedImages ?? false,
234
+ signal: options.signal
235
+ };
236
+ if (typeof resolved.viewportScale === "number") {
237
+ assertPositiveFinite(resolved.viewportScale, "viewportScale");
238
+ }
239
+ if (!Number.isFinite(resolved.jpegQuality) || resolved.jpegQuality < 0 || resolved.jpegQuality > 1) {
240
+ throw new PdfReaderError("INVALID_OPTION", "jpegQuality must be a finite number from 0 through 1.");
241
+ }
242
+ if (resolved.pageImageOutput !== "data-url" && resolved.pageImageOutput !== "blob") {
243
+ throw new PdfReaderError("INVALID_OPTION", 'pageImageOutput must be either "data-url" or "blob".');
244
+ }
245
+ validatePageRange(resolved.pageRange);
246
+ return resolved;
247
+ }
248
+ function resolvePageNumbers(pageRange, numPages) {
249
+ if (pageRange === void 0) return [1, numPages];
250
+ if (typeof pageRange === "number") return [pageRange, pageRange];
251
+ return [Math.min(...pageRange), Math.max(...pageRange)];
252
+ }
253
+ function assertPositiveFinite(value, option) {
254
+ if (!Number.isFinite(value) || value <= 0) {
255
+ throw new PdfReaderError("INVALID_OPTION", `${option} must be a positive finite number.`);
256
+ }
257
+ }
258
+ function validatePageRange(pageRange) {
259
+ if (pageRange === void 0) return;
260
+ const values = typeof pageRange === "number" ? [pageRange] : pageRange;
261
+ if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
262
+ throw new PdfReaderError("INVALID_OPTION", "pageRange values must be positive safe integers.");
263
+ }
264
+ }
265
+
266
+ // src/PDFReader.ts
267
+ var defaultLimits = {
268
+ maxDocumentPages: 1e3,
269
+ maxCanvasPixels: 4e7,
270
+ maxEmbeddedImagePixels: 25e6
271
+ };
272
+ var _source, _createCanvas, _logger, _limits, _sourcePolicy, _loadingState, _document, _destroyPromise, _activeRenderTasks, _activePageWorkCount, _destroyed, _lastLoadFailed, _PDFReader_instances, load_fn, processPage_fn, encodePageImage_fn, resolveViewport_fn, encodeCanvasToBlob_fn, allocateCanvas_fn, waitForRender_fn, releaseCanvas_fn, getOrCreateLoadState_fn, awaitWithSignal_fn, createAbortedError_fn, createDestroyedError_fn, createDeadlineExceededError_fn, createUnsupportedEnvironmentError_fn, rethrowLifecycleError_fn, throwIfDestroyed_fn, throwIfAborted_fn, resolveLoadOptions_fn, isAbortSignal_fn, enforceSourcePolicy_fn, isPromiseLike_fn, inspectSource_fn, knownByteLength_fn, readUrl_fn, readHttpHeaders_fn, validateLimits_fn;
273
+ var PDFReader = class {
274
+ constructor(source, options = {}) {
275
+ __privateAdd(this, _PDFReader_instances);
276
+ __privateAdd(this, _source);
277
+ __privateAdd(this, _createCanvas);
278
+ __privateAdd(this, _logger);
279
+ __privateAdd(this, _limits);
280
+ __privateAdd(this, _sourcePolicy);
281
+ __privateAdd(this, _loadingState);
282
+ __privateAdd(this, _document);
283
+ __privateAdd(this, _destroyPromise);
284
+ __privateAdd(this, _activeRenderTasks, /* @__PURE__ */ new Set());
285
+ __privateAdd(this, _activePageWorkCount, 0);
286
+ __privateAdd(this, _destroyed, false);
287
+ __privateAdd(this, _lastLoadFailed, false);
288
+ __privateSet(this, _source, source);
289
+ __privateSet(this, _createCanvas, options.canvasFactory ?? (() => document.createElement("canvas")));
290
+ __privateSet(this, _logger, options.logger);
291
+ __privateSet(this, _limits, { ...defaultLimits, ...options.limits });
292
+ __privateSet(this, _sourcePolicy, options.sourcePolicy);
293
+ __privateMethod(this, _PDFReader_instances, validateLimits_fn).call(this);
294
+ }
295
+ get numPages() {
296
+ return __privateGet(this, _document)?.numPages;
297
+ }
298
+ /** Current lifecycle state for load, iteration/rendering, retry, and teardown boundaries. */
299
+ get state() {
300
+ if (__privateGet(this, _destroyed)) return "destroyed";
301
+ if (__privateGet(this, _activePageWorkCount) > 0) return "iterating";
302
+ if (__privateGet(this, _document)) return "loaded";
303
+ if (__privateGet(this, _loadingState)) return "loading";
304
+ if (__privateGet(this, _lastLoadFailed)) return "failed";
305
+ return "new";
306
+ }
307
+ load(options) {
308
+ const resolved = __privateMethod(this, _PDFReader_instances, resolveLoadOptions_fn).call(this, options);
309
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, resolved.signal);
310
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
311
+ if (__privateGet(this, _document)) return Promise.resolve(__privateGet(this, _document));
312
+ return __privateMethod(this, _PDFReader_instances, load_fn).call(this, resolved);
313
+ }
314
+ /** Streams page results so callers do not need to retain the entire document conversion in memory. */
315
+ async *pages(options = {}) {
316
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
317
+ const documentProxy = __privateGet(this, _document);
318
+ if (!documentProxy) {
319
+ throw new PdfReaderError("DOCUMENT_NOT_LOADED", "Document not loaded. Call load() first.");
320
+ }
321
+ const resolved = resolveConvertOptions(options);
322
+ const [start, end] = resolvePageNumbers(resolved.pageRange, documentProxy.numPages);
323
+ if (start > documentProxy.numPages) {
324
+ throw new PdfReaderError("INVALID_OPTION", `pageRange starts after the last page (${documentProxy.numPages}).`);
325
+ }
326
+ for (let pageNumber = start; pageNumber <= Math.min(end, documentProxy.numPages); pageNumber += 1) {
327
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
328
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, resolved.signal);
329
+ let page;
330
+ let ownsActivePageWork = false;
331
+ try {
332
+ __privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) + 1);
333
+ ownsActivePageWork = true;
334
+ page = await documentProxy.getPage(pageNumber);
335
+ const result = await __privateMethod(this, _PDFReader_instances, processPage_fn).call(this, page, pageNumber, documentProxy.numPages, resolved);
336
+ page.cleanup();
337
+ page = void 0;
338
+ __privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) - 1);
339
+ ownsActivePageWork = false;
340
+ yield result;
341
+ } catch (error) {
342
+ __privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, resolved.signal);
343
+ } finally {
344
+ if (ownsActivePageWork) __privateSet(this, _activePageWorkCount, __privateGet(this, _activePageWorkCount) - 1);
345
+ page?.cleanup();
346
+ }
347
+ }
348
+ }
349
+ /** Collects `pages()` into an array. Prefer `pages()` for large documents. */
350
+ async convert(options = {}) {
351
+ const results = [];
352
+ for await (const page of this.pages(options)) results.push(page);
353
+ return results;
354
+ }
355
+ /** Terminates the loading task and document resources. The reader cannot be reused afterwards. */
356
+ async destroy() {
357
+ if (__privateGet(this, _destroyPromise)) return __privateGet(this, _destroyPromise);
358
+ __privateSet(this, _destroyed, true);
359
+ const documentProxy = __privateGet(this, _document);
360
+ const loadingState = __privateGet(this, _loadingState);
361
+ __privateSet(this, _document, void 0);
362
+ __privateSet(this, _loadingState, void 0);
363
+ __privateSet(this, _destroyPromise, (async () => {
364
+ for (const renderTask of __privateGet(this, _activeRenderTasks)) renderTask.cancel();
365
+ if (documentProxy) {
366
+ await documentProxy.destroy();
367
+ return;
368
+ }
369
+ if (!loadingState) return;
370
+ loadingState.destroyed = true;
371
+ loadingState.destroyPromise ?? (loadingState.destroyPromise = loadingState.task ? loadingState.task.destroy() : Promise.resolve());
372
+ await loadingState.destroyPromise;
373
+ })());
374
+ await __privateGet(this, _destroyPromise);
375
+ }
376
+ };
377
+ _source = new WeakMap();
378
+ _createCanvas = new WeakMap();
379
+ _logger = new WeakMap();
380
+ _limits = new WeakMap();
381
+ _sourcePolicy = new WeakMap();
382
+ _loadingState = new WeakMap();
383
+ _document = new WeakMap();
384
+ _destroyPromise = new WeakMap();
385
+ _activeRenderTasks = new WeakMap();
386
+ _activePageWorkCount = new WeakMap();
387
+ _destroyed = new WeakMap();
388
+ _lastLoadFailed = new WeakMap();
389
+ _PDFReader_instances = new WeakSet();
390
+ load_fn = async function(options) {
391
+ const state = __privateMethod(this, _PDFReader_instances, getOrCreateLoadState_fn).call(this);
392
+ try {
393
+ const documentProxy = await __privateMethod(this, _PDFReader_instances, awaitWithSignal_fn).call(this, state.promise, options.signal, options.deadlineMs);
394
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
395
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
396
+ return documentProxy;
397
+ } catch (error) {
398
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
399
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
400
+ throw error;
401
+ }
402
+ };
403
+ processPage_fn = async function(page, pageNumber, numPages, options) {
404
+ const viewport = __privateMethod(this, _PDFReader_instances, resolveViewport_fn).call(this, page, options.viewportScale);
405
+ const result = {
406
+ numPages,
407
+ pageNumber,
408
+ pageIndex: pageNumber - 1,
409
+ viewport,
410
+ images: []
411
+ };
412
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
413
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
414
+ if (options.includeText) {
415
+ try {
416
+ result.text = await page.getTextContent();
417
+ } catch (error) {
418
+ __privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, options.signal);
419
+ }
420
+ }
421
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
422
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
423
+ if (options.includeEmbeddedImages) {
424
+ try {
425
+ result.images = await extractEmbeddedImages(page, viewport, {
426
+ signal: options.signal,
427
+ createCanvas: __privateGet(this, _createCanvas),
428
+ maxPixels: __privateGet(this, _limits).maxEmbeddedImagePixels,
429
+ logger: __privateGet(this, _logger),
430
+ throwIfAborted: (signal) => __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal),
431
+ throwIfDestroyed: () => __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this)
432
+ });
433
+ } catch (error) {
434
+ __privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, options.signal);
435
+ }
436
+ }
437
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, options.signal);
438
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
439
+ if (options.includePageImage) {
440
+ const canvas = __privateMethod(this, _PDFReader_instances, allocateCanvas_fn).call(this, viewport.width, viewport.height, __privateGet(this, _limits).maxCanvasPixels, "page");
441
+ try {
442
+ const context = canvas.getContext("2d");
443
+ if (!context) {
444
+ throw __privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, `Failed to create a 2D canvas context for page ${pageNumber}.`);
445
+ }
446
+ const renderTask = page.render({ canvas, canvasContext: context, viewport });
447
+ await __privateMethod(this, _PDFReader_instances, waitForRender_fn).call(this, renderTask, options.signal);
448
+ result.pageImage = await __privateMethod(this, _PDFReader_instances, encodePageImage_fn).call(this, canvas, options.imageFormat, options.pageImageOutput, options.jpegQuality, options.signal);
449
+ } finally {
450
+ __privateMethod(this, _PDFReader_instances, releaseCanvas_fn).call(this, canvas);
451
+ }
452
+ }
453
+ return result;
454
+ };
455
+ encodePageImage_fn = async function(canvas, mimeType, output, jpegQuality, signal) {
456
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
457
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
458
+ const quality = mimeType === "image/jpeg" ? jpegQuality : void 0;
459
+ if (output === "data-url") {
460
+ const dataUrl = quality === void 0 ? canvas.toDataURL(mimeType) : canvas.toDataURL(mimeType, quality);
461
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
462
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
463
+ return { kind: "data-url", mimeType, dataUrl };
464
+ }
465
+ const blob = await __privateMethod(this, _PDFReader_instances, encodeCanvasToBlob_fn).call(this, canvas, mimeType, quality, signal);
466
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
467
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
468
+ return { kind: "blob", mimeType, blob };
469
+ };
470
+ resolveViewport_fn = function(page, viewportScale) {
471
+ if (typeof viewportScale === "number") return page.getViewport({ scale: viewportScale });
472
+ const base = page.getViewport({ scale: 1 });
473
+ const scale = viewportScale(base.width, base.height);
474
+ assertPositiveFinite(scale, "viewportScale callback result");
475
+ return page.getViewport({ scale });
476
+ };
477
+ encodeCanvasToBlob_fn = async function(canvas, mimeType, quality, signal) {
478
+ if (typeof canvas.toBlob !== "function") {
479
+ throw __privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, "Canvas Blob encoding is not supported by this canvas implementation.");
480
+ }
481
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
482
+ return await new Promise((resolve, reject) => {
483
+ let settled = false;
484
+ const onAbort = () => settle(() => reject(__privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this)));
485
+ const cleanup = () => signal?.removeEventListener("abort", onAbort);
486
+ const settle = (callback) => {
487
+ if (settled) return;
488
+ settled = true;
489
+ cleanup();
490
+ callback();
491
+ };
492
+ signal?.addEventListener("abort", onAbort, { once: true });
493
+ try {
494
+ const resolveBlob = (blob) => {
495
+ if (!blob) {
496
+ settle(
497
+ () => reject(__privateMethod(this, _PDFReader_instances, createUnsupportedEnvironmentError_fn).call(this, `Canvas Blob encoding returned null for ${mimeType}.`))
498
+ );
499
+ return;
500
+ }
501
+ settle(() => resolve(blob));
502
+ };
503
+ if (quality === void 0) {
504
+ canvas.toBlob(resolveBlob, mimeType);
505
+ } else {
506
+ canvas.toBlob(resolveBlob, mimeType, quality);
507
+ }
508
+ } catch (error) {
509
+ settle(() => reject(error));
510
+ }
511
+ });
512
+ };
513
+ allocateCanvas_fn = function(width, height, limit, subject) {
514
+ const pixelWidth = Math.ceil(width);
515
+ const pixelHeight = Math.ceil(height);
516
+ const pixels = pixelWidth * pixelHeight;
517
+ if (!Number.isSafeInteger(pixels) || pixels > limit) {
518
+ const code = subject === "page" ? "CANVAS_LIMIT_EXCEEDED" : "IMAGE_LIMIT_EXCEEDED";
519
+ throw new PdfReaderError(code, `${subject} requires ${pixels} pixels; limit is ${limit}.`);
520
+ }
521
+ const canvas = __privateGet(this, _createCanvas).call(this);
522
+ canvas.width = pixelWidth;
523
+ canvas.height = pixelHeight;
524
+ return canvas;
525
+ };
526
+ waitForRender_fn = async function(renderTask, signal) {
527
+ const abort = () => renderTask.cancel();
528
+ __privateGet(this, _activeRenderTasks).add(renderTask);
529
+ signal?.addEventListener("abort", abort, { once: true });
530
+ try {
531
+ await renderTask.promise;
532
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
533
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
534
+ } catch (error) {
535
+ __privateMethod(this, _PDFReader_instances, rethrowLifecycleError_fn).call(this, error, signal);
536
+ } finally {
537
+ signal?.removeEventListener("abort", abort);
538
+ __privateGet(this, _activeRenderTasks).delete(renderTask);
539
+ }
540
+ };
541
+ releaseCanvas_fn = function(canvas) {
542
+ canvas.width = 0;
543
+ canvas.height = 0;
544
+ };
545
+ getOrCreateLoadState_fn = function() {
546
+ const existing = __privateGet(this, _loadingState);
547
+ if (existing) return existing;
548
+ __privateSet(this, _lastLoadFailed, false);
549
+ const state = { destroyed: false };
550
+ state.promise = (async () => {
551
+ try {
552
+ const policyResult = __privateMethod(this, _PDFReader_instances, enforceSourcePolicy_fn).call(this);
553
+ if (__privateMethod(this, _PDFReader_instances, isPromiseLike_fn).call(this, policyResult)) await policyResult;
554
+ if (state.destroyed || __privateGet(this, _destroyed)) {
555
+ throw __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this);
556
+ }
557
+ const task = getDocument(__privateGet(this, _source));
558
+ state.task = task;
559
+ const documentProxy = await task.promise;
560
+ if (state.destroyed || state.destroyPromise) {
561
+ await state.destroyPromise?.catch(() => void 0);
562
+ throw __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this);
563
+ }
564
+ if (documentProxy.numPages > __privateGet(this, _limits).maxDocumentPages) {
565
+ await documentProxy.destroy();
566
+ throw new PdfReaderError(
567
+ "PAGE_LIMIT_EXCEEDED",
568
+ `PDF has ${documentProxy.numPages} pages; limit is ${__privateGet(this, _limits).maxDocumentPages}.`
569
+ );
570
+ }
571
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
572
+ __privateSet(this, _document, documentProxy);
573
+ __privateSet(this, _lastLoadFailed, false);
574
+ return documentProxy;
575
+ } catch (error) {
576
+ if (state.destroyed || state.destroyPromise || __privateGet(this, _destroyed)) {
577
+ await state.destroyPromise?.catch(() => void 0);
578
+ throw __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this);
579
+ }
580
+ __privateSet(this, _lastLoadFailed, true);
581
+ throw error;
582
+ } finally {
583
+ if (__privateGet(this, _loadingState) === state) __privateSet(this, _loadingState, void 0);
584
+ }
585
+ })();
586
+ state.promise.catch(() => void 0);
587
+ __privateSet(this, _loadingState, state);
588
+ return state;
589
+ };
590
+ awaitWithSignal_fn = async function(promise, signal, deadlineMs) {
591
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
592
+ if (!signal && deadlineMs === void 0) return promise;
593
+ return await new Promise((resolve, reject) => {
594
+ let settled = false;
595
+ const onAbort = () => settle(() => reject(__privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this)));
596
+ const cleanup = () => {
597
+ signal?.removeEventListener("abort", onAbort);
598
+ if (timer !== void 0) clearTimeout(timer);
599
+ };
600
+ const settle = (callback) => {
601
+ if (settled) return;
602
+ settled = true;
603
+ cleanup();
604
+ callback();
605
+ };
606
+ const timer = deadlineMs === void 0 ? void 0 : setTimeout(() => settle(() => reject(__privateMethod(this, _PDFReader_instances, createDeadlineExceededError_fn).call(this))), deadlineMs);
607
+ signal?.addEventListener("abort", onAbort, { once: true });
608
+ promise.then(
609
+ (value) => settle(() => resolve(value)),
610
+ (error) => settle(() => reject(error))
611
+ ).catch(() => void 0);
612
+ });
613
+ };
614
+ createAbortedError_fn = function() {
615
+ return new PdfReaderError("ABORTED", "PDF operation was aborted.");
616
+ };
617
+ createDestroyedError_fn = function() {
618
+ return new PdfReaderError("DESTROYED", "PDFReader has been destroyed.");
619
+ };
620
+ createDeadlineExceededError_fn = function() {
621
+ return new PdfReaderError("DEADLINE_EXCEEDED", "PDF load exceeded the configured deadline.");
622
+ };
623
+ createUnsupportedEnvironmentError_fn = function(message) {
624
+ return new PdfReaderError("UNSUPPORTED_ENVIRONMENT", message);
625
+ };
626
+ rethrowLifecycleError_fn = function(error, signal) {
627
+ __privateMethod(this, _PDFReader_instances, throwIfDestroyed_fn).call(this);
628
+ __privateMethod(this, _PDFReader_instances, throwIfAborted_fn).call(this, signal);
629
+ throw error;
630
+ };
631
+ throwIfDestroyed_fn = function() {
632
+ if (__privateGet(this, _destroyed)) throw __privateMethod(this, _PDFReader_instances, createDestroyedError_fn).call(this);
633
+ };
634
+ throwIfAborted_fn = function(signal) {
635
+ if (signal?.aborted) throw __privateMethod(this, _PDFReader_instances, createAbortedError_fn).call(this);
636
+ };
637
+ resolveLoadOptions_fn = function(options) {
638
+ if (!options) return {};
639
+ if (__privateMethod(this, _PDFReader_instances, isAbortSignal_fn).call(this, options)) return { signal: options };
640
+ if (options.deadlineMs !== void 0 && (!Number.isFinite(options.deadlineMs) || options.deadlineMs <= 0)) {
641
+ throw new PdfReaderError("INVALID_OPTION", "deadlineMs must be a positive finite number.");
642
+ }
643
+ return options;
644
+ };
645
+ isAbortSignal_fn = function(value) {
646
+ return "aborted" in value && "addEventListener" in value && "removeEventListener" in value;
647
+ };
648
+ enforceSourcePolicy_fn = function() {
649
+ const source = __privateMethod(this, _PDFReader_instances, inspectSource_fn).call(this, __privateGet(this, _source));
650
+ if (source.byteLength !== void 0 && __privateGet(this, _limits).maxSourceBytes !== void 0 && source.byteLength > __privateGet(this, _limits).maxSourceBytes) {
651
+ throw new PdfReaderError(
652
+ "SOURCE_LIMIT_EXCEEDED",
653
+ `PDF source is ${source.byteLength} bytes; limit is ${__privateGet(this, _limits).maxSourceBytes}.`
654
+ );
655
+ }
656
+ if (!__privateGet(this, _sourcePolicy)) return;
657
+ try {
658
+ const result = __privateGet(this, _sourcePolicy).call(this, source);
659
+ if (!__privateMethod(this, _PDFReader_instances, isPromiseLike_fn).call(this, result)) return;
660
+ return result.catch((error) => {
661
+ if (error instanceof PdfReaderError) throw error;
662
+ throw new PdfReaderError("SOURCE_POLICY_VIOLATION", "PDF source rejected by sourcePolicy.");
663
+ });
664
+ } catch (error) {
665
+ if (error instanceof PdfReaderError) throw error;
666
+ throw new PdfReaderError("SOURCE_POLICY_VIOLATION", "PDF source rejected by sourcePolicy.");
667
+ }
668
+ };
669
+ isPromiseLike_fn = function(value) {
670
+ return value instanceof Promise;
671
+ };
672
+ inspectSource_fn = function(source) {
673
+ if (typeof source === "string") {
674
+ return {
675
+ rawSource: source,
676
+ kind: "url",
677
+ url: source,
678
+ hasHttpHeaders: false,
679
+ withCredentials: false
680
+ };
681
+ }
682
+ if (typeof URL !== "undefined" && source instanceof URL) {
683
+ return {
684
+ rawSource: source,
685
+ kind: "url",
686
+ url: source.toString(),
687
+ hasHttpHeaders: false,
688
+ withCredentials: false
689
+ };
690
+ }
691
+ const byteLength = __privateMethod(this, _PDFReader_instances, knownByteLength_fn).call(this, source);
692
+ if (byteLength !== void 0) {
693
+ return {
694
+ rawSource: source,
695
+ kind: "bytes",
696
+ byteLength,
697
+ hasHttpHeaders: false,
698
+ withCredentials: false
699
+ };
700
+ }
701
+ const candidate = source;
702
+ const headers = __privateMethod(this, _PDFReader_instances, readHttpHeaders_fn).call(this, candidate.httpHeaders);
703
+ return {
704
+ rawSource: source,
705
+ kind: "document-init-parameters",
706
+ url: __privateMethod(this, _PDFReader_instances, readUrl_fn).call(this, candidate.url),
707
+ byteLength: __privateMethod(this, _PDFReader_instances, knownByteLength_fn).call(this, candidate.data),
708
+ hasHttpHeaders: headers !== void 0,
709
+ httpHeaders: headers,
710
+ withCredentials: candidate.withCredentials === true
711
+ };
712
+ };
713
+ knownByteLength_fn = function(value) {
714
+ if (value instanceof ArrayBuffer) return value.byteLength;
715
+ if (ArrayBuffer.isView(value)) return value.byteLength;
716
+ if (Array.isArray(value) && value.every((entry) => Number.isFinite(entry))) return value.length;
717
+ return void 0;
718
+ };
719
+ readUrl_fn = function(value) {
720
+ if (typeof value === "string") return value;
721
+ if (typeof URL !== "undefined" && value instanceof URL) return value.toString();
722
+ return void 0;
723
+ };
724
+ readHttpHeaders_fn = function(value) {
725
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
726
+ const entries = Object.entries(value).filter((entry) => typeof entry[1] === "string");
727
+ if (entries.length === 0) return void 0;
728
+ return Object.freeze(Object.fromEntries(entries));
729
+ };
730
+ validateLimits_fn = function() {
731
+ for (const [name, value] of Object.entries(__privateGet(this, _limits))) {
732
+ if (value === void 0) continue;
733
+ if (!Number.isSafeInteger(value) || value <= 0) {
734
+ throw new PdfReaderError("INVALID_OPTION", `${name} must be a positive safe integer.`);
735
+ }
736
+ }
737
+ };
738
+
739
+ // src/source.ts
740
+ function pdfUrlSource(url, options = {}) {
741
+ return { ...options, url };
742
+ }
743
+
744
+ // src/worker.ts
745
+ import { GlobalWorkerOptions } from "pdfjs-dist";
746
+ function configurePdfWorker(worker) {
747
+ if (typeof worker === "string") {
748
+ GlobalWorkerOptions.workerPort = null;
749
+ GlobalWorkerOptions.workerSrc = worker;
750
+ } else {
751
+ GlobalWorkerOptions.workerSrc = "";
752
+ GlobalWorkerOptions.workerPort = worker;
753
+ }
754
+ }
755
+ export {
756
+ PDFReader,
757
+ PdfReaderError,
758
+ configurePdfWorker,
759
+ pdfUrlSource
760
+ };