Preserve mask when sending output into image upload

This commit is contained in:
space-nuko
2023-05-27 22:39:07 -05:00
parent cb9e8540a0
commit 3b9d4533f9
5 changed files with 59 additions and 28 deletions

View File

@@ -146,9 +146,9 @@
if (entry.extraData?.workflowTitle != null) { if (entry.extraData?.workflowTitle != null) {
message = `${entry.extraData.workflowTitle}` message = `${entry.extraData.workflowTitle}`
} }
if (subgraphs) { if (subgraphs) {
const subgraphsString = subgraphs.join(', ') const subgraphsString = subgraphs.join(', ')
if (subgraphsString.length > 0)
message += ` (${subgraphsString})` message += ` (${subgraphsString})`
} }

View File

@@ -2,7 +2,19 @@
export type MaskCanvasData = { export type MaskCanvasData = {
hasMask: boolean, hasMask: boolean,
maskCanvas: HTMLCanvasElement | null, maskCanvas: HTMLCanvasElement | null,
curLineGroup: LineGroup,
redoCurLines: LineGroup,
} }
export type LinePoint = {
x: number,
y: number
}
export interface Line {
size?: number,
points: LinePoint[]
}
export type LineGroup = Line[];
</script> </script>
<script lang="ts"> <script lang="ts">
@@ -16,6 +28,7 @@
const dispatch = createEventDispatcher<{ const dispatch = createEventDispatcher<{
change: MaskCanvasData; change: MaskCanvasData;
release: MaskCanvasData; release: MaskCanvasData;
loaded: MaskCanvasData
}>(); }>();
let canvasCursor: string | undefined = undefined; let canvasCursor: string | undefined = undefined;
@@ -87,8 +100,8 @@
isImageLoaded = false; isImageLoaded = false;
original = null; original = null;
renders = [] renders = []
curLineGroup = []; // curLineGroup = [];
redoCurLines = [] // redoCurLines = []
imageWidth = 512; imageWidth = 512;
imageHeight = 512; imageHeight = 512;
scale = 1.0; scale = 1.0;
@@ -96,12 +109,14 @@
} }
let loadedFileURL: string | null = null let loadedFileURL: string | null = null
let dispatchLoaded: boolean = false;
$: if (fileURL !== loadedFileURL) { $: if (fileURL !== loadedFileURL) {
clearState(); clearState();
if (fileURL) { if (fileURL) {
loadImage(fileURL).then(i => { loadImage(fileURL).then(i => {
original = i; original = i;
isImageLoaded = true; isImageLoaded = true;
dispatchLoaded = true;
}) })
.catch(i => { .catch(i => {
isImageLoaded = false; isImageLoaded = false;
@@ -119,6 +134,28 @@
[imageWidth, imageHeight] = getCurrentWidthAndHeight(isImageLoaded, original) [imageWidth, imageHeight] = getCurrentWidthAndHeight(isImageLoaded, original)
scale = initScale(imageWidth, imageHeight) scale = initScale(imageWidth, imageHeight)
initImagePos() initImagePos()
// in case mask strokes were preserved after new image load
// (use case: sending an inpainted image back while reusing the same mask)
tick().then(() => {
loaded();
})
}
function loaded() {
if (!dispatchLoaded)
return;
dispatchLoaded = false;
redrawCurLines()
hasMask = curLineGroup.length > 0;
console.warn("[MaskCanvas] LOADED", maskCanvas, hasMask)
dispatch("loaded", {
hasMask,
maskCanvas,
curLineGroup,
redoCurLines
})
} }
$: hasMask = curLineGroup.length > 0; $: hasMask = curLineGroup.length > 0;
@@ -143,21 +180,13 @@
minScale = scale; minScale = scale;
} }
type LinePoint = {
x: number,
y: number
}
interface Line {
size?: number,
points: LinePoint[]
}
type LineGroup = Line[];
function drawOnCurrentRender(lineGroup: LineGroup) { function drawOnCurrentRender(lineGroup: LineGroup) {
draw(lineGroup) draw(lineGroup)
dispatch("change", { dispatch("change", {
hasMask, hasMask,
maskCanvas maskCanvas,
curLineGroup,
redoCurLines
}) })
} }
@@ -214,6 +243,10 @@
}) })
} }
function redrawCurLines() {
drawOnCurrentRender(curLineGroup || [])
}
$: if (canvas && original) { $: if (canvas && original) {
console.warn("INITCANVAS", imageWidth, imageHeight, original.src) console.warn("INITCANVAS", imageWidth, imageHeight, original.src)
maskCanvas = document.createElement("canvas"); maskCanvas = document.createElement("canvas");
@@ -222,7 +255,7 @@
maskCanvas.height = imageHeight; maskCanvas.height = imageHeight;
canvas.width = imageWidth; canvas.width = imageWidth;
canvas.height = imageHeight; canvas.height = imageHeight;
drawOnCurrentRender([]) redrawCurLines() // no react on curLineGroup
} }
function getCurrentWidthAndHeight(isImageLoaded: boolean, original: HTMLImageElement | null) { function getCurrentWidthAndHeight(isImageLoaded: boolean, original: HTMLImageElement | null) {
@@ -421,11 +454,12 @@
return; return;
isDrawing = false; isDrawing = false;
dispatch("release", { hasMask, maskCanvas }) dispatch("release", { hasMask, maskCanvas, curLineGroup, redoCurLines })
} }
function dispatchRelease() { function dispatchRelease() {
dispatch("release", { hasMask, maskCanvas }) updateMaskImage()
dispatch("release", { hasMask, maskCanvas, curLineGroup, redoCurLines })
} }
</script> </script>

