mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2025-08-03 15:39:54 +08:00
Add support for pasting images into the graph
It can be useful to paste images from the clipboard directly into the node graph. This commit modifies copy and paste handling to support this. When an image file is found in the clipboard, we check whether an image node is selected. If so, paste the image into that node. Otherwise, a new node is created. If no image data are found in the clipboard, we call the original Litegraph paste. To ensure that onCopy and onPaste events are fired, we override Litegraph's ctrl+c and ctrl+v handling. Try to detect whether the pasted image is a real file on disk, or just pixel data copied from e.g. Photoshop. Pasted pixel data will be called 'image.png' and have a creation time of now. If it is simply pasted data, we store it in the subfolder /input/clipboard/. This also adds support for the subfolder property in the IMAGEUPLOAD widget.
This commit is contained in:
@@ -667,11 +667,40 @@ export class ComfyApp {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a handler on paste that extracts and loads workflows from pasted JSON data
|
||||
* Adds a handler on paste that extracts and loads images or workflows from pasted JSON data
|
||||
*/
|
||||
#addPasteHandler() {
|
||||
document.addEventListener("paste", (e) => {
|
||||
let data = (e.clipboardData || window.clipboardData).getData("text/plain");
|
||||
let data = (e.clipboardData || window.clipboardData);
|
||||
const items = data.items;
|
||||
|
||||
// Look for image paste data
|
||||
for (const item of items) {
|
||||
if (item.type.startsWith('image/')) {
|
||||
var imageNode = null;
|
||||
|
||||
// If an image node is selected, paste into it
|
||||
if (this.canvas.current_node &&
|
||||
this.canvas.current_node.is_selected &&
|
||||
ComfyApp.isImageNode(this.canvas.current_node)) {
|
||||
imageNode = this.canvas.current_node;
|
||||
}
|
||||
|
||||
// No image node selected: add a new one
|
||||
if (!imageNode) {
|
||||
const newNode = LiteGraph.createNode("LoadImage");
|
||||
newNode.pos = [...this.canvas.graph_mouse];
|
||||
imageNode = this.graph.add(newNode);
|
||||
this.graph.change();
|
||||
}
|
||||
const blob = item.getAsFile();
|
||||
imageNode.pasteFile(blob);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No image found. Look for node data
|
||||
data = data.getData("text/plain");
|
||||
let workflow;
|
||||
try {
|
||||
data = data.slice(data.indexOf("{"));
|
||||
@@ -687,9 +716,29 @@ export class ComfyApp {
|
||||
if (workflow && workflow.version && workflow.nodes && workflow.extra) {
|
||||
this.loadGraphData(workflow);
|
||||
}
|
||||
else {
|
||||
// Litegraph default paste
|
||||
this.canvas.pasteFromClipboard();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a handler on copy that serializes selected nodes to JSON
|
||||
*/
|
||||
#addCopyHandler() {
|
||||
document.addEventListener("copy", (e) => {
|
||||
// copy
|
||||
if (this.canvas.selected_nodes) {
|
||||
this.canvas.copyToClipboard();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle mouse
|
||||
*
|
||||
@@ -745,12 +794,6 @@ export class ComfyApp {
|
||||
const self = this;
|
||||
const origProcessKey = LGraphCanvas.prototype.processKey;
|
||||
LGraphCanvas.prototype.processKey = function(e) {
|
||||
const res = origProcessKey.apply(this, arguments);
|
||||
|
||||
if (res === false) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!this.graph) {
|
||||
return;
|
||||
}
|
||||
@@ -761,9 +804,10 @@ export class ComfyApp {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.type == "keydown") {
|
||||
if (e.type == "keydown" && !e.repeat) {
|
||||
|
||||
// Ctrl + M mute/unmute
|
||||
if (e.keyCode == 77 && e.ctrlKey) {
|
||||
if (e.key === 'm' && e.ctrlKey) {
|
||||
if (this.selected_nodes) {
|
||||
for (var i in this.selected_nodes) {
|
||||
if (this.selected_nodes[i].mode === 2) { // never
|
||||
@@ -776,7 +820,8 @@ export class ComfyApp {
|
||||
block_default = true;
|
||||
}
|
||||
|
||||
if (e.keyCode == 66 && e.ctrlKey) {
|
||||
// Ctrl + B bypass
|
||||
if (e.key === 'b' && e.ctrlKey) {
|
||||
if (this.selected_nodes) {
|
||||
for (var i in this.selected_nodes) {
|
||||
if (this.selected_nodes[i].mode === 4) { // never
|
||||
@@ -788,6 +833,28 @@ export class ComfyApp {
|
||||
}
|
||||
block_default = true;
|
||||
}
|
||||
|
||||
// Ctrl+C Copy
|
||||
if ((e.key === 'c') && (e.metaKey || e.ctrlKey)) {
|
||||
if (e.shiftKey) {
|
||||
this.copyToClipboard(true);
|
||||
block_default = true;
|
||||
}
|
||||
// Trigger default onCopy
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ctrl+V Paste
|
||||
if ((e.key === 'v') && (e.metaKey || e.ctrlKey)) {
|
||||
if (e.shiftKey) {
|
||||
this.pasteFromClipboard(true);
|
||||
block_default = true;
|
||||
}
|
||||
else {
|
||||
// Trigger default onPaste
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.graph.change();
|
||||
@@ -798,7 +865,8 @@ export class ComfyApp {
|
||||
return false;
|
||||
}
|
||||
|
||||
return res;
|
||||
// Fall through to Litegraph defaults
|
||||
return origProcessKey.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1110,6 +1178,7 @@ export class ComfyApp {
|
||||
this.#addDrawGroupsHandler();
|
||||
this.#addApiUpdateHandlers();
|
||||
this.#addDropHandler();
|
||||
this.#addCopyHandler();
|
||||
this.#addPasteHandler();
|
||||
this.#addKeyboardHandler();
|
||||
|
||||
|
Reference in New Issue
Block a user