RealTimeDrawEngine: Change RenderFrame logic to use stage clone instead of OffscreenCanvas

This commit is contained in:
Tanish Manku committed 2025-03-06 22:53:46 -08:00
1 parent a605a2e51d
commit d5df7dbca1
1 file changed
+37 -42
@@ -88,6 +88,7 @@ export class RealTimeDrawEngine {
y: number;
},
) => void;
private offscreenRenderDiv: HTMLDivElement;
private onPreviewCopyCallback?: (previewCopy: Konva.Image) => void; // New Callback
@@ -184,6 +185,8 @@ export class RealTimeDrawEngine {
fill: "white",
});
this.offscreenRenderDiv = document.createElement("div");
this.mediaLayerRef.add(this.captureCanvas);
this.mediaLayerRef.add(this.previewCanvas);
// send back
@@ -785,6 +788,27 @@ export class RealTimeDrawEngine {
}
}
private cloneStageForRender(stage: Konva.Stage, layerOfInterest: Konva.Layer): Konva.Stage {
const stageClone = new Konva.Stage({
width: stage.width(),
height: stage.height(),
container: this.offscreenRenderDiv,
});
const renderLayer = new Konva.Layer();
// Clone all the nodes then reset them to render right
layerOfInterest.getChildren().forEach((node) => {
const dupNode = node.clone();
dupNode.strokeWidth(0);
renderLayer.add(dupNode);
});
stageClone.add(renderLayer);
return stageClone;
}
private async renderFrame(config: {
layerOfInterest: Konva.Layer; // layer where the element that you want to clip lives.
// XY and height of a captureCanvas ( region of interest )
@@ -805,54 +829,25 @@ export class RealTimeDrawEngine {
const y = config.y !== undefined ? config.y : Math.floor(box.y);
const pixelRatio = config.pixelRatio || 1;
const container = config.layerOfInterest as Container<Group | Shape>;
const offScreenSceneCanvas = new OffScreenSceneCanvas({
width:
config.width || Math.ceil(box.width) || (stage ? stage.width() : 0),
height:
config.height ||
Math.ceil(box.height) ||
(stage ? stage.height() : 0),
// Clone the required layer from the stage
// Set the right details (like removing highlight stroke)
// Then render the cloned stage to a bitmap
const stageClone = this.cloneStageForRender(stage, config.layerOfInterest);
const stageBlob = await stageClone.toBlob({
x: x,
y: y,
width: config.width || Math.ceil(box.width),
height: config.height || Math.ceil(box.height),
pixelRatio: pixelRatio,
});
const context = offScreenSceneCanvas.getContext();
const buffer = new OffScreenSceneCanvas({
width:
offScreenSceneCanvas.width / offScreenSceneCanvas.pixelRatio +
Math.abs(x),
height:
offScreenSceneCanvas.height / offScreenSceneCanvas.pixelRatio +
Math.abs(y),
pixelRatio: offScreenSceneCanvas.pixelRatio,
});
context.save();
if (x || y) {
context.translate(-1 * x, -1 * y);
}
container.drawScene(offScreenSceneCanvas, undefined, buffer);
// Not a type mistake ... DO NOT FIX
// @ts-ignore
const offscreenCanvas = offScreenSceneCanvas._canvas as OffscreenCanvas;
let result = undefined;
}) as Blob;
// if config.test is true, the result is downloaded to the local files
// config.test = true;
if (config.test) {
const blob = await offscreenCanvas.convertToBlob({
quality: config.quality ?? 1.0,
type: "image/jpeg",
});
await FileUtilities.blobToFileJpeg(blob, "1");
result = blob;
} else {
result = offscreenCanvas.transferToImageBitmap();
await FileUtilities.blobToFileJpeg(stageBlob, "1");
}
context.restore();
const result = await createImageBitmap(stageBlob);
return result;
} catch (error) {
throw error;