canvu-react 0.3.12 → 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 +9 -1
- package/dist/index.cjs +135 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +135 -63
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +194 -115
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +9 -1
- package/dist/react.d.ts +9 -1
- package/dist/react.js +194 -115
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +30 -5
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.js +30 -5
- package/dist/realtime.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -236,10 +236,32 @@ async function runWithConcurrency(items, concurrency, execute) {
|
|
|
236
236
|
async function loadPdfToStore(file, store, options) {
|
|
237
237
|
const scale = options?.scale ?? 1.5;
|
|
238
238
|
const pageConcurrency = options?.pageConcurrency ?? 2;
|
|
239
|
+
const storeThumbnails = options?.storeThumbnails ?? false;
|
|
239
240
|
const pdfjs = await getPdfJs();
|
|
240
241
|
const arrayBuffer = await file.arrayBuffer();
|
|
241
242
|
const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
|
|
242
243
|
const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
|
|
244
|
+
const bufferedResults = /* @__PURE__ */ new Map();
|
|
245
|
+
let nextEmitIndex = 0;
|
|
246
|
+
let emitChain = Promise.resolve();
|
|
247
|
+
const queuePageEmission = async (pageResult) => {
|
|
248
|
+
bufferedResults.set(pageResult.pageNumber, pageResult);
|
|
249
|
+
const run = async () => {
|
|
250
|
+
while (nextEmitIndex < pageNumbers.length) {
|
|
251
|
+
const nextPageNumber = pageNumbers[nextEmitIndex];
|
|
252
|
+
if (nextPageNumber == null) break;
|
|
253
|
+
const bufferedResult = bufferedResults.get(nextPageNumber);
|
|
254
|
+
if (!bufferedResult) break;
|
|
255
|
+
bufferedResults.delete(nextPageNumber);
|
|
256
|
+
nextEmitIndex += 1;
|
|
257
|
+
await options?.onPageStored?.(bufferedResult);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
const nextChain = emitChain.then(run, run);
|
|
261
|
+
emitChain = nextChain.catch(() => {
|
|
262
|
+
});
|
|
263
|
+
await nextChain;
|
|
264
|
+
};
|
|
243
265
|
return await runWithConcurrency(
|
|
244
266
|
pageNumbers,
|
|
245
267
|
pageConcurrency,
|
|
@@ -249,27 +271,31 @@ async function loadPdfToStore(file, store, options) {
|
|
|
249
271
|
const mime = "image/png";
|
|
250
272
|
const pageBlob = await canvasToBlob(canvas, mime);
|
|
251
273
|
const blobId = await store.storeOriginal(pageBlob);
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
tCtx
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
274
|
+
const thumbnailBlobId = storeThumbnails ? await (async () => {
|
|
275
|
+
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
276
|
+
const tw = Math.max(1, Math.round(width * thumbScale));
|
|
277
|
+
const th = Math.max(1, Math.round(height * thumbScale));
|
|
278
|
+
const thumbCanvas = document.createElement("canvas");
|
|
279
|
+
thumbCanvas.width = tw;
|
|
280
|
+
thumbCanvas.height = th;
|
|
281
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
282
|
+
if (tCtx) {
|
|
283
|
+
tCtx.imageSmoothingEnabled = true;
|
|
284
|
+
tCtx.imageSmoothingQuality = "high";
|
|
285
|
+
tCtx.drawImage(canvas, 0, 0, tw, th);
|
|
286
|
+
}
|
|
287
|
+
const thumbBlob = await canvasToBlob(thumbCanvas, mime);
|
|
288
|
+
return await store.storeThumbnail(thumbBlob);
|
|
289
|
+
})() : "";
|
|
290
|
+
const pageResult = {
|
|
267
291
|
blobId,
|
|
268
292
|
thumbnailBlobId,
|
|
269
293
|
width,
|
|
270
294
|
height,
|
|
271
295
|
pageNumber
|
|
272
296
|
};
|
|
297
|
+
await queuePageEmission(pageResult);
|
|
298
|
+
return pageResult;
|
|
273
299
|
}
|
|
274
300
|
);
|
|
275
301
|
}
|
|
@@ -1706,7 +1732,8 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
1706
1732
|
var HYDRATION_CACHE_NAME = "canvu-asset-hydration-v1";
|
|
1707
1733
|
var DEFAULT_PDF_SCALE = 1.15;
|
|
1708
1734
|
var DEFAULT_PDF_PAGE_CONCURRENCY = 2;
|
|
1709
|
-
var
|
|
1735
|
+
var hydrationSourcePromises = /* @__PURE__ */ new Map();
|
|
1736
|
+
var pdfSourceBlobPromises = /* @__PURE__ */ new Map();
|
|
1710
1737
|
function buildImageHydrationKey(assetId) {
|
|
1711
1738
|
return `image:${assetId}`;
|
|
1712
1739
|
}
|
|
@@ -1754,23 +1781,38 @@ async function fetchBlob(url) {
|
|
|
1754
1781
|
return null;
|
|
1755
1782
|
}
|
|
1756
1783
|
}
|
|
1757
|
-
async function
|
|
1784
|
+
async function getHydrationSource(key, preferCachedRasters, loader) {
|
|
1758
1785
|
const cached = preferCachedRasters ? await readCachedHydrationBlob(key) : null;
|
|
1759
|
-
if (cached)
|
|
1760
|
-
|
|
1786
|
+
if (cached) {
|
|
1787
|
+
return {
|
|
1788
|
+
blob: cached
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
const inFlight = hydrationSourcePromises.get(key);
|
|
1761
1792
|
if (inFlight) return await inFlight;
|
|
1762
1793
|
const nextPromise = (async () => {
|
|
1763
|
-
const
|
|
1764
|
-
if (blob) {
|
|
1765
|
-
await writeCachedHydrationBlob(key, blob);
|
|
1794
|
+
const source = await loader();
|
|
1795
|
+
if (source?.blob) {
|
|
1796
|
+
await writeCachedHydrationBlob(key, source.blob);
|
|
1766
1797
|
}
|
|
1767
|
-
return
|
|
1798
|
+
return source;
|
|
1768
1799
|
})();
|
|
1769
|
-
|
|
1800
|
+
hydrationSourcePromises.set(key, nextPromise);
|
|
1801
|
+
try {
|
|
1802
|
+
return await nextPromise;
|
|
1803
|
+
} finally {
|
|
1804
|
+
hydrationSourcePromises.delete(key);
|
|
1805
|
+
}
|
|
1806
|
+
}
|
|
1807
|
+
async function getPdfSourceBlob(url) {
|
|
1808
|
+
const inFlight = pdfSourceBlobPromises.get(url);
|
|
1809
|
+
if (inFlight) return await inFlight;
|
|
1810
|
+
const nextPromise = fetchBlob(url);
|
|
1811
|
+
pdfSourceBlobPromises.set(url, nextPromise);
|
|
1770
1812
|
try {
|
|
1771
1813
|
return await nextPromise;
|
|
1772
1814
|
} finally {
|
|
1773
|
-
|
|
1815
|
+
pdfSourceBlobPromises.delete(url);
|
|
1774
1816
|
}
|
|
1775
1817
|
}
|
|
1776
1818
|
function registerObjectUrl(objectUrls, blob) {
|
|
@@ -1824,18 +1866,22 @@ async function hydrateImageAssets(requests, resolvedAssetUrls, objectUrls, prefe
|
|
|
1824
1866
|
if (!resolvedAsset?.url) {
|
|
1825
1867
|
return [assetId, null];
|
|
1826
1868
|
}
|
|
1827
|
-
const
|
|
1869
|
+
const source = await getHydrationSource(
|
|
1828
1870
|
buildImageHydrationKey(assetId),
|
|
1829
1871
|
preferCachedRasters,
|
|
1830
|
-
async () =>
|
|
1872
|
+
async () => {
|
|
1873
|
+
const blob = await fetchBlob(resolvedAsset.url);
|
|
1874
|
+
if (!blob) return null;
|
|
1875
|
+
return { blob };
|
|
1876
|
+
}
|
|
1831
1877
|
);
|
|
1832
|
-
if (!blob) {
|
|
1878
|
+
if (!source?.blob) {
|
|
1833
1879
|
return [assetId, null];
|
|
1834
1880
|
}
|
|
1835
1881
|
return [
|
|
1836
1882
|
assetId,
|
|
1837
1883
|
{
|
|
1838
|
-
href: registerObjectUrl(objectUrls, blob)
|
|
1884
|
+
href: registerObjectUrl(objectUrls, source.blob)
|
|
1839
1885
|
}
|
|
1840
1886
|
];
|
|
1841
1887
|
})
|
|
@@ -1850,45 +1896,69 @@ async function hydratePdfAssets(requests, resolvedAssetUrls, objectUrls, options
|
|
|
1850
1896
|
if (!resolvedAsset?.url) {
|
|
1851
1897
|
continue;
|
|
1852
1898
|
}
|
|
1853
|
-
const
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1899
|
+
const pageKeys = group.pageNumbers.map((pageNumber) => ({
|
|
1900
|
+
pageNumber,
|
|
1901
|
+
cacheKey: buildPdfHydrationKey(group.assetId, pageNumber, group.scale)
|
|
1902
|
+
}));
|
|
1903
|
+
const pagesToRender = [];
|
|
1904
|
+
for (const { pageNumber, cacheKey } of pageKeys) {
|
|
1905
|
+
const cachedBlob = options.preferCachedRasters ? await readCachedHydrationBlob(cacheKey) : null;
|
|
1906
|
+
if (cachedBlob) {
|
|
1907
|
+
hydratedPages.set(cacheKey, {
|
|
1908
|
+
href: registerObjectUrl(objectUrls, cachedBlob)
|
|
1909
|
+
});
|
|
1859
1910
|
continue;
|
|
1860
1911
|
}
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
if (missingPages.length === 0) {
|
|
1866
|
-
continue;
|
|
1912
|
+
if (!hydrationSourcePromises.has(cacheKey)) {
|
|
1913
|
+
pagesToRender.push({ pageNumber, cacheKey });
|
|
1914
|
+
}
|
|
1867
1915
|
}
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1916
|
+
if (pagesToRender.length > 0) {
|
|
1917
|
+
const renderPromise = (async () => {
|
|
1918
|
+
const pdfBlob = await getPdfSourceBlob(resolvedAsset.url);
|
|
1919
|
+
if (!pdfBlob) {
|
|
1920
|
+
return /* @__PURE__ */ new Map();
|
|
1921
|
+
}
|
|
1922
|
+
const renderedPages = await loadPdfToStore(pdfBlob, options.imageStore, {
|
|
1923
|
+
scale: group.scale,
|
|
1924
|
+
pageNumbers: pagesToRender.map(({ pageNumber }) => pageNumber),
|
|
1925
|
+
pageConcurrency: options.pdfPageConcurrency
|
|
1926
|
+
});
|
|
1927
|
+
const renderedByPage = /* @__PURE__ */ new Map();
|
|
1928
|
+
for (const renderedPage of renderedPages) {
|
|
1929
|
+
const pageBlob = await options.imageStore.getOriginal(renderedPage.blobId);
|
|
1930
|
+
renderedByPage.set(
|
|
1931
|
+
renderedPage.pageNumber,
|
|
1932
|
+
pageBlob ? {
|
|
1933
|
+
blob: pageBlob,
|
|
1934
|
+
width: renderedPage.width,
|
|
1935
|
+
height: renderedPage.height
|
|
1936
|
+
} : null
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
return renderedByPage;
|
|
1940
|
+
})();
|
|
1941
|
+
for (const { pageNumber, cacheKey } of pagesToRender) {
|
|
1942
|
+
const pagePromise = getHydrationSource(
|
|
1943
|
+
cacheKey,
|
|
1944
|
+
options.preferCachedRasters,
|
|
1945
|
+
async () => (await renderPromise).get(pageNumber) ?? null
|
|
1946
|
+
);
|
|
1947
|
+
hydrationSourcePromises.set(cacheKey, pagePromise);
|
|
1948
|
+
}
|
|
1871
1949
|
}
|
|
1872
|
-
const
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
const cacheKey = buildPdfHydrationKey(
|
|
1879
|
-
group.assetId,
|
|
1880
|
-
renderedPage.pageNumber,
|
|
1881
|
-
group.scale
|
|
1950
|
+
for (const { cacheKey } of pageKeys) {
|
|
1951
|
+
if (hydratedPages.has(cacheKey)) continue;
|
|
1952
|
+
const source = await getHydrationSource(
|
|
1953
|
+
cacheKey,
|
|
1954
|
+
options.preferCachedRasters,
|
|
1955
|
+
async () => null
|
|
1882
1956
|
);
|
|
1883
|
-
|
|
1884
|
-
if (!pageBlob) {
|
|
1885
|
-
continue;
|
|
1886
|
-
}
|
|
1887
|
-
await writeCachedHydrationBlob(cacheKey, pageBlob);
|
|
1957
|
+
if (!source?.blob) continue;
|
|
1888
1958
|
hydratedPages.set(cacheKey, {
|
|
1889
|
-
href: registerObjectUrl(objectUrls,
|
|
1890
|
-
width:
|
|
1891
|
-
height:
|
|
1959
|
+
href: registerObjectUrl(objectUrls, source.blob),
|
|
1960
|
+
width: source.width,
|
|
1961
|
+
height: source.height
|
|
1892
1962
|
});
|
|
1893
1963
|
}
|
|
1894
1964
|
}
|
|
@@ -1929,7 +1999,9 @@ async function hydrateSceneItemsWithAssets(items, assetStore, options = {}) {
|
|
|
1929
1999
|
objectUrls,
|
|
1930
2000
|
{
|
|
1931
2001
|
imageStore,
|
|
1932
|
-
pdfPageConcurrency
|
|
2002
|
+
pdfPageConcurrency,
|
|
2003
|
+
preferCachedRasters
|
|
2004
|
+
}
|
|
1933
2005
|
);
|
|
1934
2006
|
return {
|
|
1935
2007
|
items: items.map((item) => {
|