From c3fbc4eac9dd18ae6d90d255bd1795dedfd7cce3 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Mon, 24 Oct 2022 20:40:06 -0700 Subject: [PATCH] Fix image flickering while Imaginate layers generate --- frontend/src/state-providers/portfolio.ts | 13 +++++++------ frontend/src/utility-functions/imaginate.ts | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/frontend/src/state-providers/portfolio.ts b/frontend/src/state-providers/portfolio.ts index b39462a4..b06235de 100644 --- a/frontend/src/state-providers/portfolio.ts +++ b/frontend/src/state-providers/portfolio.ts @@ -2,7 +2,7 @@ import { reactive, readonly } from "vue"; import { downloadFileText, downloadFileBlob, upload } from "@/utility-functions/files"; -import { imaginateGenerate, imaginateCheckConnection, imaginateTerminate } from "@/utility-functions/imaginate"; +import { imaginateGenerate, imaginateCheckConnection, imaginateTerminate, preloadAndSetImaginateBlobURL } from "@/utility-functions/imaginate"; import { rasterizeSVG } from "@/utility-functions/rasterization"; import { type Editor } from "@/wasm-communication/editor"; import { @@ -75,9 +75,7 @@ export function createPortfolioState(editor: Editor) { // Rasterize the SVG to an image file image = await rasterizeSVG(baseImage.svg, baseImage.size[0], baseImage.size[1], "image/png"); - const blobURL = URL.createObjectURL(image); - - editor.instance.setImaginateBlobURL(documentId, layerPath, blobURL, baseImage.size[0], baseImage.size[1]); + preloadAndSetImaginateBlobURL(editor, image, documentId, layerPath, baseImage.size[0], baseImage.size[1]); } imaginateGenerate(parameters, image, hostname, refreshFrequency, documentId, layerPath, editor); @@ -94,9 +92,12 @@ export function createPortfolioState(editor: Editor) { const blobURL = URL.createObjectURL(blob); - const image = await createImageBitmap(blob); + // Pre-decode the image so it is ready to be drawn instantly once it's placed into the viewport SVG + const image = new Image(); + image.src = blobURL; + await image.decode(); - editor.instance.setImageBlobURL(updateImageData.documentId, element.path, blobURL, image.width, image.height); + editor.instance.setImageBlobURL(updateImageData.documentId, element.path, blobURL, image.naturalWidth, image.naturalHeight); }); }); editor.subscriptions.subscribeJsMessage(TriggerRevokeBlobUrl, async (triggerRevokeBlobUrl) => { diff --git a/frontend/src/utility-functions/imaginate.ts b/frontend/src/utility-functions/imaginate.ts index f37bcf5e..6d5098d7 100644 --- a/frontend/src/utility-functions/imaginate.ts +++ b/frontend/src/utility-functions/imaginate.ts @@ -73,8 +73,7 @@ export async function imaginateGenerate( editor.instance.setImaginateGeneratingStatus(documentId, layerPath, percent, newStatus); // Send the backend a blob URL for the final image - const blobURL = URL.createObjectURL(blob); - editor.instance.setImaginateBlobURL(documentId, layerPath, blobURL, parameters.resolution.x, parameters.resolution.y); + preloadAndSetImaginateBlobURL(editor, blob, documentId, layerPath, parameters.resolution.x, parameters.resolution.y); // Send the backend the blob data to be stored persistently in the layer const u8Array = new Uint8Array(await blob.arrayBuffer()); @@ -112,6 +111,17 @@ export async function imaginateCheckConnection(hostname: string, editor: Editor) editor.instance.setImaginateServerStatus(serverReached); } +export async function preloadAndSetImaginateBlobURL(editor: Editor, blob: Blob, documentId: bigint, layerPath: BigUint64Array, width: number, height: number): Promise { + const blobURL = URL.createObjectURL(blob); + + // Pre-decode the image so it is ready to be drawn instantly once it's placed into the viewport SVG + const image = new Image(); + image.src = blobURL; + await image.decode(); + + editor.instance.setImaginateBlobURL(documentId, layerPath, blobURL, width, height); +} + // ABORTING AND RESETTING HELPERS function abortAndResetGenerating(): void { @@ -148,8 +158,7 @@ function scheduleNextPollingUpdate( const [blob, percentComplete] = await pollImage(hostname); if (terminated) return; - const blobURL = URL.createObjectURL(blob); - editor.instance.setImaginateBlobURL(documentId, layerPath, blobURL, resolution.x, resolution.y); + preloadAndSetImaginateBlobURL(editor, blob, documentId, layerPath, resolution.x, resolution.y); editor.instance.setImaginateGeneratingStatus(documentId, layerPath, percentComplete, "Generating"); scheduleNextPollingUpdate(interval, nextTimeoutBegan, 0, editor, hostname, documentId, layerPath, resolution);