canvu-react 0.3.10 → 0.3.12

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.
@@ -0,0 +1,27 @@
1
+ import { V as VectorSceneItem } from './types-CB0TZZuk.cjs';
2
+ import { u as VectorViewportAssetStore } from './shape-builders-DFudWDFI.cjs';
3
+
4
+ declare class IndexedDbImageStore {
5
+ private dbPromise;
6
+ private getDb;
7
+ storeOriginal(blob: Blob): Promise<string>;
8
+ getOriginal(id: string): Promise<Blob | undefined>;
9
+ deleteOriginal(id: string): Promise<void>;
10
+ storeThumbnail(blob: Blob): Promise<string>;
11
+ getThumbnail(id: string): Promise<Blob | undefined>;
12
+ deleteThumbnail(id: string): Promise<void>;
13
+ }
14
+
15
+ type HydrateSceneItemsWithAssetsOptions = {
16
+ imageStore?: IndexedDbImageStore;
17
+ pdfScale?: number;
18
+ pdfPageConcurrency?: number;
19
+ preferCachedRasters?: boolean;
20
+ };
21
+ type HydratedSceneItemsWithAssetsResult = {
22
+ items: VectorSceneItem[];
23
+ objectUrls: string[];
24
+ };
25
+ declare function hydrateSceneItemsWithAssets(items: readonly VectorSceneItem[], assetStore: VectorViewportAssetStore, options?: HydrateSceneItemsWithAssetsOptions): Promise<HydratedSceneItemsWithAssetsResult>;
26
+
27
+ export { type HydratedSceneItemsWithAssetsResult as H, IndexedDbImageStore as I, hydrateSceneItemsWithAssets as h };
@@ -0,0 +1,27 @@
1
+ import { V as VectorSceneItem } from './types-CB0TZZuk.js';
2
+ import { u as VectorViewportAssetStore } from './shape-builders-ENwnK-zT.js';
3
+
4
+ declare class IndexedDbImageStore {
5
+ private dbPromise;
6
+ private getDb;
7
+ storeOriginal(blob: Blob): Promise<string>;
8
+ getOriginal(id: string): Promise<Blob | undefined>;
9
+ deleteOriginal(id: string): Promise<void>;
10
+ storeThumbnail(blob: Blob): Promise<string>;
11
+ getThumbnail(id: string): Promise<Blob | undefined>;
12
+ deleteThumbnail(id: string): Promise<void>;
13
+ }
14
+
15
+ type HydrateSceneItemsWithAssetsOptions = {
16
+ imageStore?: IndexedDbImageStore;
17
+ pdfScale?: number;
18
+ pdfPageConcurrency?: number;
19
+ preferCachedRasters?: boolean;
20
+ };
21
+ type HydratedSceneItemsWithAssetsResult = {
22
+ items: VectorSceneItem[];
23
+ objectUrls: string[];
24
+ };
25
+ declare function hydrateSceneItemsWithAssets(items: readonly VectorSceneItem[], assetStore: VectorViewportAssetStore, options?: HydrateSceneItemsWithAssetsOptions): Promise<HydratedSceneItemsWithAssetsResult>;
26
+
27
+ export { type HydratedSceneItemsWithAssetsResult as H, IndexedDbImageStore as I, hydrateSceneItemsWithAssets as h };
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { C as CanvasPlugin } from './types-BtLGGw0r.cjs';
2
+ import { C as CanvasPlugin } from './types-CTyASYIm.cjs';
3
3
  import 'react';
4
4
  import './types-CB0TZZuk.cjs';
5
5
  import './camera-BwQjm5oh.cjs';
6
- import './shape-builders-DxPoOecg.cjs';
6
+ import './shape-builders-DFudWDFI.cjs';
7
7
 
8
8
  type ChatbotPluginPanelProps = {
9
9
  /**
package/dist/chatbot.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { C as CanvasPlugin } from './types-ChnTSRSe.js';
2
+ import { C as CanvasPlugin } from './types-UvUy2Eed.js';
3
3
  import 'react';
4
4
  import './types-CB0TZZuk.js';
5
5
  import './camera-KwCYYPhm.js';
6
- import './shape-builders-DTYvub8W.js';
6
+ import './shape-builders-ENwnK-zT.js';
7
7
 
8
8
  type ChatbotPluginPanelProps = {
9
9
  /**
package/dist/index.cjs CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  var getStroke = require('perfect-freehand');
4
4
 
5
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
5
6
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
7
 
7
8
  var getStroke__default = /*#__PURE__*/_interopDefault(getStroke);
@@ -84,6 +85,202 @@ var Camera2D = class {
84
85
  }
85
86
  };
