canvu-react 0.4.67 → 0.4.69

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/react.cjs CHANGED
@@ -6884,6 +6884,177 @@ function cullItemsByViewport(items, visibleWorld) {
6884
6884
  return cullItemsByViewportSpatial(items, visibleWorld, SPATIAL_CELL_SIZE);
6885
6885
  }
6886
6886
 
6887
+ // src/renderer/raster-image-canvas.ts
6888
+ init_rect();
6889
+ var DEFAULT_PIXEL_HEADROOM = 1.5;
6890
+ var DEFAULT_MAX_PIXEL_COUNT = 12e6;
6891
+ var DEFAULT_MAX_DIMENSION = 4096;
6892
+ var DEFAULT_UPSCALE_REDRAW_RATIO = 1.15;
6893
+ function resolveRasterImageCanvasRenderingOptions(options) {
6894
+ if (!options) return null;
6895
+ const fallbackDevicePixelRatio = typeof window === "undefined" ? 1 : window.devicePixelRatio;
6896
+ return {
6897
+ resolveSourceSize: options.resolveSourceSize,
6898
+ resolveRenderTarget: options.resolveRenderTarget,
6899
+ devicePixelRatio: toPositiveFiniteNumber(
6900
+ options.devicePixelRatio,
6901
+ fallbackDevicePixelRatio
6902
+ ),
6903
+ pixelHeadroom: toPositiveFiniteNumber(
6904
+ options.pixelHeadroom,
6905
+ DEFAULT_PIXEL_HEADROOM
6906
+ ),
6907
+ maxPixelCount: toPositiveFiniteNumber(
6908
+ options.maxPixelCount,
6909
+ DEFAULT_MAX_PIXEL_COUNT
6910
+ ),
6911
+ maxDimension: toPositiveFiniteNumber(
6912
+ options.maxDimension,
6913
+ DEFAULT_MAX_DIMENSION
6914
+ ),
6915
+ upscaleRedrawRatio: toPositiveFiniteNumber(
6916
+ options.upscaleRedrawRatio,
6917
+ DEFAULT_UPSCALE_REDRAW_RATIO
6918
+ )
6919
+ };
6920
+ }
6921
+ function getRasterImageContentRect(item) {
6922
+ if (item.toolKind !== "image" || !item.imageIntrinsicSize) return null;
6923
+ const bounds = normalizeRect(item.bounds);
6924
+ const intrinsicWidth = Math.max(1e-6, item.imageIntrinsicSize.width);
6925
+ const intrinsicHeight = Math.max(1e-6, item.imageIntrinsicSize.height);
6926
+ const boundsAspectRatio = bounds.width / Math.max(1e-9, bounds.height);
6927
+ const imageAspectRatio = intrinsicWidth / intrinsicHeight;
6928
+ if (Math.abs(boundsAspectRatio - imageAspectRatio) < 1e-3) {
6929
+ return { x: 0, y: 0, width: bounds.width, height: bounds.height };
6930
+ }
6931
+ if (boundsAspectRatio > imageAspectRatio) {
6932
+ const height2 = bounds.height;
6933
+ const width2 = height2 * imageAspectRatio;
6934
+ return { x: (bounds.width - width2) / 2, y: 0, width: width2, height: height2 };
6935
+ }
6936
+ const width = bounds.width;
6937
+ const height = width / imageAspectRatio;
6938
+ return { x: 0, y: (bounds.height - height) / 2, width, height };
6939
+ }
6940
+ function resolveRasterImageCanvasSourceSize({
6941
+ item,
6942
+ href,
6943
+ intrinsicSize,
6944
+ contentRect,
6945
+ viewportSize,
6946
+ cameraZoom,
6947
+ options
6948
+ }) {
6949
+ const resolved = options.resolveSourceSize?.({
6950
+ item,
6951
+ href,
6952
+ intrinsicSize,
6953
+ contentRect,
6954
+ viewportSize,
6955
+ cameraZoom,
6956
+ devicePixelRatio: options.devicePixelRatio
6957
+ });
6958
+ const width = toPositiveFiniteNumber(resolved?.width, intrinsicSize.width);
6959
+ const height = toPositiveFiniteNumber(resolved?.height, intrinsicSize.height);
6960
+ return { width, height };
6961
+ }
6962
+ function getRasterImageCanvasTargetSize({
6963
+ intrinsicSize,
6964
+ contentRect,
6965
+ cameraZoom,
6966
+ devicePixelRatio,
6967
+ pixelHeadroom,
6968
+ maxPixelCount,
6969
+ maxDimension
6970
+ }) {
6971
+ const intrinsicWidth = Math.max(1, Math.round(intrinsicSize.width));
6972
+ const intrinsicHeight = Math.max(1, Math.round(intrinsicSize.height));
6973
+ const targetCssWidth = Math.max(1, contentRect.width * cameraZoom);
6974
+ const targetCssHeight = Math.max(1, contentRect.height * cameraZoom);
6975
+ const desiredWidth = targetCssWidth * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
6976
+ const desiredHeight = targetCssHeight * toPositiveFiniteNumber(devicePixelRatio, 1) * pixelHeadroom;
6977
+ const dimensionScale = Math.min(
6978
+ 1,
6979
+ toPositiveFiniteNumber(maxDimension, intrinsicWidth) / Math.max(intrinsicWidth, intrinsicHeight)
6980
+ );
6981
+ const pixelScale = Math.min(
6982
+ 1,
6983
+ Math.sqrt(
6984
+ toPositiveFiniteNumber(maxPixelCount, intrinsicWidth * intrinsicHeight) / (intrinsicWidth * intrinsicHeight)
6985
+ )
6986
+ );
6987
+ const viewportScale = Math.min(
6988
+ 1,
6989
+ desiredWidth / intrinsicWidth,
6990
+ desiredHeight / intrinsicHeight
6991
+ );
6992
+ const scale = Math.min(dimensionScale, pixelScale, viewportScale);
6993
+ const width = Math.max(1, Math.round(intrinsicWidth * scale));
6994
+ const height = Math.max(1, Math.round(width * (intrinsicHeight / intrinsicWidth)));
6995
+ return { width, height };
6996
+ }
6997
+ function resolveRasterImageCanvasRenderTarget({
6998
+ item,
6999
+ href,
7000
+ intrinsicSize,
7001
+ sourceSize,
7002
+ contentRect,
7003
+ targetSize,
7004
+ viewportSize,
7005
+ cameraZoom,
7006
+ options
7007
+ }) {
7008
+ const request = {
7009
+ item,
7010
+ href,
7011
+ intrinsicSize,
7012
+ sourceSize,
7013
+ contentRect,
7014
+ targetSize,
7015
+ viewportSize,
7016
+ cameraZoom,
7017
+ devicePixelRatio: options.devicePixelRatio
7018
+ };
7019
+ const resolved = options.resolveRenderTarget?.(request);
7020
+ if (typeof resolved === "string") {
7021
+ return { href: resolved, sourceKey: resolved, targetSize, contentRect };
7022
+ }
7023
+ if (resolved?.href) {
7024
+ return {
7025
+ href: resolved.href,
7026
+ sourceKey: resolved.sourceKey ?? resolved.href,
7027
+ targetSize,
7028
+ contentRect
7029
+ };
7030
+ }
7031
+ return { href, sourceKey: href, targetSize, contentRect };
7032
+ }
7033
+ function shouldRedrawRasterImageCanvas({
7034
+ currentSourceKey,
7035
+ currentWidth,
7036
+ currentHeight,
7037
+ nextSourceKey,
7038
+ nextWidth,
7039
+ nextHeight,
7040
+ upscaleRedrawRatio
7041
+ }) {
7042
+ const safeCurrentWidth = Math.max(0, Math.round(currentWidth));
7043
+ const safeCurrentHeight = Math.max(0, Math.round(currentHeight));
7044
+ const safeNextWidth = Math.max(1, Math.round(nextWidth));
7045
+ const safeNextHeight = Math.max(1, Math.round(nextHeight));
7046
+ if (!currentSourceKey || safeCurrentWidth <= 1 || safeCurrentHeight <= 1) {
7047
+ return true;
7048
+ }
7049
+ if (currentSourceKey !== nextSourceKey && safeCurrentWidth === safeNextWidth && safeCurrentHeight === safeNextHeight) {
7050
+ return true;
7051
+ }
7052
+ return safeNextWidth > safeCurrentWidth * upscaleRedrawRatio || safeNextHeight > safeCurrentHeight * upscaleRedrawRatio;
7053
+ }
7054
+ function toPositiveFiniteNumber(value, fallback) {
7055
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
7056
+ }
7057
+
6887
7058
  // src/renderer/svg-vector-renderer.ts
