canvu-react 0.3.13 → 0.3.14

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 CHANGED
@@ -255,6 +255,11 @@ export function BoardImport() {
255
255
  files: Array.from(files),
256
256
  worldCenter: { x: 0, y: 0 },
257
257
  assetStore,
258
+ pdfScale: 1.15,
259
+ pdfPageConcurrency: 2,
260
+ onItemsReady(nextItems) {
261
+ doc.onItemsChange([...doc.items, ...nextItems]);
262
+ },
258
263
  decorateItem(item) {
259
264
  return {
260
265
  ...item,
@@ -265,7 +270,6 @@ export function BoardImport() {
265
270
 
266
271
  doc.onItemsChange([...doc.items, ...result.items]);
267
272
  }
268
-
269
273
  if (!doc.isHydrated) return null;
270
274
 
271
275
  return (
@@ -300,6 +304,10 @@ export function BoardImport() {
300
304
  }
301
305
  ```
302
306
 
307
+ canvu can now stream PDF pages into the canvas progressively through
308
+ `onItemsReady(...)`, skip PDF thumbnails during ingest, and use a lower initial
309
+ raster scale by default to improve time-to-first-render.
310
+
303
311
  This helper is the same ingestion layer used internally by the native file
304
312
  tool, so external imports do not need to reimplement PDF rasterization, local
305
313
  blob persistence, or `pluginData` attachment.
package/dist/index.cjs CHANGED
@@ -243,10 +243,32 @@ async function runWithConcurrency(items, concurrency, execute) {
243
243
  async function loadPdfToStore(file, store, options) {
244
244
  const scale = options?.scale ?? 1.5;
245
245
  const pageConcurrency = options?.pageConcurrency ?? 2;
246
+ const storeThumbnails = options?.storeThumbnails ?? false;
246
247
  const pdfjs = await getPdfJs();
247
248
  const arrayBuffer = await file.arrayBuffer();
248
249
  const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
249
250
  const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
251
+ const bufferedResults = /* @__PURE__ */ new Map();
252
+ let nextEmitIndex = 0;
253
+ let emitChain = Promise.resolve();
254
+ const queuePageEmission = async (pageResult) => {
255
+ bufferedResults.set(pageResult.pageNumber, pageResult);
256
+ const run = async () => {
257
+ while (nextEmitIndex < pageNumbers.length) {
258
+ const nextPageNumber = pageNumbers[nextEmitIndex];
259
+ if (nextPageNumber == null) break;
260
+ const bufferedResult = bufferedResults.get(nextPageNumber);
261
+ if (!bufferedResult) break;
262
+ bufferedResults.delete(nextPageNumber);
263
+ nextEmitIndex += 1;
264
+ await options?.onPageStored?.(bufferedResult);
265
+ }
266
+ };
267
+ const nextChain = emitChain.then(run, run);
268
+ emitChain = nextChain.catch(() => {
269
+ });
270
+ await nextChain;
271
+ };
250
272
  return await runWithConcurrency(
251
273
  pageNumbers,
252
274
  pageConcurrency,
@@ -256,27 +278,31 @@ async function loadPdfToStore(file, store, options) {
256
278
  const mime = "image/png";
257
279
  const pageBlob = await canvasToBlob(canvas, mime);
258
280
  const blobId = await store.storeOriginal(pageBlob);
259
- const thumbScale = Math.min(1, 256 / Math.max(width, height));
260
- const tw = Math.max(1, Math.round(width * thumbScale));
261
- const th = Math.max(1, Math.round(height * thumbScale));
262
- const thumbCanvas = document.createElement("canvas");
263
- thumbCanvas.width = tw;
264
- thumbCanvas.height = th;
265
- const tCtx = thumbCanvas.getContext("2d");
266
- if (tCtx) {
267
- tCtx.imageSmoothingEnabled = true;
268
- tCtx.imageSmoothingQuality = "high";
269
- tCtx.drawImage(canvas, 0, 0, tw, th);
270
- }
271
- const thumbBlob = await canvasToBlob(thumbCanvas, mime);
272
- const thumbnailBlobId = await store.storeThumbnail(thumbBlob);
273
- return {
281
+ const thumbnailBlobId = storeThumbnails ? await (async () => {
282
+ const thumbScale = Math.min(1, 256 / Math.max(width, height));
283
+ const tw = Math.max(1, Math.round(width * thumbScale));
284
+ const th = Math.max(1, Math.round(height * thumbScale));
285
+ const thumbCanvas = document.createElement("canvas");
286
+ thumbCanvas.width = tw;
287
+ thumbCanvas.height = th;
288
+ const tCtx = thumbCanvas.getContext("2d");
289
+ if (tCtx) {
290
+ tCtx.imageSmoothingEnabled = true;
291
+ tCtx.imageSmoothingQuality = "high";
292
+ tCtx.drawImage(canvas, 0, 0, tw, th);
293
+ }
294
+ const thumbBlob = await canvasToBlob(thumbCanvas, mime);
295
+ return await store.storeThumbnail(thumbBlob);
296
+ })() : "";
297
+ const pageResult = {
274
298
  blobId,
275
299
  thumbnailBlobId,
276
300
  width,
277
301
  height,
278
302
  pageNumber
279
303
  };
304
+ await queuePageEmission(pageResult);
305
+ return pageResult;
280
306
  }
281
307
  );
282
308
  }