canvu-react 0.4.75 → 0.4.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -210,342 +210,6 @@ var IndexedDbImageStore = class {
210
210
  }
211
211
  };
212
212
 
213
- // src/image/pdf-worker-renderer.ts
214
- var PDF_WORKER_SOURCE = `
215
- let pdfjsPromise = null;
216
-
217
- const loadPdfJs = async (pdfjsModuleCandidates) => {
218
- if (!pdfjsPromise) {
219
- pdfjsPromise = (async () => {
220
- let lastError;
221
- for (const candidate of pdfjsModuleCandidates) {
222
- try {
223
- const pdfjs = await import(candidate.moduleUrl);
224
- if (pdfjs.GlobalWorkerOptions) {
225
- pdfjs.GlobalWorkerOptions.workerSrc = candidate.workerUrl;
226
- }
227
- return pdfjs;
228
- } catch (error) {
229
- lastError = error;
230
- }
231
- }
232
- throw lastError ?? new Error("Unable to load pdfjs-dist");
233
- })();
234
- }
235
- return await pdfjsPromise;
236
- };
237
-
238
- const createErrorPayload = (error) => ({
239
- message: error instanceof Error ? error.message : String(error),
240
- name: error instanceof Error ? error.name : "Error",
241
- stack: error instanceof Error ? error.stack : undefined,
242
- });
243
-
244
- const normalizePdfPageNumbers = (pageNumbers, pageCount) => {
245
- if (!Array.isArray(pageNumbers) || pageNumbers.length === 0) {
246
- return Array.from({ length: pageCount }, (_, index) => index + 1);
247
- }
248
- return [...new Set(pageNumbers)]
249
- .filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount)
250
- .sort((left, right) => left - right);
251
- };
252
-
253
- const runWithConcurrency = async (items, concurrency, execute) => {
254
- const results = new Array(items.length);
255
- let nextIndex = 0;
256
- const safeConcurrency = Number.isFinite(concurrency) && concurrency > 0
257
- ? Math.round(concurrency)
258
- : 1;
259
- const workerCount = Math.max(1, Math.min(safeConcurrency, items.length));
260
- await Promise.all(
261
- Array.from({ length: workerCount }, async () => {
262
- while (nextIndex < items.length) {
263
- const currentIndex = nextIndex;
264
- nextIndex += 1;
265
- const item = items[currentIndex];
266
- if (item === undefined) {
267
- continue;
268
- }
269
- results[currentIndex] = await execute(item);
270
- }
271
- }),
272
- );
273
- return results;
274
- };
275
-
276
- const renderPageToBlob = async (page, scale, storeThumbnails) => {
277
- const raw = page.getViewport({ scale: 1 });
278
- const adjustedScale = Math.round(raw.width * scale) / raw.width;
279
- const viewport = page.getViewport({ scale: adjustedScale });
280
- const width = Math.round(viewport.width);
281
- const height = Math.round(viewport.height);
282
- const canvas = new OffscreenCanvas(width, height);
283
- const canvasContext = canvas.getContext("2d");
284
- if (!canvasContext) {
285
- throw new Error("OffscreenCanvas 2D context unavailable");
286
- }
287
- canvasContext.imageSmoothingEnabled = true;
288
- canvasContext.imageSmoothingQuality = "high";
289
- await page.render({ canvasContext, viewport }).promise;
290
- const blob = await canvas.convertToBlob({ type: "image/png" });
291
- let thumbnailBlob;
292
- if (storeThumbnails) {
293
- const thumbScale = Math.min(1, 256 / Math.max(width, height));
294
- const thumbnailWidth = Math.max(1, Math.round(width * thumbScale));
295
- const thumbnailHeight = Math.max(1, Math.round(height * thumbScale));
296
- const thumbnailCanvas = new OffscreenCanvas(thumbnailWidth, thumbnailHeight);
297
- const thumbnailContext = thumbnailCanvas.getContext("2d");
298
- if (thumbnailContext) {
299
- thumbnailContext.imageSmoothingEnabled = true;
300
- thumbnailContext.imageSmoothingQuality = "high";
301
- thumbnailContext.drawImage(canvas, 0, 0, thumbnailWidth, thumbnailHeight);
302
- }
303
- thumbnailBlob = await thumbnailCanvas.convertToBlob({ type: "image/png" });
304
- }
305
- return { blob, height, thumbnailBlob, width };
306
- };
307
-
308
- self.onmessage = async (event) => {
309
- const message = event.data;
310
- if (!message || message.type !== "render") {
311
- return;
312
- }
313
- try {
314
- const pdfjs = await loadPdfJs(message.pdfjsModuleCandidates);
315
- const pdf = await pdfjs.getDocument({
316
- data: new Uint8Array(message.pdfData),
317
- disableWorker: true,
318
- }).promise;
319
- try {
320
- const pageNumbers = normalizePdfPageNumbers(message.pageNumbers, pdf.numPages);
321
- const bufferedPages = new Map();
322
- let nextEmitIndex = 0;
323
- let emitChain = Promise.resolve();
324
- const emitPageInOrder = async (pageNumber, renderedPage) => {
325
- bufferedPages.set(pageNumber, renderedPage);
326
- const flush = () => {
327
- while (nextEmitIndex < pageNumbers.length) {
328
- const nextPageNumber = pageNumbers[nextEmitIndex];
329
- if (nextPageNumber == null) break;
330
- const nextPage = bufferedPages.get(nextPageNumber);
331
- if (!nextPage) break;
332
- bufferedPages.delete(nextPageNumber);
333
- nextEmitIndex += 1;
334
- self.postMessage({
335
- type: "page",
336
- page: {
337
- ...nextPage,
338
- pageNumber: nextPageNumber,
339
- },
340
- });
341
- }
342
- };
343
- const nextChain = emitChain.then(flush, flush);
344
- emitChain = nextChain.catch(() => {});
345
- await nextChain;
346
- };
347
- await runWithConcurrency(
348
- pageNumbers,
349
- message.pageConcurrency,
350
- async (pageNumber) => {
351
- const page = await pdf.getPage(pageNumber);
352
- try {
353
- const renderedPage = await renderPageToBlob(
354
- page,
355
- message.scale,
356
- message.storeThumbnails,
357
- );
358
- await emitPageInOrder(pageNumber, renderedPage);
359
- } finally {
360
- page.cleanup();
361
- }
362
- },
363
- );
364
- await emitChain;
365
- } finally {
366
- await pdf.destroy();
367
- }
368
- self.postMessage({ type: "done" });
369
- } catch (error) {
370
- self.postMessage({ type: "error", error: createErrorPayload(error) });
371
- }
372
- };
373
- `;
374
- var isRecord = (value) => typeof value === "object" && value !== null;
375
- var hasObjectMembers = (value) => (typeof value === "object" || typeof value === "function") && value !== null;
376
- var isOffscreenCanvasCandidate = (value) => typeof value === "function";
377
- var getEnvironmentRecord = (environment) => isRecord(environment) ? environment : null;
378
- var canUsePdfWorkerRenderer = (environment = globalThis) => {
379
- const candidateEnvironment = getEnvironmentRecord(environment);
380
- if (!candidateEnvironment) return false;
381
- if (typeof candidateEnvironment.Worker !== "function") return false;
382
- if (typeof candidateEnvironment.Blob !== "function") return false;
383
- if (!isOffscreenCanvasCandidate(candidateEnvironment.OffscreenCanvas)) {
384
- return false;
385
- }
386
- const urlCandidate = candidateEnvironment.URL;
387
- if (!hasObjectMembers(urlCandidate)) return false;
388
- if (typeof urlCandidate.createObjectURL !== "function") return false;
389
- if (typeof urlCandidate.revokeObjectURL !== "function") return false;
390
- try {
391
- const canvas = new candidateEnvironment.OffscreenCanvas(1, 1);
392
- return typeof canvas.getContext === "function" && typeof canvas.convertToBlob === "function";
393
- } catch {
394
- return false;
395
- }
396
- };
397
- var createAbortError = () => new DOMException("Aborted", "AbortError");
398
- var throwIfAborted = (signal) => {
399
- if (signal?.aborted) {
400
- throw createAbortError();
401
- }
402
- };
403
- var createPdfWorker = () => {
404
- const workerBlob = new Blob([PDF_WORKER_SOURCE], {
405
- type: "text/javascript"
406
- });
407
- const workerUrl = URL.createObjectURL(workerBlob);
408
- try {
409
- const worker = new Worker(workerUrl, {
410
- name: "canvu-pdf-renderer",
411
- type: "module"
412
- });
413
- return {
414
- release: () => URL.revokeObjectURL(workerUrl),
415
- worker
416
- };
417
- } catch (error) {
418
- URL.revokeObjectURL(workerUrl);
419
- throw error;
420
- }
421
- };
422
- var createWorkerError = (message) => {
423
- const error = new Error(message.error.message);
424
- error.name = message.error.name;
425
- error.stack = message.error.stack;
426
- return error;
427
- };
428
- var PACKAGED_PDFJS_MODULE_FILE = "./pdf.mjs";
429
- var PACKAGED_PDFJS_WORKER_FILE = "./pdf.worker.mjs";
430
- var resolveRelativeAssetUrl = (path, baseUrl) => new URL(path, baseUrl).toString();
431
- var resolvePackagedPdfJsModuleCandidate = (baseUrl = (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))) => ({
432
- moduleUrl: resolveRelativeAssetUrl(PACKAGED_PDFJS_MODULE_FILE, baseUrl),
433
- workerUrl: resolveRelativeAssetUrl(PACKAGED_PDFJS_WORKER_FILE, baseUrl)
434
- });
435
- var resolveBundledPdfJsModuleCandidate = () => ({
436
- moduleUrl: new URL("pdfjs-dist/build/pdf.min.mjs", (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))).toString(),
437
- workerUrl: new URL(
438
- "pdfjs-dist/build/pdf.worker.min.mjs",
439
- (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
440
- ).toString()
441
- });
442
- var resolvePdfJsModuleCandidates = () => [
443
- resolvePackagedPdfJsModuleCandidate(),
444
- resolveBundledPdfJsModuleCandidate()
445
- ];
446
- var loadPdfToStoreWithWorker = async (file, store, options) => {
447
- throwIfAborted(options.signal);
448
- const arrayBuffer = await file.arrayBuffer();
449
- throwIfAborted(options.signal);
450
- return await new Promise((resolve, reject) => {
451
- const { release, worker } = createPdfWorker();
452
- const pageResults = [];
453
- let storeChain = Promise.resolve();
454
- let cleanedUp = false;
455
- let settled = false;
456
- const cleanup = () => {
457
- if (cleanedUp) return;
458
- cleanedUp = true;
459
- options.signal?.removeEventListener("abort", abortWorker);
460
- worker.onmessage = null;
461
- worker.onerror = null;
462
- worker.terminate();
463
- release();
464
- };
465
- const rejectOnce = (error) => {
466
- if (settled) return;
467
- settled = true;
468
- cleanup();
469
- reject(error);
470
- };
471
- const rejectAfterQueuedStores = (error) => {
472
- if (settled) return;
473
- cleanup();
474
- storeChain.then(() => {
475
- if (settled) return;
476
- settled = true;
477
- reject(error);
478
- }).catch(rejectOnce);
479
- };
480
- function abortWorker() {
481
- rejectOnce(createAbortError());
482
- }
483
- const storePage = (message) => {
484
- try {
485
- options.onPageReceived?.({ pageNumber: message.page.pageNumber });
486
- } catch (error) {
487
- rejectOnce(error);
488
- return;
489
- }
490
- storeChain = storeChain.then(async () => {
491
- throwIfAborted(options.signal);
492
- const blobId = await store.storeOriginal(message.page.blob);
493
- throwIfAborted(options.signal);
494
- const thumbnailBlobId = options.storeThumbnails && message.page.thumbnailBlob ? await store.storeThumbnail(message.page.thumbnailBlob) : "";
495
- throwIfAborted(options.signal);
496
- const pageResult = {
497
- blobId,
498
- height: message.page.height,
499
- pageNumber: message.page.pageNumber,
500
- thumbnailBlobId,
501
- width: message.page.width
502
- };
503
- pageResults.push(pageResult);
504
- await options.onPageStored?.(pageResult);
505
- throwIfAborted(options.signal);
506
- });
507
- void storeChain.catch(rejectOnce);
508
- };
509
- worker.onmessage = (event) => {
510
- const message = event.data;
511
- if (message.type === "page") {
512
- storePage(message);
513
- return;
514
- }
515
- if (message.type === "error") {
516
- rejectAfterQueuedStores(createWorkerError(message));
517
- return;
518
- }
519
- storeChain.then(() => {
520
- if (settled) return;
521
- settled = true;
522
- cleanup();
523
- resolve(pageResults);
524
- }).catch(rejectOnce);
525
- };
526
- worker.onerror = (event) => {
527
- rejectAfterQueuedStores(event.error ?? new Error(event.message));
528
- };
529
- options.signal?.addEventListener("abort", abortWorker, { once: true });
530
- try {
531
- worker.postMessage(
532
- {
533
- pdfData: arrayBuffer,
534
- pdfjsModuleCandidates: resolvePdfJsModuleCandidates(),
535
- pageNumbers: options.pageNumbers ? [...options.pageNumbers] : void 0,
536
- pageConcurrency: options.pageConcurrency,
537
- scale: options.scale,
538
- storeThumbnails: options.storeThumbnails,
539
- type: "render"
540
- },
541
- [arrayBuffer]
542
- );
543
- } catch (error) {
544
- rejectOnce(error);
545
- }
546
- });
547
- };
548
-
549
213
  // src/image/pdf-loader.ts