86
87
 
88
+ // src/image/indexed-db-image-store.ts
89
+ var DB_NAME = "canvu-image-store";
90
+ var DB_VERSION = 1;
91
+ function openDb() {
92
+ return new Promise((resolve, reject) => {
93
+ const req = indexedDB.open(DB_NAME, DB_VERSION);
94
+ req.onupgradeneeded = () => {
95
+ const db = req.result;
96
+ if (!db.objectStoreNames.contains("images")) {
97
+ db.createObjectStore("images");
98
+ }
99
+ if (!db.objectStoreNames.contains("thumbnails")) {
100
+ db.createObjectStore("thumbnails");
101
+ }
102
+ };
103
+ req.onsuccess = () => resolve(req.result);
104
+ req.onerror = () => reject(req.error);
105
+ });
106
+ }
107
+ function getFromStore(db, storeName, id) {
108
+ return new Promise((resolve, reject) => {
109
+ const tx = db.transaction(storeName, "readonly");
110
+ const req = tx.objectStore(storeName).get(id);
111
+ req.onsuccess = () => resolve(req.result ?? void 0);
112
+ req.onerror = () => reject(req.error);
113
+ });
114
+ }
115
+ function putInStore(db, storeName, id, blob) {
116
+ return new Promise((resolve, reject) => {
117
+ const tx = db.transaction(storeName, "readwrite");
118
+ const req = tx.objectStore(storeName).put(blob, id);
119
+ req.onsuccess = () => resolve();
120
+ req.onerror = () => reject(req.error);
121
+ });
122
+ }
123
+ function deleteFromStore(db, storeName, id) {
124
+ return new Promise((resolve, reject) => {
125
+ const tx = db.transaction(storeName, "readwrite");
126
+ const req = tx.objectStore(storeName).delete(id);
127
+ req.onsuccess = () => resolve();
128
+ req.onerror = () => reject(req.error);
129
+ });
130
+ }
131
+ function generateBlobId() {
132
+ return crypto.randomUUID();
133
+ }
134
+ var IndexedDbImageStore = class {
135
+ dbPromise = null;
136
+ getDb() {
137
+ if (!this.dbPromise) {
138
+ this.dbPromise = openDb();
139
+ }
140
+ return this.dbPromise;
141
+ }
142
+ async storeOriginal(blob) {
143
+ const id = generateBlobId();
144
+ const db = await this.getDb();
145
+ await putInStore(db, "images", id, blob);
146
+ return id;
147
+ }
148
+ async getOriginal(id) {
149
+ const db = await this.getDb();
150
+ return getFromStore(db, "images", id);
151
+ }
152
+ async deleteOriginal(id) {
153
+ const db = await this.getDb();
154
+ await deleteFromStore(db, "images", id);
155
+ }
156
+ async storeThumbnail(blob) {
157
+ const id = generateBlobId();
158
+ const db = await this.getDb();
159
+ await putInStore(db, "thumbnails", id, blob);
160
+ return id;
161
+ }
162
+ async getThumbnail(id) {
163
+ const db = await this.getDb();
164
+ return getFromStore(db, "thumbnails", id);
165
+ }
166
+ async deleteThumbnail(id) {
167
+ const db = await this.getDb();
168
+ await deleteFromStore(db, "thumbnails", id);
169
+ }
170
+ };
171
+
172
+ // src/image/pdf-loader.ts
173
+ var pdfjsPromise = null;
174
+ function getPdfJs() {
175
+ if (!pdfjsPromise) {
176
+ pdfjsPromise = import('pdfjs-dist').then((mod) => {
177
+ const workerSrc = new URL(
178
+ "pdfjs-dist/build/pdf.worker.min.mjs",
179
+ (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))
180
+ ).toString();
181
+ mod.GlobalWorkerOptions.workerSrc = workerSrc;
182
+ return mod;
183
+ });
184
+ }
185
+ return pdfjsPromise;
186
+ }
187
+ async function renderPageToCanvas(page, scale) {
188
+ const raw = page.getViewport({ scale: 1 });
189
+ const adjustedScale = Math.round(raw.width * scale) / raw.width;
190
+ const viewport = page.getViewport({ scale: adjustedScale });
191
+ const w = Math.round(viewport.width);
192
+ const h = Math.round(viewport.height);
193
+ const canvas = document.createElement("canvas");
194
+ canvas.width = w;
195
+ canvas.height = h;
196
+ const ctx = canvas.getContext("2d");
197
+ if (!ctx) throw new Error("Canvas 2D context unavailable");
198
+ ctx.imageSmoothingEnabled = true;
199
+ ctx.imageSmoothingQuality = "high";
200
+ await page.render({ canvas, viewport }).promise;
201
+ return { canvas, width: w, height: h };
202
+ }
203
+ function canvasToBlob(canvas, mime, quality) {
204
+ return new Promise((resolve, reject) => {
205
+ canvas.toBlob(
206
+ (blob) => {
207
+ if (!blob) {
208
+ reject(new Error("Could not encode blob"));
209
+ return;
210
+ }
211
+ resolve(blob);
212
+ },
213
+ mime,
214
+ quality
215
+ );
216
+ });
217
+ }
218
+ function normalizePdfPageNumbers(pageNumbers, pageCount) {
219
+ if (!pageNumbers || pageNumbers.length === 0) {
220
+ return Array.from({ length: pageCount }, (_, index) => index + 1);
221
+ }
222
+ return [...new Set(pageNumbers)].filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount).sort((left, right) => left - right);
223
+ }
224
+ async function runWithConcurrency(items, concurrency, execute) {
225
+ const results = new Array(items.length);
226
+ let nextIndex = 0;
227
+ const workerCount = Math.max(1, Math.min(concurrency, items.length));
228
+ await Promise.all(
229
+ Array.from({ length: workerCount }, async () => {
230
+ while (nextIndex < items.length) {
231
+ const currentIndex = nextIndex;
232
+ nextIndex += 1;
233
+ const item = items[currentIndex];
234
+ if (item === void 0) {
235
+ continue;
236
+ }
237
+ results[currentIndex] = await execute(item);
238
+ }
239
+ })
240
+ );
241
+ return results;
242
+ }
243
+ async function loadPdfToStore(file, store, options) {
244
+ const scale = options?.scale ?? 1.5;
245
+ const pageConcurrency = options?.pageConcurrency ?? 2;
246
+ const pdfjs = await getPdfJs();
247
+ const arrayBuffer = await file.arrayBuffer();
248
+ const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
249
+ const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
250
+ return await runWithConcurrency(
251
+ pageNumbers,
252
+ pageConcurrency,
253
+ async (pageNumber) => {
254
+ const page = await pdf.getPage(pageNumber);
255
+ const { canvas, width, height } = await renderPageToCanvas(page, scale);
256
+ const mime = "image/png";
257
+ const pageBlob = await canvasToBlob(canvas, mime);
258
+ 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 {
274
+ blobId,
275
+ thumbnailBlobId,
276
+ width,
277
+ height,
278
+ pageNumber
279
+ };
280
+ }
281
+ );
282
+ }
283
+
87
284
  // src/image/raster-image.ts