6888
7059
  function formatCameraTransform(camera) {
6889
7060
  const z = camera.zoom;
@@ -6908,6 +7079,87 @@ function itemClassName(item) {
6908
7079
  }
6909
7080
  return classes.join(" ");
6910
7081
  }
7082
+ async function decodeRasterImage(href, width, height, signal) {
7083
+ if (typeof createImageBitmap === "function") {
7084
+ try {
7085
+ const response = await fetch(href, { signal, credentials: "same-origin" });
7086
+ if (!response.ok) {
7087
+ throw new Error(`Failed to fetch raster image: ${response.status}`);
7088
+ }
7089
+ const blob = await response.blob();
7090
+ if (signal.aborted) throw new DOMException("Aborted", "AbortError");
7091
+ const bitmap = await createImageBitmap(blob, {
7092
+ resizeWidth: width,
7093
+ resizeHeight: height,
7094
+ resizeQuality: "high"
7095
+ });
7096
+ return {
7097
+ width: bitmap.width,
7098
+ height: bitmap.height,
7099
+ draw: (context) => {
7100
+ context.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height);
7101
+ },
7102
+ close: () => bitmap.close()
7103
+ };
7104
+ } catch (error) {
7105
+ if (signal.aborted) throw error;
7106
+ }
7107
+ }
7108
+ const image = await loadImageElement(href, signal);
7109
+ return {
7110
+ width,
7111
+ height,
7112
+ draw: (context) => {
7113
+ context.drawImage(image, 0, 0, width, height);
7114
+ },
7115
+ close: () => {
7116
+ }
7117
+ };
7118
+ }
7119
+ function loadImageElement(href, signal) {
7120
+ return new Promise((resolve, reject) => {
7121
+ if (signal.aborted) {
7122
+ reject(new DOMException("Aborted", "AbortError"));
7123
+ return;
7124
+ }
7125
+ const image = new Image();
7126
+ const cleanup = () => {
7127
+ signal.removeEventListener("abort", abort);
7128
+ image.onload = null;
7129
+ image.onerror = null;
7130
+ };
7131
+ const abort = () => {
7132
+ cleanup();
7133
+ image.removeAttribute("src");
7134
+ reject(new DOMException("Aborted", "AbortError"));
7135
+ };
7136
+ image.decoding = "async";
7137
+ image.onload = () => {
7138
+ const decodePromise = image.decode?.();
7139
+ if (!decodePromise) {
7140
+ cleanup();
7141
+ resolve(image);
7142
+ return;
7143
+ }
7144
+ decodePromise.then(
7145
+ () => {
7146
+ cleanup();
7147
+ resolve(image);
7148
+ },
7149
+ () => {
7150
+ cleanup();
7151
+ resolve(image);
7152
+ }
7153
+ );
7154
+ };
7155
+ image.onerror = () => {
7156
+ cleanup();
7157
+ reject(new Error("Failed to load raster image"));
7158
+ };
7159
+ signal.addEventListener("abort", abort, { once: true });
7160
+ image.src = href;
7161
+ });
7162
+ }
6911
7163
  var SvgVectorRenderer = class {
6912
7164
  container;
6913
7165
  scene;
@@ -6919,10 +7171,14 @@ var SvgVectorRenderer = class {
6919
7171
  hoveredItemId = null;
6920
7172
  liveOverlay = null;
6921
7173
  resizeObserver;
7174
+ rasterImageCanvasRendering;
6922
7175
  constructor(options) {
6923
7176
  this.container = options.container;
6924
7177
  this.scene = options.scene;
6925
7178
  this.camera = options.camera;
7179
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(
7180
+ options.rasterImageCanvas
7181
+ );
6926
7182
  this.svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
6927
7183
  this.svg.setAttribute("width", "100%");
6928
7184
  this.svg.setAttribute("height", "100%");
@@ -6951,6 +7207,15 @@ var SvgVectorRenderer = class {
6951
7207
  this.applyInteractionAttributes(cached.g, id);
6952
7208
  }
6953
7209
  }
7210
+ setRasterImageCanvasRendering(options) {
7211
+ this.rasterImageCanvasRendering = resolveRasterImageCanvasRenderingOptions(options);
7212
+ if (!this.rasterImageCanvasRendering) {
7213
+ for (const cached of this.itemNodeCache.values()) {
7214
+ this.releaseRasterImageCanvas(cached);
7215
+ }
7216
+ }
7217
+ this.render();
7218
+ }
6954
7219
  /**
6955
7220
  * Reads container size, culls items, and updates the SVG (incrementally when possible).
6956
7221
  */
@@ -7024,6 +7289,7 @@ var SvgVectorRenderer = class {
7024
7289
  }
7025
7290
  for (const [id, cached] of this.itemNodeCache) {
7026
7291
  if (!visibleIds.has(id)) {
7292
+ this.releaseRasterImageCanvas(cached);
7027
7293
  cached.g.remove();
7028
7294
  }
7029
7295
  }
@@ -7056,6 +7322,7 @@ var SvgVectorRenderer = class {
7056
7322
  g.innerHTML = item.childrenSvg;
7057
7323
  cached.lastChildrenSvg = item.childrenSvg;
7058
7324
  }
7325
+ this.syncRasterImageCanvas(cached, item);
7059
7326
  const expectedPosition = previousNode ? previousNode.nextSibling : this.rootG.firstChild;
7060
7327
  if (expectedPosition !== g) {
7061
7328
  this.rootG.insertBefore(g, expectedPosition);
@@ -7063,6 +7330,238 @@ var SvgVectorRenderer = class {
7063
7330
  previousNode = g;
7064
7331
  }
7065
7332
  }
7333
+ syncRasterImageCanvas(cached, item) {
7334
+ const options = this.rasterImageCanvasRendering;
7335
+ if (!options || item.toolKind !== "image" || !item.imageRasterHref || !item.imageIntrinsicSize) {
7336
+ this.releaseRasterImageCanvas(cached);
7337
+ return;
7338
+ }
7339
+ const contentRect = getRasterImageContentRect(item);
7340
+ const viewportSize = {
7341
+ width: this.container.clientWidth,
7342
+ height: this.container.clientHeight
7343
+ };
7344
+ if (!contentRect || viewportSize.width <= 0 || viewportSize.height <= 0) {
7345
+ this.releaseRasterImageCanvas(cached);
7346
+ return;
7347
+ }
7348
+ const sourceSize = resolveRasterImageCanvasSourceSize({
7349
+ item,
7350
+ href: item.imageRasterHref,
7351
+ intrinsicSize: item.imageIntrinsicSize,
7352
+ contentRect,
7353
+ viewportSize,
7354
+ cameraZoom: this.camera.zoom,
7355
+ options
7356
+ });
7357
+ const targetSize = getRasterImageCanvasTargetSize({
7358
+ intrinsicSize: sourceSize,
7359
+ contentRect,
7360
+ cameraZoom: this.camera.zoom,
7361
+ devicePixelRatio: options.devicePixelRatio,
7362
+ pixelHeadroom: options.pixelHeadroom,
7363
+ maxPixelCount: options.maxPixelCount,
7364
+ maxDimension: options.maxDimension
7365
+ });
7366
+ const target = resolveRasterImageCanvasRenderTarget({
7367
+ item,
7368
+ href: item.imageRasterHref,
7369
+ intrinsicSize: item.imageIntrinsicSize,
7370
+ sourceSize,
7371
+ contentRect,
7372
+ targetSize,
7373
+ viewportSize,
7374
+ cameraZoom: this.camera.zoom,
7375
+ options
7376
+ });
7377
+ const rasterCanvas = this.ensureRasterImageCanvas(cached);
7378
+ this.positionRasterImageCanvas(rasterCanvas, target.contentRect);
7379
+ if (rasterCanvas.itemHref !== null && rasterCanvas.itemHref !== item.imageRasterHref) {
7380
+ this.clearRasterImageCanvasBitmap(rasterCanvas);
7381
+ }
7382
+ if (!shouldRedrawRasterImageCanvas({
7383
+ currentSourceKey: rasterCanvas.sourceKey,
7384
+ currentWidth: rasterCanvas.width,
7385
+ currentHeight: rasterCanvas.height,
7386
+ nextSourceKey: target.sourceKey,
7387
+ nextWidth: target.targetSize.width,
7388
+ nextHeight: target.targetSize.height,
7389
+ upscaleRedrawRatio: options.upscaleRedrawRatio
7390
+ })) {
7391
+ return;
7392
+ }
7393
+ const request = {
7394
+ itemHref: item.imageRasterHref,
7395
+ target
7396
+ };
7397
+ if (rasterCanvas.abortController) {
7398
+ if (rasterCanvas.loadingItemHref !== item.imageRasterHref) {
7399
+ rasterCanvas.abortController.abort();
7400
+ rasterCanvas.abortController = null;
7401
+ rasterCanvas.loadingItemHref = null;
7402
+ rasterCanvas.loadingSourceKey = null;
7403
+ rasterCanvas.loadingWidth = 0;
7404
+ rasterCanvas.loadingHeight = 0;
7405
+ rasterCanvas.queuedTarget = null;
7406
+ this.drawRasterImageCanvas(rasterCanvas, request);
7407
+ return;
7408
+ }
7409
+ if (rasterCanvas.loadingSourceKey === target.sourceKey && rasterCanvas.loadingWidth === target.targetSize.width && rasterCanvas.loadingHeight === target.targetSize.height) {
7410
+ return;
7411
+ }
7412
+ if (shouldRedrawRasterImageCanvas({
7413
+ currentSourceKey: rasterCanvas.loadingSourceKey,
7414
+ currentWidth: rasterCanvas.loadingWidth,
7415
+ currentHeight: rasterCanvas.loadingHeight,
7416
+ nextSourceKey: target.sourceKey,
7417
+ nextWidth: target.targetSize.width,
7418
+ nextHeight: target.targetSize.height,
7419
+ upscaleRedrawRatio: options.upscaleRedrawRatio
7420
+ })) {
7421
+ rasterCanvas.queuedTarget = request;
7422
+ }
7423
+ return;
7424
+ }
7425
+ this.drawRasterImageCanvas(rasterCanvas, request);
7426
+ }
7427
+ ensureRasterImageCanvas(cached) {
7428
+ if (cached.rasterCanvas) {
7429
+ if (!cached.rasterCanvas.foreignObject.isConnected) {
7430
+ cached.g.appendChild(cached.rasterCanvas.foreignObject);
7431
+ }
7432
+ return cached.rasterCanvas;
7433
+ }
7434
+ const foreignObject = document.createElementNS(
7435
+ "http://www.w3.org/2000/svg",
7436
+ "foreignObject"
7437
+ );
7438
+ foreignObject.setAttribute("data-canvu-raster-canvas", "true");
7439
+ foreignObject.style.pointerEvents = "none";
7440
+ const canvas = document.createElement("canvas");
7441
+ canvas.width = 1;
7442
+ canvas.height = 1;
7443
+ canvas.style.display = "block";
7444
+ canvas.style.width = "100%";
7445
+ canvas.style.height = "100%";
7446
+ foreignObject.appendChild(canvas);
7447
+ cached.g.appendChild(foreignObject);
7448
+ cached.rasterCanvas = {
7449
+ foreignObject,
7450
+ canvas,
7451
+ itemHref: null,
7452
+ sourceKey: null,
7453
+ width: 0,
7454
+ height: 0,
7455
+ loadSequence: 0,
7456
+ abortController: null,
7457
+ loadingItemHref: null,
7458
+ loadingSourceKey: null,
7459
+ loadingWidth: 0,
7460
+ loadingHeight: 0,
7461
+ queuedTarget: null
7462
+ };
7463
+ return cached.rasterCanvas;
7464
+ }
7465
+ positionRasterImageCanvas(rasterCanvas, contentRect) {
7466
+ rasterCanvas.foreignObject.setAttribute("x", String(contentRect.x));
7467
+ rasterCanvas.foreignObject.setAttribute("y", String(contentRect.y));
7468
+ rasterCanvas.foreignObject.setAttribute("width", String(contentRect.width));
7469
+ rasterCanvas.foreignObject.setAttribute("height", String(contentRect.height));
7470
+ }
7471
+ drawRasterImageCanvas(rasterCanvas, request) {
7472
+ const { target } = request;
7473
+ const width = Math.max(1, Math.round(target.targetSize.width));
7474
+ const height = Math.max(1, Math.round(target.targetSize.height));
7475
+ const sequence = rasterCanvas.loadSequence + 1;
7476
+ rasterCanvas.loadSequence = sequence;
7477
+ rasterCanvas.abortController?.abort();
7478
+ const abortController = new AbortController();
7479
+ rasterCanvas.abortController = abortController;
7480
+ rasterCanvas.loadingItemHref = request.itemHref;
7481
+ rasterCanvas.loadingSourceKey = target.sourceKey;
7482
+ rasterCanvas.loadingWidth = width;
7483
+ rasterCanvas.loadingHeight = height;
7484
+ rasterCanvas.queuedTarget = null;
7485
+ decodeRasterImage(target.href, width, height, abortController.signal).then((decoded) => {
7486
+ if (abortController.signal.aborted || rasterCanvas.loadSequence !== sequence) {
7487
+ decoded.close();
7488
+ return;
7489
+ }
7490
+ const context = rasterCanvas.canvas.getContext("2d");
7491
+ if (!context) {
7492
+ decoded.close();
7493
+ rasterCanvas.abortController = null;
7494
+ rasterCanvas.loadingItemHref = null;
7495
+ rasterCanvas.loadingSourceKey = null;
7496
+ rasterCanvas.loadingWidth = 0;
7497
+ rasterCanvas.loadingHeight = 0;
7498
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7499
+ return;
7500
+ }
7501
+ rasterCanvas.canvas.width = decoded.width;
7502
+ rasterCanvas.canvas.height = decoded.height;
7503
+ context.clearRect(0, 0, decoded.width, decoded.height);
7504
+ decoded.draw(context);
7505
+ decoded.close();
7506
+ rasterCanvas.itemHref = request.itemHref;
7507
+ rasterCanvas.sourceKey = target.sourceKey;
7508
+ rasterCanvas.width = decoded.width;
7509
+ rasterCanvas.height = decoded.height;
7510
+ rasterCanvas.abortController = null;
7511
+ rasterCanvas.loadingItemHref = null;
7512
+ rasterCanvas.loadingSourceKey = null;
7513
+ rasterCanvas.loadingWidth = 0;
7514
+ rasterCanvas.loadingHeight = 0;
7515
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7516
+ }).catch((error) => {
7517
+ if (abortController.signal.aborted) return;
7518
+ if (error instanceof Error && error.name === "AbortError") return;
7519
+ if (rasterCanvas.loadSequence === sequence) {
7520
+ rasterCanvas.abortController = null;
7521
+ rasterCanvas.loadingItemHref = null;
7522
+ rasterCanvas.loadingSourceKey = null;
7523
+ rasterCanvas.loadingWidth = 0;
7524
+ rasterCanvas.loadingHeight = 0;
7525
+ this.drawQueuedRasterImageCanvasTarget(rasterCanvas);
7526
+ }
7527
+ });
7528
+ }
7529
+ drawQueuedRasterImageCanvasTarget(rasterCanvas) {
7530
+ const queuedTarget = rasterCanvas.queuedTarget;
7531
+ if (!queuedTarget) return;
7532
+ rasterCanvas.queuedTarget = null;
7533
+ if (!shouldRedrawRasterImageCanvas({
7534
+ currentSourceKey: rasterCanvas.sourceKey,
7535
+ currentWidth: rasterCanvas.width,
7536
+ currentHeight: rasterCanvas.height,
7537
+ nextSourceKey: queuedTarget.target.sourceKey,
7538
+ nextWidth: queuedTarget.target.targetSize.width,
7539
+ nextHeight: queuedTarget.target.targetSize.height,
7540
+ upscaleRedrawRatio: this.rasterImageCanvasRendering?.upscaleRedrawRatio ?? 1
7541
+ })) {
7542
+ return;
7543
+ }
7544
+ this.drawRasterImageCanvas(rasterCanvas, queuedTarget);
7545
+ }
7546
+ clearRasterImageCanvasBitmap(rasterCanvas) {
7547
+ const context = rasterCanvas.canvas.getContext("2d");
7548
+ context?.clearRect(0, 0, rasterCanvas.canvas.width, rasterCanvas.canvas.height);
7549
+ rasterCanvas.canvas.width = 1;
7550
+ rasterCanvas.canvas.height = 1;
7551
+ rasterCanvas.itemHref = null;
7552
+ rasterCanvas.sourceKey = null;
7553
+ rasterCanvas.width = 0;
7554
+ rasterCanvas.height = 0;
7555
+ }
7556
+ releaseRasterImageCanvas(cached) {
7557
+ const rasterCanvas = cached.rasterCanvas;
7558
+ if (!rasterCanvas) return;
7559
+ rasterCanvas.abortController?.abort();
7560
+ rasterCanvas.loadSequence += 1;
7561
+ rasterCanvas.queuedTarget = null;
7562
+ rasterCanvas.foreignObject.remove();
7563
+ cached.rasterCanvas = void 0;
7564
+ }
7066
7565
  applyInteractionAttributes(g, itemId) {
7067
7566
  g.setAttribute(
7068
7567
  "data-canvu-selected",
@@ -7075,6 +7574,9 @@ var SvgVectorRenderer = class {
7075
7574
  }
7076
7575
  destroy() {
7077
7576
  this.resizeObserver.disconnect();
7577
+ for (const cached of this.itemNodeCache.values()) {
7578
+ this.releaseRasterImageCanvas(cached);
7579
+ }
7078
7580
  this.itemNodeCache.clear();
7079
7581
  this.liveOverlay = null;
7080
7582
  this.svg.remove();
@@ -8364,6 +8866,7 @@ var VectorViewport = react.forwardRef(
8364
8866
  customPlacement: consumerCustomPlacement,
8365
8867
  customPlacements: consumerCustomPlacements,
8366
8868
  assetStore,
8869
+ imageCanvasRendering,
8367
8870
  toolLocked = false,
8368
8871
  autoResetToolTo = "select",
8369
8872
  onToolChangeRequest,
@@ -8570,6 +9073,8 @@ var VectorViewport = react.forwardRef(
8570
9073
  onActivateLinkRef.current = onActivateLink;
8571
9074
  const assetStoreRef = react.useRef(assetStore);
8572
9075
  assetStoreRef.current = assetStore;
9076
+ const imageCanvasRenderingRef = react.useRef(imageCanvasRendering);
9077
+ imageCanvasRenderingRef.current = imageCanvasRendering;
8573
9078
  const customPlacementRef = react.useRef(customPlacement);
8574
9079
  customPlacementRef.current = customPlacement;
8575
9080
  const allCustomPlacementsRef = react.useRef(allCustomPlacements);
@@ -9190,7 +9695,8 @@ var VectorViewport = react.forwardRef(
9190
9695
  container: el,
9191
9696
  scene,
9192
9697
  camera,
9193
- pointerEventsNone: interactiveRef.current
9698
+ pointerEventsNone: interactiveRef.current,
9699
+ rasterImageCanvas: imageCanvasRenderingRef.current
9194
9700
  });
9195
9701
  rendererRef.current = renderer;
9196
9702
  renderer.setInteractionState({
@@ -9242,6 +9748,9 @@ var VectorViewport = react.forwardRef(
9242
9748
  hoveredItemId: hoveredItemIdRef.current
9243
9749
  });
9244
9750
  }, [effectiveSelectedIds]);
9751
+ react.useEffect(() => {
9752
+ rendererRef.current?.setRasterImageCanvasRendering(imageCanvasRendering);
9753
+ }, [imageCanvasRendering]);
9245
9754
  react.useEffect(() => {
9246
9755
  const r = rendererRef.current;
9247
9756
  if (!r) return;