canvu-react 0.3.9 → 0.3.11
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/asset-hydration-3Iv5xHxM.d.cts +27 -0
- package/dist/asset-hydration-BEG21hMp.d.ts +27 -0
- package/dist/chatbot.d.cts +2 -2
- package/dist/chatbot.d.ts +2 -2
- package/dist/index.cjs +469 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +468 -9
- package/dist/index.js.map +1 -1
- package/dist/native.cjs +645 -704
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +645 -704
- package/dist/native.js.map +1 -1
- package/dist/react.cjs +358 -141
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +9 -16
- package/dist/react.d.ts +9 -16
- package/dist/react.js +358 -142
- package/dist/react.js.map +1 -1
- package/dist/realtime.cjs +541 -38
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +40 -5
- package/dist/realtime.d.ts +40 -5
- package/dist/realtime.js +541 -39
- package/dist/realtime.js.map +1 -1
- package/dist/{shape-builders-DxPoOecg.d.cts → shape-builders-DFudWDFI.d.cts} +111 -1
- package/dist/{shape-builders-DTYvub8W.d.ts → shape-builders-ENwnK-zT.d.ts} +111 -1
- package/dist/{types-DgEArHkA.d.ts → types-BtAJFS_-.d.ts} +1 -0
- package/dist/{types-BtLGGw0r.d.cts → types-CTyASYIm.d.cts} +2 -105
- package/dist/{types-B58i5k-u.d.cts → types-DNwjgs5U.d.cts} +1 -0
- package/dist/{types-ChnTSRSe.d.ts → types-UvUy2Eed.d.ts} +2 -105
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -2,7 +2,8 @@ import { C as Camera2D } from './camera-BwQjm5oh.cjs';
|
|
|
2
2
|
export { a as Camera2DOptions } from './camera-BwQjm5oh.cjs';
|
|
3
3
|
import { V as VectorSceneItem, A as ArrowEndpointBinding, R as Rect } from './types-CB0TZZuk.cjs';
|
|
4
4
|
export { a as ArrowBindings, b as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-CB0TZZuk.cjs';
|
|
5
|
-
export {
|
|
5
|
+
export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-3Iv5xHxM.cjs';
|
|
6
|
+
export { D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, a as applyStrokeToItem, b as buildArrowSvg, c as buildDrawDotSvg, d as buildEllipseSvg, e as buildFreehandPathSvg, f as buildLineSvg, g as buildRectSvg, h as computeFreehandSvgPayload, i as createDrawDotItem, j as createEllipseItem, k as createFreehandStrokeItem, l as createImageFromVectorTrace, m as createImageItem, n as createLineItem, o as createRectangleItem, p as createShapeId, q as createTextItem, r as lineEndpointsToLocal, s as rebuildItemSvg, t as resolveStrokeStyle } from './shape-builders-DFudWDFI.cjs';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Embeds the bitmap as a single SVG `<image>` (data URL or blob URL) instead of tracing paths.
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { C as Camera2D } from './camera-KwCYYPhm.js';
|
|
|
2
2
|
export { a as Camera2DOptions } from './camera-KwCYYPhm.js';
|
|
3
3
|
import { V as VectorSceneItem, A as ArrowEndpointBinding, R as Rect } from './types-CB0TZZuk.js';
|
|
4
4
|
export { a as ArrowBindings, b as VectorPathPoint, n as normalizeRect, r as rectsIntersect } from './types-CB0TZZuk.js';
|
|
5
|
-
export {
|
|
5
|
+
export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAssets } from './asset-hydration-BEG21hMp.js';
|
|
6
|
+
export { D as DEFAULT_STROKE_STYLE, F as FreehandSvgPayload, S as StrokeStyle, a as applyStrokeToItem, b as buildArrowSvg, c as buildDrawDotSvg, d as buildEllipseSvg, e as buildFreehandPathSvg, f as buildLineSvg, g as buildRectSvg, h as computeFreehandSvgPayload, i as createDrawDotItem, j as createEllipseItem, k as createFreehandStrokeItem, l as createImageFromVectorTrace, m as createImageItem, n as createLineItem, o as createRectangleItem, p as createShapeId, q as createTextItem, r as lineEndpointsToLocal, s as rebuildItemSvg, t as resolveStrokeStyle } from './shape-builders-ENwnK-zT.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Embeds the bitmap as a single SVG `<image>` (data URL or blob URL) instead of tracing paths.
|
package/dist/index.js
CHANGED
|
@@ -78,6 +78,202 @@ var Camera2D = class {
|
|
|
78
78
|
}
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
+
// src/image/indexed-db-image-store.ts
|
|
82
|
+
var DB_NAME = "canvu-image-store";
|
|
83
|
+
var DB_VERSION = 1;
|
|
84
|
+
function openDb() {
|
|
85
|
+
return new Promise((resolve, reject) => {
|
|
86
|
+
const req = indexedDB.open(DB_NAME, DB_VERSION);
|
|
87
|
+
req.onupgradeneeded = () => {
|
|
88
|
+
const db = req.result;
|
|
89
|
+
if (!db.objectStoreNames.contains("images")) {
|
|
90
|
+
db.createObjectStore("images");
|
|
91
|
+
}
|
|
92
|
+
if (!db.objectStoreNames.contains("thumbnails")) {
|
|
93
|
+
db.createObjectStore("thumbnails");
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
req.onsuccess = () => resolve(req.result);
|
|
97
|
+
req.onerror = () => reject(req.error);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function getFromStore(db, storeName, id) {
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const tx = db.transaction(storeName, "readonly");
|
|
103
|
+
const req = tx.objectStore(storeName).get(id);
|
|
104
|
+
req.onsuccess = () => resolve(req.result ?? void 0);
|
|
105
|
+
req.onerror = () => reject(req.error);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
function putInStore(db, storeName, id, blob) {
|
|
109
|
+
return new Promise((resolve, reject) => {
|
|
110
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
111
|
+
const req = tx.objectStore(storeName).put(blob, id);
|
|
112
|
+
req.onsuccess = () => resolve();
|
|
113
|
+
req.onerror = () => reject(req.error);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
function deleteFromStore(db, storeName, id) {
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
const tx = db.transaction(storeName, "readwrite");
|
|
119
|
+
const req = tx.objectStore(storeName).delete(id);
|
|
120
|
+
req.onsuccess = () => resolve();
|
|
121
|
+
req.onerror = () => reject(req.error);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function generateBlobId() {
|
|
125
|
+
return crypto.randomUUID();
|
|
126
|
+
}
|
|
127
|
+
var IndexedDbImageStore = class {
|
|
128
|
+
dbPromise = null;
|
|
129
|
+
getDb() {
|
|
130
|
+
if (!this.dbPromise) {
|
|
131
|
+
this.dbPromise = openDb();
|
|
132
|
+
}
|
|
133
|
+
return this.dbPromise;
|
|
134
|
+
}
|
|
135
|
+
async storeOriginal(blob) {
|
|
136
|
+
const id = generateBlobId();
|
|
137
|
+
const db = await this.getDb();
|
|
138
|
+
await putInStore(db, "images", id, blob);
|
|
139
|
+
return id;
|
|
140
|
+
}
|
|
141
|
+
async getOriginal(id) {
|
|
142
|
+
const db = await this.getDb();
|
|
143
|
+
return getFromStore(db, "images", id);
|
|
144
|
+
}
|
|
145
|
+
async deleteOriginal(id) {
|
|
146
|
+
const db = await this.getDb();
|
|
147
|
+
await deleteFromStore(db, "images", id);
|
|
148
|
+
}
|
|
149
|
+
async storeThumbnail(blob) {
|
|
150
|
+
const id = generateBlobId();
|
|
151
|
+
const db = await this.getDb();
|
|
152
|
+
await putInStore(db, "thumbnails", id, blob);
|
|
153
|
+
return id;
|
|
154
|
+
}
|
|
155
|
+
async getThumbnail(id) {
|
|
156
|
+
const db = await this.getDb();
|
|
157
|
+
return getFromStore(db, "thumbnails", id);
|
|
158
|
+
}
|
|
159
|
+
async deleteThumbnail(id) {
|
|
160
|
+
const db = await this.getDb();
|
|
161
|
+
await deleteFromStore(db, "thumbnails", id);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// src/image/pdf-loader.ts
|
|
166
|
+
var pdfjsPromise = null;
|
|
167
|
+
function getPdfJs() {
|
|
168
|
+
if (!pdfjsPromise) {
|
|
169
|
+
pdfjsPromise = import('pdfjs-dist').then((mod) => {
|
|
170
|
+
const workerSrc = new URL(
|
|
171
|
+
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
172
|
+
import.meta.url
|
|
173
|
+
).toString();
|
|
174
|
+
mod.GlobalWorkerOptions.workerSrc = workerSrc;
|
|
175
|
+
return mod;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return pdfjsPromise;
|
|
179
|
+
}
|
|
180
|
+
async function renderPageToCanvas(page, scale) {
|
|
181
|
+
const raw = page.getViewport({ scale: 1 });
|
|
182
|
+
const adjustedScale = Math.round(raw.width * scale) / raw.width;
|
|
183
|
+
const viewport = page.getViewport({ scale: adjustedScale });
|
|
184
|
+
const w = Math.round(viewport.width);
|
|
185
|
+
const h = Math.round(viewport.height);
|
|
186
|
+
const canvas = document.createElement("canvas");
|
|
187
|
+
canvas.width = w;
|
|
188
|
+
canvas.height = h;
|
|
189
|
+
const ctx = canvas.getContext("2d");
|
|
190
|
+
if (!ctx) throw new Error("Canvas 2D context unavailable");
|
|
191
|
+
ctx.imageSmoothingEnabled = true;
|
|
192
|
+
ctx.imageSmoothingQuality = "high";
|
|
193
|
+
await page.render({ canvas, viewport }).promise;
|
|
194
|
+
return { canvas, width: w, height: h };
|
|
195
|
+
}
|
|
196
|
+
function canvasToBlob(canvas, mime, quality) {
|
|
197
|
+
return new Promise((resolve, reject) => {
|
|
198
|
+
canvas.toBlob(
|
|
199
|
+
(blob) => {
|
|
200
|
+
if (!blob) {
|
|
201
|
+
reject(new Error("Could not encode blob"));
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
resolve(blob);
|
|
205
|
+
},
|
|
206
|
+
mime,
|
|
207
|
+
quality
|
|
208
|
+
);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
function normalizePdfPageNumbers(pageNumbers, pageCount) {
|
|
212
|
+
if (!pageNumbers || pageNumbers.length === 0) {
|
|
213
|
+
return Array.from({ length: pageCount }, (_, index) => index + 1);
|
|
214
|
+
}
|
|
215
|
+
return [...new Set(pageNumbers)].filter((pageNumber) => pageNumber >= 1 && pageNumber <= pageCount).sort((left, right) => left - right);
|
|
216
|
+
}
|
|
217
|
+
async function runWithConcurrency(items, concurrency, execute) {
|
|
218
|
+
const results = new Array(items.length);
|
|
219
|
+
let nextIndex = 0;
|
|
220
|
+
const workerCount = Math.max(1, Math.min(concurrency, items.length));
|
|
221
|
+
await Promise.all(
|
|
222
|
+
Array.from({ length: workerCount }, async () => {
|
|
223
|
+
while (nextIndex < items.length) {
|
|
224
|
+
const currentIndex = nextIndex;
|
|
225
|
+
nextIndex += 1;
|
|
226
|
+
const item = items[currentIndex];
|
|
227
|
+
if (item === void 0) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
results[currentIndex] = await execute(item);
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
return results;
|
|
235
|
+
}
|
|
236
|
+
async function loadPdfToStore(file, store, options) {
|
|
237
|
+
const scale = options?.scale ?? 1.5;
|
|
238
|
+
const pageConcurrency = options?.pageConcurrency ?? 2;
|
|
239
|
+
const pdfjs = await getPdfJs();
|
|
240
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
241
|
+
const pdf = await pdfjs.getDocument({ data: arrayBuffer }).promise;
|
|
242
|
+
const pageNumbers = normalizePdfPageNumbers(options?.pageNumbers, pdf.numPages);
|
|
243
|
+
return await runWithConcurrency(
|
|
244
|
+
pageNumbers,
|
|
245
|
+
pageConcurrency,
|
|
246
|
+
async (pageNumber) => {
|
|
247
|
+
const page = await pdf.getPage(pageNumber);
|
|
248
|
+
const { canvas, width, height } = await renderPageToCanvas(page, scale);
|
|
249
|
+
const mime = "image/png";
|
|
250
|
+
const pageBlob = await canvasToBlob(canvas, mime);
|
|
251
|
+
const blobId = await store.storeOriginal(pageBlob);
|
|
252
|
+
const thumbScale = Math.min(1, 256 / Math.max(width, height));
|
|
253
|
+
const tw = Math.max(1, Math.round(width * thumbScale));
|
|
254
|
+
const th = Math.max(1, Math.round(height * thumbScale));
|
|
255
|
+
const thumbCanvas = document.createElement("canvas");
|
|
256
|
+
thumbCanvas.width = tw;
|
|
257
|
+
thumbCanvas.height = th;
|
|
258
|
+
const tCtx = thumbCanvas.getContext("2d");
|
|
259
|
+
if (tCtx) {
|
|
260
|
+
tCtx.imageSmoothingEnabled = true;
|
|
261
|
+
tCtx.imageSmoothingQuality = "high";
|
|
262
|
+
tCtx.drawImage(canvas, 0, 0, tw, th);
|
|
263
|
+
}
|
|
264
|
+
const thumbBlob = await canvasToBlob(thumbCanvas, mime);
|
|
265
|
+
const thumbnailBlobId = await store.storeThumbnail(thumbBlob);
|
|
266
|
+
return {
|
|
267
|
+
blobId,
|
|
268
|
+
thumbnailBlobId,
|
|
269
|
+
width,
|
|
270
|
+
height,
|
|
271
|
+
pageNumber
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
81
277
|
// src/image/raster-image.ts
|
|
82
278
|
var MAX_RASTER_EMBED_DIMENSION = 4096;
|
|
83
279
|
function normalizeLoadOptions(maxDimensionOrOptions) {
|
|
@@ -1462,16 +1658,14 @@ function itemHitTestWorldPoint(item, worldX, worldY, options) {
|
|
|
1462
1658
|
return true;
|
|
1463
1659
|
}
|
|
1464
1660
|
}
|
|
1661
|
+
return false;
|
|
1465
1662
|
}
|
|
1466
|
-
if (pts
|
|
1663
|
+
if (pts && pts.length === 1) {
|
|
1467
1664
|
const p = pts[0];
|
|
1468
|
-
if (p)
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
return true;
|
|
1473
|
-
}
|
|
1474
|
-
}
|
|
1665
|
+
if (!p) return false;
|
|
1666
|
+
const cw = itemLocalToWorld(p.x, p.y, item.x, item.y, w, h, rot);
|
|
1667
|
+
const dsq = (worldX - cw.x) ** 2 + (worldY - cw.y) ** 2;
|
|
1668
|
+
return dsq <= tolSq;
|
|
1475
1669
|
}
|
|
1476
1670
|
return hitTestFilledShape(item, worldX, worldY);
|
|
1477
1671
|
}
|
|
@@ -1508,6 +1702,271 @@ function collectEraserTargetsAtWorldPoint(items, worldX, worldY, options) {
|
|
|
1508
1702
|
return ids;
|
|
1509
1703
|
}
|
|
1510
1704
|
|
|
1705
|
+
// src/react/asset-hydration.ts
|
|
1706
|
+
var HYDRATION_CACHE_NAME = "canvu-asset-hydration-v1";
|
|
1707
|
+
var DEFAULT_PDF_SCALE = 1.15;
|
|
1708
|
+
var DEFAULT_PDF_PAGE_CONCURRENCY = 2;
|
|
1709
|
+
var hydrationBlobPromises = /* @__PURE__ */ new Map();
|
|
1710
|
+
function buildImageHydrationKey(assetId) {
|
|
1711
|
+
return `image:${assetId}`;
|
|
1712
|
+
}
|
|
1713
|
+
function buildPdfHydrationKey(assetId, pageNumber, scale) {
|
|
1714
|
+
return `pdf:${assetId}:page:${pageNumber}:scale:${scale}`;
|
|
1715
|
+
}
|
|
1716
|
+
function getCacheRequest(key) {
|
|
1717
|
+
return new Request(
|
|
1718
|
+
`https://canvu.local/asset-hydration/${encodeURIComponent(key)}`
|
|
1719
|
+
);
|
|
1720
|
+
}
|
|
1721
|
+
async function openHydrationCache() {
|
|
1722
|
+
if (typeof caches === "undefined") return null;
|
|
1723
|
+
try {
|
|
1724
|
+
return await caches.open(HYDRATION_CACHE_NAME);
|
|
1725
|
+
} catch {
|
|
1726
|
+
return null;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
async function readCachedHydrationBlob(key) {
|
|
1730
|
+
const cache = await openHydrationCache();
|
|
1731
|
+
if (!cache) return null;
|
|
1732
|
+
try {
|
|
1733
|
+
const response = await cache.match(getCacheRequest(key));
|
|
1734
|
+
if (!response?.ok) return null;
|
|
1735
|
+
return await response.blob();
|
|
1736
|
+
} catch {
|
|
1737
|
+
return null;
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
async function writeCachedHydrationBlob(key, blob) {
|
|
1741
|
+
const cache = await openHydrationCache();
|
|
1742
|
+
if (!cache) return;
|
|
1743
|
+
try {
|
|
1744
|
+
await cache.put(getCacheRequest(key), new Response(blob));
|
|
1745
|
+
} catch {
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
async function fetchBlob(url) {
|
|
1749
|
+
try {
|
|
1750
|
+
const response = await fetch(url);
|
|
1751
|
+
if (!response.ok) return null;
|
|
1752
|
+
return await response.blob();
|
|
1753
|
+
} catch {
|
|
1754
|
+
return null;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
async function getHydrationBlob(key, preferCachedRasters, loader) {
|
|
1758
|
+
const cached = preferCachedRasters ? await readCachedHydrationBlob(key) : null;
|
|
1759
|
+
if (cached) return cached;
|
|
1760
|
+
const inFlight = hydrationBlobPromises.get(key);
|
|
1761
|
+
if (inFlight) return await inFlight;
|
|
1762
|
+
const nextPromise = (async () => {
|
|
1763
|
+
const blob = await loader();
|
|
1764
|
+
if (blob) {
|
|
1765
|
+
await writeCachedHydrationBlob(key, blob);
|
|
1766
|
+
}
|
|
1767
|
+
return blob;
|
|
1768
|
+
})();
|
|
1769
|
+
hydrationBlobPromises.set(key, nextPromise);
|
|
1770
|
+
try {
|
|
1771
|
+
return await nextPromise;
|
|
1772
|
+
} finally {
|
|
1773
|
+
hydrationBlobPromises.delete(key);
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
function registerObjectUrl(objectUrls, blob) {
|
|
1777
|
+
const href = URL.createObjectURL(blob);
|
|
1778
|
+
objectUrls.push(href);
|
|
1779
|
+
return href;
|
|
1780
|
+
}
|
|
1781
|
+
function getHydrationRequests(items, assetStore, pdfScale) {
|
|
1782
|
+
if (!assetStore.getHydrationRequest) return [];
|
|
1783
|
+
return items.flatMap((item) => {
|
|
1784
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1785
|
+
if (!request) return [];
|
|
1786
|
+
return [
|
|
1787
|
+
{
|
|
1788
|
+
request: {
|
|
1789
|
+
...request,
|
|
1790
|
+
scale: request.scale ?? pdfScale
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
];
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
function createPdfHydrationGroups(requests) {
|
|
1797
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1798
|
+
for (const entry of requests) {
|
|
1799
|
+
if (entry.request.kind !== "pdf" || entry.request.pageNumber == null) continue;
|
|
1800
|
+
const scale = entry.request.scale ?? DEFAULT_PDF_SCALE;
|
|
1801
|
+
const key = `${entry.request.assetId}:${scale}`;
|
|
1802
|
+
const existingGroup = groups.get(key);
|
|
1803
|
+
if (existingGroup) {
|
|
1804
|
+
if (!existingGroup.pageNumbers.includes(entry.request.pageNumber)) {
|
|
1805
|
+
existingGroup.pageNumbers.push(entry.request.pageNumber);
|
|
1806
|
+
}
|
|
1807
|
+
continue;
|
|
1808
|
+
}
|
|
1809
|
+
groups.set(key, {
|
|
1810
|
+
assetId: entry.request.assetId,
|
|
1811
|
+
scale,
|
|
1812
|
+
pageNumbers: [entry.request.pageNumber]
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return [...groups.values()];
|
|
1816
|
+
}
|
|
1817
|
+
async function hydrateImageAssets(requests, resolvedAssetUrls, objectUrls, preferCachedRasters) {
|
|
1818
|
+
const uniqueAssetIds = [
|
|
1819
|
+
...new Set(requests.map((entry) => entry.request.assetId))
|
|
1820
|
+
];
|
|
1821
|
+
const hydratedEntries = await Promise.all(
|
|
1822
|
+
uniqueAssetIds.map(async (assetId) => {
|
|
1823
|
+
const resolvedAsset = resolvedAssetUrls[assetId];
|
|
1824
|
+
if (!resolvedAsset?.url) {
|
|
1825
|
+
return [assetId, null];
|
|
1826
|
+
}
|
|
1827
|
+
const blob = await getHydrationBlob(
|
|
1828
|
+
buildImageHydrationKey(assetId),
|
|
1829
|
+
preferCachedRasters,
|
|
1830
|
+
async () => await fetchBlob(resolvedAsset.url)
|
|
1831
|
+
);
|
|
1832
|
+
if (!blob) {
|
|
1833
|
+
return [assetId, null];
|
|
1834
|
+
}
|
|
1835
|
+
return [
|
|
1836
|
+
assetId,
|
|
1837
|
+
{
|
|
1838
|
+
href: registerObjectUrl(objectUrls, blob)
|
|
1839
|
+
}
|
|
1840
|
+
];
|
|
1841
|
+
})
|
|
1842
|
+
);
|
|
1843
|
+
return new Map(hydratedEntries);
|
|
1844
|
+
}
|
|
1845
|
+
async function hydratePdfAssets(requests, resolvedAssetUrls, objectUrls, options) {
|
|
1846
|
+
const hydratedPages = /* @__PURE__ */ new Map();
|
|
1847
|
+
const groups = createPdfHydrationGroups(requests);
|
|
1848
|
+
for (const group of groups) {
|
|
1849
|
+
const resolvedAsset = resolvedAssetUrls[group.assetId];
|
|
1850
|
+
if (!resolvedAsset?.url) {
|
|
1851
|
+
continue;
|
|
1852
|
+
}
|
|
1853
|
+
const missingPages = [];
|
|
1854
|
+
for (const pageNumber of group.pageNumbers) {
|
|
1855
|
+
const cacheKey = buildPdfHydrationKey(group.assetId, pageNumber, group.scale);
|
|
1856
|
+
const cachedBlob = await readCachedHydrationBlob(cacheKey);
|
|
1857
|
+
if (!cachedBlob) {
|
|
1858
|
+
missingPages.push(pageNumber);
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
hydratedPages.set(cacheKey, {
|
|
1862
|
+
href: registerObjectUrl(objectUrls, cachedBlob)
|
|
1863
|
+
});
|
|
1864
|
+
}
|
|
1865
|
+
if (missingPages.length === 0) {
|
|
1866
|
+
continue;
|
|
1867
|
+
}
|
|
1868
|
+
const pdfBlob = await fetchBlob(resolvedAsset.url);
|
|
1869
|
+
if (!pdfBlob) {
|
|
1870
|
+
continue;
|
|
1871
|
+
}
|
|
1872
|
+
const renderedPages = await loadPdfToStore(pdfBlob, options.imageStore, {
|
|
1873
|
+
scale: group.scale,
|
|
1874
|
+
pageNumbers: missingPages,
|
|
1875
|
+
pageConcurrency: options.pdfPageConcurrency
|
|
1876
|
+
});
|
|
1877
|
+
for (const renderedPage of renderedPages) {
|
|
1878
|
+
const cacheKey = buildPdfHydrationKey(
|
|
1879
|
+
group.assetId,
|
|
1880
|
+
renderedPage.pageNumber,
|
|
1881
|
+
group.scale
|
|
1882
|
+
);
|
|
1883
|
+
const pageBlob = await options.imageStore.getOriginal(renderedPage.blobId);
|
|
1884
|
+
if (!pageBlob) {
|
|
1885
|
+
continue;
|
|
1886
|
+
}
|
|
1887
|
+
await writeCachedHydrationBlob(cacheKey, pageBlob);
|
|
1888
|
+
hydratedPages.set(cacheKey, {
|
|
1889
|
+
href: registerObjectUrl(objectUrls, pageBlob),
|
|
1890
|
+
width: renderedPage.width,
|
|
1891
|
+
height: renderedPage.height
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
return hydratedPages;
|
|
1896
|
+
}
|
|
1897
|
+
async function hydrateSceneItemsWithAssets(items, assetStore, options = {}) {
|
|
1898
|
+
if (!assetStore.resolve || !assetStore.getHydrationRequest) {
|
|
1899
|
+
return {
|
|
1900
|
+
items: [...items],
|
|
1901
|
+
objectUrls: []
|
|
1902
|
+
};
|
|
1903
|
+
}
|
|
1904
|
+
const pdfScale = options.pdfScale ?? DEFAULT_PDF_SCALE;
|
|
1905
|
+
const pdfPageConcurrency = options.pdfPageConcurrency ?? DEFAULT_PDF_PAGE_CONCURRENCY;
|
|
1906
|
+
const preferCachedRasters = options.preferCachedRasters ?? true;
|
|
1907
|
+
const imageStore = options.imageStore ?? new IndexedDbImageStore();
|
|
1908
|
+
const hydrationRequests = getHydrationRequests(items, assetStore, pdfScale);
|
|
1909
|
+
if (hydrationRequests.length === 0) {
|
|
1910
|
+
return {
|
|
1911
|
+
items: [...items],
|
|
1912
|
+
objectUrls: []
|
|
1913
|
+
};
|
|
1914
|
+
}
|
|
1915
|
+
const assetIds = [
|
|
1916
|
+
...new Set(hydrationRequests.map((entry) => entry.request.assetId))
|
|
1917
|
+
];
|
|
1918
|
+
const resolvedAssetUrls = await assetStore.resolve({ assetIds });
|
|
1919
|
+
const objectUrls = [];
|
|
1920
|
+
const hydratedImages = await hydrateImageAssets(
|
|
1921
|
+
hydrationRequests.filter((entry) => entry.request.kind === "image"),
|
|
1922
|
+
resolvedAssetUrls,
|
|
1923
|
+
objectUrls,
|
|
1924
|
+
preferCachedRasters
|
|
1925
|
+
);
|
|
1926
|
+
const hydratedPdfPages = await hydratePdfAssets(
|
|
1927
|
+
hydrationRequests.filter((entry) => entry.request.kind === "pdf"),
|
|
1928
|
+
resolvedAssetUrls,
|
|
1929
|
+
objectUrls,
|
|
1930
|
+
{
|
|
1931
|
+
imageStore,
|
|
1932
|
+
pdfPageConcurrency}
|
|
1933
|
+
);
|
|
1934
|
+
return {
|
|
1935
|
+
items: items.map((item) => {
|
|
1936
|
+
const request = assetStore.getHydrationRequest?.(item);
|
|
1937
|
+
if (!request || item.toolKind !== "image") return item;
|
|
1938
|
+
if (request.kind === "image") {
|
|
1939
|
+
const hydratedImage = hydratedImages.get(request.assetId);
|
|
1940
|
+
if (!hydratedImage) return item;
|
|
1941
|
+
return rebuildItemSvg({
|
|
1942
|
+
...item,
|
|
1943
|
+
imageRasterHref: hydratedImage.href,
|
|
1944
|
+
imageThumbnailHref: hydratedImage.href
|
|
1945
|
+
});
|
|
1946
|
+
}
|
|
1947
|
+
if (request.pageNumber == null) return item;
|
|
1948
|
+
const hydratedPdfPage = hydratedPdfPages.get(
|
|
1949
|
+
buildPdfHydrationKey(
|
|
1950
|
+
request.assetId,
|
|
1951
|
+
request.pageNumber,
|
|
1952
|
+
request.scale ?? pdfScale
|
|
1953
|
+
)
|
|
1954
|
+
);
|
|
1955
|
+
if (!hydratedPdfPage) return item;
|
|
1956
|
+
return rebuildItemSvg({
|
|
1957
|
+
...item,
|
|
1958
|
+
imageRasterHref: hydratedPdfPage.href,
|
|
1959
|
+
imageThumbnailHref: hydratedPdfPage.href,
|
|
1960
|
+
imageIntrinsicSize: {
|
|
1961
|
+
width: item.imageIntrinsicSize?.width ?? Math.max(1, Math.round(hydratedPdfPage.width ?? item.bounds.width)),
|
|
1962
|
+
height: item.imageIntrinsicSize?.height ?? Math.max(1, Math.round(hydratedPdfPage.height ?? item.bounds.height))
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
}),
|
|
1966
|
+
objectUrls
|
|
1967
|
+
};
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1511
1970
|
// src/scene/spatial-cull.ts
|
|
1512
1971
|
var spatialIndexCache = /* @__PURE__ */ new WeakMap();
|
|
1513
1972
|
function cellKey(ix, iy) {
|
|
@@ -1750,6 +2209,6 @@ var VectorScene = class {
|
|
|
1750
2209
|
}
|
|
1751
2210
|
};
|
|
1752
2211
|
|
|
1753
|
-
export { ARROW_BIND_SNAP_PX, Camera2D, DEFAULT_STROKE_STYLE, DEFAULT_TEXT_FONT_SIZE, MAX_RASTER_EMBED_DIMENSION, SvgVectorRenderer, VectorScene, applyStrokeToItem, attachApplePencilNavigation, attachViewportInput, bakeArrowItemToAbsolute, buildArrowSvg, buildCustomShapeChildrenSvg, buildDrawDotSvg, buildEllipseSvg, buildFreehandPathSvg, buildLineSvg, buildRectSvg, buildTextSvg, cloneVectorSceneItemWithNewId, cloneVectorSceneItemsWithNewIds, collectEraserTargetsAtWorldPoint, computeFreehandSvgPayload, createCustomShapeItem, createDrawDotItem, createEllipseItem, createFreehandStrokeItem, createImageFromVectorTrace, createImageItem, createLineItem, createRectangleItem, createShapeId, createTextItem, cullItemsByViewport, expandCustomShapeTemplate, formatCameraTransform, formatItemPlacementTransform, hitTestWorldPoint, isArrowBindTarget, itemHitTestWorldPoint, lineEndpointsToLocal, loadImageFileAsRasterSceneSource, normalizeRect, rebuildItemSvg, rectsIntersect, resolveArrowBindingsInScene, resolveStrokeStyle, snapArrowEndpointToShape };
|
|
2212
|
+
export { ARROW_BIND_SNAP_PX, Camera2D, DEFAULT_STROKE_STYLE, DEFAULT_TEXT_FONT_SIZE, MAX_RASTER_EMBED_DIMENSION, SvgVectorRenderer, VectorScene, applyStrokeToItem, attachApplePencilNavigation, attachViewportInput, bakeArrowItemToAbsolute, buildArrowSvg, buildCustomShapeChildrenSvg, buildDrawDotSvg, buildEllipseSvg, buildFreehandPathSvg, buildLineSvg, buildRectSvg, buildTextSvg, cloneVectorSceneItemWithNewId, cloneVectorSceneItemsWithNewIds, collectEraserTargetsAtWorldPoint, computeFreehandSvgPayload, createCustomShapeItem, createDrawDotItem, createEllipseItem, createFreehandStrokeItem, createImageFromVectorTrace, createImageItem, createLineItem, createRectangleItem, createShapeId, createTextItem, cullItemsByViewport, expandCustomShapeTemplate, formatCameraTransform, formatItemPlacementTransform, hitTestWorldPoint, hydrateSceneItemsWithAssets, isArrowBindTarget, itemHitTestWorldPoint, lineEndpointsToLocal, loadImageFileAsRasterSceneSource, normalizeRect, rebuildItemSvg, rectsIntersect, resolveArrowBindingsInScene, resolveStrokeStyle, snapArrowEndpointToShape };
|
|
1754
2213
|
//# sourceMappingURL=index.js.map
|
|
1755
2214
|
//# sourceMappingURL=index.js.map
|