Fix Imaginate by porting its JS roundtrip code to graph-based async execution in Rust (#1250)

* Create asynchronous rust imaginate node

* Make a first imaginate request via rust

* Implement parsing of imaginate API result image

* Stop refresh timer from affecting imaginate progress requests

* Add cargo-about clarification for rustls-webpki

* Delete imaginate.ts and all uses of its functions

* Add imaginate img2img feature

* Fix imaginate random seed button

* Fix imaginate ui inferring non-custom resolutions

* Fix the imaginate progress indicator

* Remove ImaginatePreferences from being compiled into node graph

* Regenerate imaginate only when hitting button

* Add ability to terminate imaginate requests

* Add imaginate server check feature

* Do not compile wasm_bindgen bindings in graphite_editor for tests

* Address some review suggestions

- move wasm futures dependency in editor to the future-executor crate
- guard wasm-bindgen in editor behind a `wasm` feature flag
- dont make seed number input a slider
- remove poll_server_check from process_message function beginning
- guard wasm related code behind `cfg(target_arch = "wasm32")` instead
  of `cfg(test)`
- Call the imaginate idle states "Ready" and "Done" instead of "Nothing
  to do"
- Call the imaginate uploading state "Uploading Image" instead of
  "Uploading Input Image"
- Remove the EvalSyncNode

* Fix imaginate host name being restored between graphite instances

also change the progress status texts a bit.

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
nat-rix
2023-06-09 09:03:15 +02:00
committed by Keavon Chambers
co-authored by Keavon Chambers
parent a1c70c4d90
commit f76b850b9c
35 changed files with 1500 additions and 1326 deletions
-34
View File
@@ -3,7 +3,6 @@
import {writable} from "svelte/store";
import { downloadFileText, downloadFileBlob, upload, downloadFileURL } from "@graphite/utility-functions/files";
import { imaginateGenerate, imaginateCheckConnection, imaginateTerminate, updateBackendImage } from "@graphite/utility-functions/imaginate";
import { extractPixelData, imageToPNG, rasterizeSVG, rasterizeSVGCanvas } from "@graphite/utility-functions/rasterization";
import { type Editor } from "@graphite/wasm-communication/editor";
import {
@@ -13,8 +12,6 @@ import {
TriggerDownloadRaster,
TriggerDownloadTextFile,
TriggerImaginateCheckServerStatus,
TriggerImaginateGenerate,
TriggerImaginateTerminate,
TriggerImport,
TriggerOpenDocument,
TriggerRasterizeRegionBelowLayer,
@@ -85,37 +82,6 @@ export function createPortfolioState(editor: Editor) {
// Have the browser download the file to the user's disk
downloadFileBlob(name, blob);
});
editor.subscriptions.subscribeJsMessage(TriggerImaginateCheckServerStatus, async (triggerImaginateCheckServerStatus) => {
const { hostname } = triggerImaginateCheckServerStatus;
imaginateCheckConnection(hostname, editor);
});
editor.subscriptions.subscribeJsMessage(TriggerImaginateGenerate, async (triggerImaginateGenerate) => {
const { documentId, layerPath, nodePath, hostname, refreshFrequency, baseImage, maskImage, maskPaintMode, maskBlurPx, maskFillContent, parameters } = triggerImaginateGenerate;
// Handle img2img mode
let image: Blob | undefined;
if (parameters.denoisingStrength !== undefined && baseImage !== undefined) {
const buffer = new Uint8Array(baseImage.imageData.values()).buffer;
image = new Blob([buffer], { type: baseImage.mime });
updateBackendImage(editor, image, documentId, layerPath, nodePath);
}
// Handle layer mask
let mask: Blob | undefined;
if (maskImage !== undefined) {
// Rasterize the SVG to an image file
mask = await rasterizeSVG(maskImage.svg, maskImage.size[0], maskImage.size[1], "image/png");
}
imaginateGenerate(parameters, image, mask, maskPaintMode, maskBlurPx, maskFillContent, hostname, refreshFrequency, documentId, layerPath, nodePath, editor);
});
editor.subscriptions.subscribeJsMessage(TriggerImaginateTerminate, async (triggerImaginateTerminate) => {
const { documentId, layerPath, nodePath, hostname } = triggerImaginateTerminate;
imaginateTerminate(hostname, documentId, layerPath, nodePath, editor);
});
editor.subscriptions.subscribeJsMessage(UpdateImageData, (updateImageData) => {
updateImageData.imageData.forEach(async (element) => {
const buffer = new Uint8Array(element.imageData.values()).buffer;