88
285
  var MAX_RASTER_EMBED_DIMENSION = 4096;
89
286
  function normalizeLoadOptions(maxDimensionOrOptions) {
@@ -1468,16 +1665,14 @@ function itemHitTestWorldPoint(item, worldX, worldY, options) {
1468
1665
  return true;
1469
1666
  }
1470
1667
  }
1668
+ return false;
1471
1669
  }
1472
- if (pts?.length === 1) {
1670
+ if (pts && pts.length === 1) {
1473
1671
  const p = pts[0];
1474
- if (p) {
1475
- const cw = itemLocalToWorld(p.x, p.y, item.x, item.y, w, h, rot);
1476
- const dsq = (worldX - cw.x) ** 2 + (worldY - cw.y) ** 2;
1477
- if (dsq <= tolSq) {
1478
- return true;
1479
- }
1480
- }
1672
+ if (!p) return false;
1673
+ const cw = itemLocalToWorld(p.x, p.y, item.x, item.y, w, h, rot);
1674
+ const dsq = (worldX - cw.x) ** 2 + (worldY - cw.y) ** 2;
1675
+ return dsq <= tolSq;
1481
1676
  }
1482
1677
  return hitTestFilledShape(item, worldX, worldY);
1483
1678
  }
@@ -1514,6 +1709,271 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
1514
1709
  return ids;
