61 lines
3.4 KiB
JavaScript
61 lines
3.4 KiB
JavaScript
import { api } from "../../scripts/api.js";
|
|
import { app } from "../../scripts/app.js";
|
|
import { executionId } from "./workspace_flow.js";
|
|
import { T } from "./i18n.js";
|
|
import {uploadImageWithProgress} from './upload_transport.js?v=stability1';
|
|
|
|
export function installResultAdoption(node, crop) {
|
|
// Saved workflows may still contain the old feedback socket and wire.
|
|
const removeLegacyInput = () => {
|
|
const index = node.inputs?.findIndex(input => input.name === "result");
|
|
if (index >= 0) node.removeInput(index);
|
|
};
|
|
removeLegacyInput();
|
|
const configured = node.onConfigure;
|
|
node.onConfigure = function () {
|
|
const result = configured?.apply(this, arguments);
|
|
removeLegacyInput();
|
|
return result;
|
|
};
|
|
node.adachiAdoptCrop = async (file, origin, {signal,onProgress}={}) => {
|
|
const editor = crop.editor, region = crop.region;
|
|
if (!editor.ready || !region.locked) throw Error(T("Select a crop region before adopting a result"));
|
|
if (crop.busy || editor.stroke) throw Error(T("Finish editing before adopting a result"));
|
|
if (origin && (origin.mode !== "crop" || String(origin.source) !== executionId(app.rootGraph||app.graph,node) || origin.job !== region.job)) {
|
|
throw Error(T("This result belongs to another crop; generate a result for the current region"));
|
|
}
|
|
if (file.size > 64 * 1024 * 1024) throw Error(T("File is too large (max 64 MB)"));
|
|
signal?.throwIfAborted();
|
|
const controller=crop.adoptController=new AbortController(),abort=()=>controller.abort();
|
|
signal?.addEventListener('abort',abort,{once:true});
|
|
crop.busy = true; crop.sync();
|
|
const objectUrl = URL.createObjectURL(file);
|
|
try {
|
|
const image = new Image(); image.src = objectUrl; await image.decode();
|
|
controller.signal.throwIfAborted();
|
|
if (image.width !== region.width || image.height !== region.height) {
|
|
throw Error(T("Result dimensions must match the selected crop"));
|
|
}
|
|
const body = new FormData();
|
|
body.append("image", file, `adopted-${crypto.randomUUID()}.png`);
|
|
body.append("type", "input"); body.append("subfolder", "adachi-inpaint-layers");
|
|
const uploaded = await uploadImageWithProgress(api,body,onProgress,{signal:controller.signal});
|
|
if (typeof uploaded.name !== "string" || !uploaded.name) throw Error(T("Upload failed"));
|
|
if (editor.destroyed || crop.mode !== "crop" || crop.region.job !== region.job) {
|
|
throw Error(T("The crop changed while adopting the result"));
|
|
}
|
|
const descriptor = {filename:uploaded.name, subfolder:uploaded.subfolder || "", type:"input"};
|
|
await crop.accept({job:region.job, image:descriptor}, {allowBusy:true, image});
|
|
const name = descriptor.subfolder ? `${descriptor.subfolder}/${descriptor.filename}` : descriptor.filename;
|
|
if (crop.widgets.layer_image.value !== name) {
|
|
// accept() may have skipped silently (busy / changed job / duplicate).
|
|
throw Error(T("The result was not applied; the crop or layer state changed"));
|
|
}
|
|
editor.status("");
|
|
} finally {
|
|
signal?.removeEventListener('abort',abort);if(crop.adoptController===controller)crop.adoptController=null;
|
|
URL.revokeObjectURL(objectUrl); crop.busy = false; crop.sync();
|
|
}
|
|
};
|
|
}
|