550
214
  var pdfjsPromise = null;
551
215
  function getPdfJs() {
@@ -562,7 +226,7 @@ function getPdfJs() {
562
226
  return pdfjsPromise;
563
227
  }
564
228
  async function renderPageToCanvas(page, scale, signal) {
565
- throwIfAborted2(signal);
229
+ throwIfAborted(signal);
566
230
  const raw = page.getViewport({ scale: 1 });
567
231
  const adjustedScale = Math.round(raw.width * scale) / raw.width;
568
232
  const viewport = page.getViewport({ scale: adjustedScale });
@@ -584,7 +248,7 @@ async function renderPageToCanvas(page, scale, signal) {
584
248
  try {
585
249
  await renderTask.promise;
586
250
  } catch (error) {
587
- if (signal.aborted) throw createAbortError2();
251
+ if (signal.aborted) throw createAbortError();
588
252
  throw error;
589
253
  } finally {
590
254
  signal.removeEventListener("abort", abortRender);
@@ -592,15 +256,15 @@ async function renderPageToCanvas(page, scale, signal) {
592
256
  } else {
593
257
  await renderTask.promise;
594
258
  }
595
- throwIfAborted2(signal);
259
+ throwIfAborted(signal);
596
260
  return { canvas, width: w, height: h };
597
261
  }
598
- function createAbortError2() {
262
+ function createAbortError() {
599
263
  return new DOMException("Aborted", "AbortError");
600
264
  }
601
- function throwIfAborted2(signal) {
265
+ function throwIfAborted(signal) {
602
266
  if (signal?.aborted) {
603
- throw createAbortError2();
267
+ throw createAbortError();
604
268
  }
605
269
  }
606
270
  function normalizePdfPageNumbers(pageNumbers, pageCount) {
@@ -616,7 +280,7 @@ async function runWithConcurrency(items, concurrency, execute, signal) {
616
280
  await Promise.all(
617
281
  Array.from({ length: workerCount }, async () => {
618
282
  while (nextIndex < items.length) {
619
- throwIfAborted2(signal);
283
+ throwIfAborted(signal);
620
284
  const currentIndex = nextIndex;
621
285
  nextIndex += 1;
622
286
  const item = items[currentIndex];
@@ -624,7 +288,7 @@ async function runWithConcurrency(items, concurrency, execute, signal) {
624
288
  continue;
625
289
  }
626
290
  results[currentIndex] = await execute(item);
627
- throwIfAborted2(signal);
291
+ throwIfAborted(signal);
628
292
  }
629
293
  })
630
294
  );
@@ -635,52 +299,11 @@ async function loadPdfToStore(file, store, options) {
635
299
  const pageConcurrency = options?.pageConcurrency ?? 2;
636
300
  const storeThumbnails = options?.storeThumbnails ?? false;
637
301
  const signal = options?.signal;
638
- throwIfAborted2(signal);
639
- if (canUsePdfWorkerRenderer()) {
640
- let workerPageCount = 0;
641
- try {
642
- return await loadPdfToStoreWithWorker(file, store, {
643
- scale,
644
- pageNumbers: options?.pageNumbers,
645
- pageConcurrency,
646
- storeThumbnails,
647
- signal,
648
- onPageReceived: () => {
649
- workerPageCount += 1;
650
- },
651
- onPageStored: async (page) => {
652
- await options?.onPageStored?.(page);
653
- }
654
- });
655
- } catch (error) {
656
- if (signal?.aborted || workerPageCount > 0) {
657
- throw error;
658
- }
659
- }
660
- }
661
- return await loadPdfToStoreOnMainThread(file, store, {
662
- scale,
663
- pageNumbers: options?.pageNumbers,
664
- pageConcurrency,
665
- storeThumbnails,
666
- signal,
667
- onPageStored: options?.onPageStored
668
- });
669
- }
670
- async function loadPdfToStoreOnMainThread(file, store, options) {
671
- const {
672
- pageConcurrency,
673
- scale,
674
- signal,
675
- storeThumbnails,
676
- onPageStored,
677
- pageNumbers
678
- } = options;
679
- throwIfAborted2(signal);
302
+ throwIfAborted(signal);
680
303
  const pdfjs = await getPdfJs();
681
- throwIfAborted2(signal);
304
+ throwIfAborted(signal);
682
305
  const arrayBuffer = await file.arrayBuffer();
683
- throwIfAborted2(signal);
306
+ throwIfAborted(signal);
684
307
  const loadingTask = pdfjs.getDocument({ data: arrayBuffer });
685
308
  if (signal) {
686
309
  const abortLoading = () => {
@@ -692,14 +315,14 @@ async function loadPdfToStoreOnMainThread(file, store, options) {
692
315
  signal.removeEventListener("abort", abortLoading);
693
316
  return await loadPdfDocumentToStore(pdf2, store, {
694
317
  scale,
695
- pageNumbers,
318
+ pageNumbers: options?.pageNumbers,
696
319
  pageConcurrency,
697
320
  storeThumbnails,
698
321
  signal,
699
- onPageStored
322
+ onPageStored: options?.onPageStored
700
323
  });
701
324
  } catch (error) {
702
- if (signal.aborted) throw createAbortError2();
325
+ if (signal.aborted) throw createAbortError();
703
326
  throw error;
704
327
  } finally {
705
328
  signal.removeEventListener("abort", abortLoading);
@@ -708,16 +331,16 @@ async function loadPdfToStoreOnMainThread(file, store, options) {
708
331
  const pdf = await loadingTask.promise;
709
332
  return await loadPdfDocumentToStore(pdf, store, {
710
333
  scale,
711
- pageNumbers,
334
+ pageNumbers: options?.pageNumbers,
712
335
  pageConcurrency,
713
336
  storeThumbnails,
714
- onPageStored
337
+ onPageStored: options?.onPageStored
715
338
  });
716
339
  }
717
340
  async function loadPdfDocumentToStore(pdf, store, options) {
718
341
  const { pageConcurrency, scale, signal } = options;
719
342
  const storeThumbnails = options.storeThumbnails ?? false;
720
- throwIfAborted2(signal);
343
+ throwIfAborted(signal);
721
344
  const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
722
345
  const bufferedResults = /* @__PURE__ */ new Map();
723
346
  let nextEmitIndex = 0;
@@ -732,9 +355,9 @@ async function loadPdfDocumentToStore(pdf, store, options) {
732
355
  if (!bufferedResult) break;
733
356
  bufferedResults.delete(nextPageNumber);
734
357
  nextEmitIndex += 1;
735
- throwIfAborted2(signal);
358
+ throwIfAborted(signal);
736
359
  await options?.onPageStored?.(bufferedResult);
737
- throwIfAborted2(signal);
360
+ throwIfAborted(signal);
738
361
  }
739
362
  };
740
363
  const nextChain = emitChain.then(run, run);
@@ -746,20 +369,20 @@ async function loadPdfDocumentToStore(pdf, store, options) {
746
369
  pageNumbers,
747
370
  pageConcurrency,
748
371
  async (pageNumber) => {
749
- throwIfAborted2(signal);
372
+ throwIfAborted(signal);
750
373
  const page = await pdf.getPage(pageNumber);
751
- throwIfAborted2(signal);
374
+ throwIfAborted(signal);
752
375
  const { canvas, width, height } = await renderPageToCanvas(
753
376
  page,
754
377
  scale,
755
378
  signal
756
379
  );
757
- throwIfAborted2(signal);
380
+ throwIfAborted(signal);
758
381
  const mime = "image/png";
759
382
  const pageBlob = await encodeCanvasToBlob(canvas, { mimeType: mime });
760
- throwIfAborted2(signal);
383
+ throwIfAborted(signal);
761
384
  const blobId = await store.storeOriginal(pageBlob);
762
- throwIfAborted2(signal);
385
+ throwIfAborted(signal);
763
386
  const thumbnailBlobId = storeThumbnails ? await (async () => {
764
387
  const thumbScale = Math.min(1, 256 / Math.max(width, height));
765
388
  const tw = Math.max(1, Math.round(width * thumbScale));
@@ -776,7 +399,7 @@ async function loadPdfDocumentToStore(pdf, store, options) {
776
399
  const thumbBlob = await encodeCanvasToBlob(thumbCanvas, {
777
400
  mimeType: mime
778
401
  });
779
- throwIfAborted2(signal);
402
+ throwIfAborted(signal);
780
403
  return await store.storeThumbnail(thumbBlob);
781
404
  })() : "";
782
405
  const pageResult = {
@@ -3200,6 +2823,9 @@ function shouldRedrawRasterImageCanvas({
3200
2823
  if (currentSourceKey !== nextSourceKey && safeCurrentWidth === safeNextWidth && safeCurrentHeight === safeNextHeight) {
3201
2824
  return true;
3202
2825
  }
2826
+ if (currentSourceKey !== nextSourceKey && (safeNextWidth < safeCurrentWidth || safeNextHeight < safeCurrentHeight)) {
2827
+ return true;
2828
+ }
3203
2829
  return safeNextWidth > safeCurrentWidth * upscaleRedrawRatio || safeNextHeight > safeCurrentHeight * upscaleRedrawRatio;
3204
2830
  }
3205
2831
  function toPositiveFiniteNumber(value, fallback) {