1515
1710
  }
1516
1711
 
1712
+ // src/react/asset-hydration.ts
1713
+ var HYDRATION_CACHE_NAME = "canvu-asset-hydration-v1";
1714
+ var DEFAULT_PDF_SCALE = 1.15;
1715
+ var DEFAULT_PDF_PAGE_CONCURRENCY = 2;
1716
+ var hydrationBlobPromises = /* @__PURE__ */ new Map();
1717
+ function buildImageHydrationKey(assetId) {
1718
+ return `image:${assetId}`;
1719
+ }
1720
+ function buildPdfHydrationKey(assetId, pageNumber, scale) {
1721
+ return `pdf:${assetId}:page:${pageNumber}:scale:${scale}`;
1722
+ }
1723
+ function getCacheRequest(key) {
1724
+ return new Request(
1725
+ `https://canvu.local/asset-hydration/${encodeURIComponent(key)}`
1726
+ );
1727
+ }
1728
+ async function openHydrationCache() {
1729
+ if (typeof caches === "undefined") return null;
1730
+ try {
1731
+ return await caches.open(HYDRATION_CACHE_NAME);
1732
+ } catch {
1733
+ return null;
1734
+ }
1735
+ }
1736
+ async function readCachedHydrationBlob(key) {
1737
+ const cache = await openHydrationCache();
1738
+ if (!cache) return null;
1739
+ try {
1740
+ const response = await cache.match(getCacheRequest(key));
1741
+ if (!response?.ok) return null;
1742
+ return await response.blob();
1743
+ } catch {
1744
+ return null;
1745
+ }
1746
+ }
1747
+ async function writeCachedHydrationBlob(key, blob) {
1748
+ const cache = await openHydrationCache();
1749
+ if (!cache) return;
1750
+ try {
1751
+ await cache.put(getCacheRequest(key), new Response(blob));
1752
+ } catch {
1753
+ }
1754
+ }
1755
+ async function fetchBlob(url) {
1756
+ try {
1757
+ const response = await fetch(url);
1758
+ if (!response.ok) return null;
1759
+ return await response.blob();
1760
+ } catch {
1761
+ return null;
1762
+ }
1763
+ }
1764
+ async function getHydrationBlob(key, preferCachedRasters, loader) {
1765
+ const cached = preferCachedRasters ? await readCachedHydrationBlob(key) : null;
1766
+ if (cached) return cached;
1767
+ const inFlight = hydrationBlobPromises.get(key);
1768
+ if (inFlight) return await inFlight;
1769
+ const nextPromise = (async () => {
1770
+ const blob = await loader();
1771
+ if (blob) {
1772
+ await writeCachedHydrationBlob(key, blob);
1773
+ }
1774
+ return blob;
1775
+ })();
1776
+ hydrationBlobPromises.set(key, nextPromise);
1777
+ try {
1778
+ return await nextPromise;
1779
+ } finally {
1780
+ hydrationBlobPromises.delete(key);
1781
+ }
1782
+ }
1783
+ function registerObjectUrl(objectUrls, blob) {
1784
+ const href = URL.createObjectURL(blob);
1785
+ objectUrls.push(href);
1786
+ return href;
1787
+ }
1788
+ function getHydrationRequests(items, assetStore, pdfScale) {
1789
+ if (!assetStore.getHydrationRequest) return [];
1790
+ return items.flatMap((item) => {
1791
+ const request = assetStore.getHydrationRequest?.(item);
1792
+ if (!request) return [];
1793
+ return [
1794
+ {
1795
+ request: {
1796
+ ...request,
1797
+ scale: request.scale ?? pdfScale
1798
+ }
1799
+ }
1800
+ ];
1801
+ });
1802
+ }
1803
+ function createPdfHydrationGroups(requests) {
1804
+ const groups = /* @__PURE__ */ new Map();
1805
+ for (const entry of requests) {
1806
+ if (entry.request.kind !== "pdf" || entry.request.pageNumber == null) continue;
1807
+ const scale = entry.request.scale ?? DEFAULT_PDF_SCALE;
1808
+ const key = `${entry.request.assetId}:${scale}`;
1809
+ const existingGroup = groups.get(key);
1810
+ if (existingGroup) {
1811
+ if (!existingGroup.pageNumbers.includes(entry.request.pageNumber)) {
1812
+ existingGroup.pageNumbers.push(entry.request.pageNumber);
1813
+ }
1814
+ continue;
1815
+ }
1816
+ groups.set(key, {
1817
+ assetId: entry.request.assetId,
1818
+ scale,
1819
+ pageNumbers: [entry.request.pageNumber]
1820
+ });
1821
+ }
1822
+ return [...groups.values()];
1823
+ }
1824
+ async function hydrateImageAssets(requests, resolvedAssetUrls, objectUrls, preferCachedRasters) {
1825
+ const uniqueAssetIds = [
1826
+ ...new Set(requests.map((entry) => entry.request.assetId))
1827
+ ];
1828
+ const hydratedEntries = await Promise.all(
1829
+ uniqueAssetIds.map(async (assetId) => {
1830
+ const resolvedAsset = resolvedAssetUrls[assetId];
1831
+ if (!resolvedAsset?.url) {
1832
+ return [assetId, null];
1833
+ }
1834
+ const blob = await getHydrationBlob(
1835
+ buildImageHydrationKey(assetId),
1836
+ preferCachedRasters,
1837
+ async () => await fetchBlob(resolvedAsset.url)
1838
+ );
1839
+ if (!blob) {
1840
+ return [assetId, null];
1841
+ }
1842
+ return [
1843
+ assetId,
1844
+ {
1845
+ href: registerObjectUrl(objectUrls, blob)
1846
+ }
1847
+ ];
1848
+ })
1849
+ );
1850
+ return new Map(hydratedEntries);
1851
+ }
1852
+ async function hydratePdfAssets(requests, resolvedAssetUrls, objectUrls, options) {
1853
+ const hydratedPages = /* @__PURE__ */ new Map();
1854
+ const groups = createPdfHydrationGroups(requests);
1855
+ for (const group of groups) {
1856
+ const resolvedAsset = resolvedAssetUrls[group.assetId];
1857
+ if (!resolvedAsset?.url) {
1858
+ continue;
1859
+ }
1860
+ const missingPages = [];
1861
+ for (const pageNumber of group.pageNumbers) {
1862
+ const cacheKey = buildPdfHydrationKey(group.assetId, pageNumber, group.scale);
1863
+ const cachedBlob = await readCachedHydrationBlob(cacheKey);
1864
+ if (!cachedBlob) {
1865
+ missingPages.push(pageNumber);
1866
+ continue;
1867
+ }
1868
+ hydratedPages.set(cacheKey, {
1869
+ href: registerObjectUrl(objectUrls, cachedBlob)
1870
+ });
1871
+ }
1872
+ if (missingPages.length === 0) {
1873
+ continue;
1874
+ }
1875
+ const pdfBlob = await fetchBlob(resolvedAsset.url);
1876
+ if (!pdfBlob) {
1877
+ continue;
1878
+ }
1879
+ const renderedPages = await loadPdfToStore(pdfBlob, options.imageStore, {
1880
+ scale: group.scale,
1881
+ pageNumbers: missingPages,
1882
+ pageConcurrency: options.pdfPageConcurrency
1883
+ });
1884
+ for (const renderedPage of renderedPages) {
1885
+ const cacheKey = buildPdfHydrationKey(
1886
+ group.assetId,
1887
+ renderedPage.pageNumber,
1888
+ group.scale
1889
+ );
1890
+ const pageBlob = await options.imageStore.getOriginal(renderedPage.blobId);
1891
+ if (!pageBlob) {
1892
+ continue;
1893
+ }
1894
+ await writeCachedHydrationBlob(cacheKey, pageBlob);
1895
+ hydratedPages.set(cacheKey, {
1896
+ href: registerObjectUrl(objectUrls, pageBlob),
1897
+ width: renderedPage.width,
1898
+ height: renderedPage.height
1899
+ });
1900
+ }
1901
+ }
1902
+ return hydratedPages;
1903
+ }
1904
+ async function hydrateSceneItemsWithAssets(items, assetStore, options = {}) {
1905
+ if (!assetStore.resolve || !assetStore.getHydrationRequest) {
1906
+ return {
1907
+ items: [...items],
1908
+ objectUrls: []
1909
+ };
1910
+ }
1911
+ const pdfScale = options.pdfScale ?? DEFAULT_PDF_SCALE;
1912
+ const pdfPageConcurrency = options.pdfPageConcurrency ?? DEFAULT_PDF_PAGE_CONCURRENCY;
1913
+ const preferCachedRasters = options.preferCachedRasters ?? true;
1914
+ const imageStore = options.imageStore ?? new IndexedDbImageStore();
1915
+ const hydrationRequests = getHydrationRequests(items, assetStore, pdfScale);
1916
+ if (hydrationRequests.length === 0) {
1917
+ return {
1918
+ items: [...items],
1919
+ objectUrls: []
1920
+ };
1921
+ }
1922
+ const assetIds = [
1923
+ ...new Set(hydrationRequests.map((entry) => entry.request.assetId))
1924
+ ];
1925
+ const resolvedAssetUrls = await assetStore.resolve({ assetIds });
1926
+ const objectUrls = [];
1927
+ const hydratedImages = await hydrateImageAssets(
1928
+ hydrationRequests.filter((entry) => entry.request.kind === "image"),
1929
+ resolvedAssetUrls,
1930
+ objectUrls,
1931
+ preferCachedRasters
1932
+ );
1933
+ const hydratedPdfPages = await hydratePdfAssets(
1934
+ hydrationRequests.filter((entry) => entry.request.kind === "pdf"),
1935
+ resolvedAssetUrls,
1936
+ objectUrls,
1937
+ {
1938
+ imageStore,
1939
+ pdfPageConcurrency}
1940
+ );
1941
+ return {
1942
+ items: items.map((item) => {
1943
+ const request = assetStore.getHydrationRequest?.(item);
1944
+ if (!request || item.toolKind !== "image") return item;
1945
+ if (request.kind === "image") {
1946
+ const hydratedImage = hydratedImages.get(request.assetId);
1947
+ if (!hydratedImage) return item;
1948
+ return rebuildItemSvg({
1949
+ ...item,
1950
+ imageRasterHref: hydratedImage.href,
1951
+ imageThumbnailHref: hydratedImage.href
1952
+ });
1953
+ }
1954
+ if (request.pageNumber == null) return item;
1955
+ const hydratedPdfPage = hydratedPdfPages.get(
1956
+ buildPdfHydrationKey(
1957
+ request.assetId,
1958
+ request.pageNumber,
1959
+ request.scale ?? pdfScale
1960
+ )
1961
+ );
1962
+ if (!hydratedPdfPage) return item;
1963
+ return rebuildItemSvg({
1964
+ ...item,
1965
+ imageRasterHref: hydratedPdfPage.href,
1966
+ imageThumbnailHref: hydratedPdfPage.href,
1967
+ imageIntrinsicSize: {
1968
+ width: item.imageIntrinsicSize?.width ?? Math.max(1, Math.round(hydratedPdfPage.width ?? item.bounds.width)),
1969
+ height: item.imageIntrinsicSize?.height ?? Math.max(1, Math.round(hydratedPdfPage.height ?? item.bounds.height))
1970
+ }
1971
+ });
1972
+ }),
1973
+ objectUrls
1974
+ };
1975
+ }
1976
+
1517
1977
  // src/scene/spatial-cull.ts
1518
1978
  var spatialIndexCache = /* @__PURE__ */ new WeakMap();
1519
1979
  function cellKey(ix, iy) {
@@ -1794,6 +2254,7 @@ exports.expandCustomShapeTemplate = expandCustomShapeTemplate;
1794
2254
  exports.formatCameraTransform = formatCameraTransform;
1795
2255
  exports.formatItemPlacementTransform = formatItemPlacementTransform;
1796
2256
  exports.hitTestWorldPoint = hitTestWorldPoint;
2257
+ exports.hydrateSceneItemsWithAssets = hydrateSceneItemsWithAssets;
1797
2258
  exports.isArrowBindTarget = isArrowBindTarget;
1798
2259
  exports.itemHitTestWorldPoint = itemHitTestWorldPoint;
1799
2260
  exports.lineEndpointsToLocal = lineEndpointsToLocal;