Preserve mask when sending output into image upload
This commit is contained in:
@@ -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})`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"}>
|
||||||
|
|||||||
Reference in New Issue
Block a user