View File

@@ -99,9 +99,9 @@ export default class ComfyPickImageNode extends ComfyGraphNode {
override onExecute() { override onExecute() {
const data = this.getInputData(0) const data = this.getInputData(0)
let index = this.getInputData(1); let index = this.getInputData(1);
if (this.properties.imageTagFilter && Array.isArray(data)) if (this.properties.imageTagFilter != "" && Array.isArray(data))
index = data.findIndex(i => i.tags?.includes(this.properties.imageTagFilter)) index = data.findIndex(i => i.tags?.includes(this.properties.imageTagFilter))
else else if (index == null)
index = 0; index = 0;
this.setValue(data, index); this.setValue(data, index);

View File

@@ -6,6 +6,7 @@ import ImageUploadWidget from "$lib/widgets/ImageUploadWidget.svelte";
import type { ComfyWidgetProperties } from "./ComfyWidgetNode"; import type { ComfyWidgetProperties } from "./ComfyWidgetNode";
import ComfyWidgetNode from "./ComfyWidgetNode"; import ComfyWidgetNode from "./ComfyWidgetNode";
import { get, writable, type Writable } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
import { type LineGroup } from "$lib/components/MaskCanvas.svelte"
export interface ComfyImageUploadNodeProperties extends ComfyWidgetProperties { export interface ComfyImageUploadNodeProperties extends ComfyWidgetProperties {
maskCount: number maskCount: number

View File

@@ -5,8 +5,6 @@
import Row from "$lib/components/gradio/app/Row.svelte"; import Row from "$lib/components/gradio/app/Row.svelte";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { Button } from "@gradio/button"; import { Button } from "@gradio/button";
import ImageUpload from "$lib/components/ImageUpload.svelte";
import { import {
type ComfyBoxImageMetadata, type ComfyBoxImageMetadata,
comfyFileToComfyBoxMetadata, comfyFileToComfyBoxMetadata,
@@ -16,13 +14,12 @@
convertComfyOutputToComfyURL, convertComfyOutputToComfyURL,
batchUploadBlobsToComfyUI, batchUploadBlobsToComfyUI,
canvasToBlob, canvasToBlob,
basename basename
} from "$lib/utils"; } from "$lib/utils";
import ImageUpload from "$lib/components/ImageUpload.svelte";
import notify from "$lib/notify"; import notify from "$lib/notify";
import { ImageViewer } from "$lib/ImageViewer"; import { ImageViewer } from "$lib/ImageViewer";
import MaskCanvas, { type MaskCanvasData } from "$lib/components/MaskCanvas.svelte"; import MaskCanvas, { type LineGroup, type MaskCanvasData } from "$lib/components/MaskCanvas.svelte";
import type { ComfyImageUploadNode } from "$lib/nodes/widgets"; import type { ComfyImageUploadNode } from "$lib/nodes/widgets";
import { tick } from "svelte"; import { tick } from "svelte";
@@ -65,7 +62,7 @@
async function onMaskReleased(e: CustomEvent<MaskCanvasData>) { async function onMaskReleased(e: CustomEvent<MaskCanvasData>) {
const data = e.detail; const data = e.detail;
if (data.maskCanvas && data.hasMask) { if (data.maskCanvas != null && data.hasMask) {
await saveMask(data.maskCanvas) await saveMask(data.maskCanvas)
} }
} }
@@ -203,7 +200,6 @@
$: canEdit = status === "empty" || status === "uploaded"; $: canEdit = status === "empty" || status === "uploaded";
function onChange(e: CustomEvent<ComfyImageLocation[]>) { function onChange(e: CustomEvent<ComfyImageLocation[]>) {
} }
</script> </script>
@@ -229,7 +225,7 @@
{#if _value && canMask} {#if _value && canMask}
{@const comfyURL = convertComfyOutputToComfyURL(_value[0])} {@const comfyURL = convertComfyOutputToComfyURL(_value[0])}
<div class="mask-canvas-wrapper" style:display={editMask ? "block" : "none"}> <div class="mask-canvas-wrapper" style:display={editMask ? "block" : "none"}>
<MaskCanvas bind:this={maskCanvasComp} fileURL={comfyURL} on:release={onMaskReleased} /> <MaskCanvas bind:this={maskCanvasComp} fileURL={comfyURL} on:release={onMaskReleased} on:loaded={onMaskReleased} />
</div> </div>
{/if} {/if}
<div style:display={(canMask && editMask) ? "none" : "block"}> <div style:display={(canMask && editMask) ? "none" : "block"}>