wip working preferences, wip passing image on hidden widget with serialize

This commit is contained in:
Enrico
2024-10-15 17:55:58 +02:00
parent d83a1ad6e5
commit 90bdb4d657
7 changed files with 397 additions and 77 deletions
+8 -5
View File
@@ -43,6 +43,7 @@ class Compositor4:
"hidden": {
"extra_pnginfo": "EXTRA_PNGINFO",
"node_id": "UNIQUE_ID",
"test":"STRING"
},
}
@@ -56,7 +57,8 @@ class Compositor4:
node_id = kwargs.pop('node_id', None)
imageName = kwargs.get('imageName', "new.png")
imageName = kwargs.get('test', "new.png")
#compositionName = kwargs.get('test', "new.png")
config = kwargs.get('config', "default")
padding = config["padding"]
@@ -92,15 +94,16 @@ class Compositor4:
}
# break and send a message to the gui as if it was "executed" below
detail = {"output": ui, "node": node_id}
PromptServer.instance.send_sync("compositor_init", detail)
# detail = {"output": ui, "node": node_id}
# PromptServer.instance.send_sync("compositor_init", detail)
imageExists = folder_paths.exists_annotated_filepath(imageName)
# block when config changed
if imageName == "new.png" or not imageExists or configChanged:
#if imageName == "new.png" or not imageExists or configChanged:
if not imageExists or configChanged:
return {
"ui": ui,
"result": (ExecutionBlocker(None), ExecutionBlocker(None))
"result": (ExecutionBlocker(None), ExecutionBlocker(None))
}
image_path = folder_paths.get_annotated_filepath(imageName)
+38
View File
@@ -1,3 +1,4 @@
import { api } from "../../scripts/api.js";
import { Toolbar, ICON_URLS, BUTTON_INDICES, fetchSVGIcon } from './toolbar4.js';
class Compositor4 {
@@ -292,6 +293,7 @@ class Compositor4 {
this.fabricCanvas.renderAll();
}
/** downloads the iamge */
downloadFile(content, filename) {
let link = document.createElement("a");
@@ -317,6 +319,7 @@ class Compositor4 {
}
}
/** saves the image as base64*/
exportAsBase64() {
return this.fabricCanvas.toDataURL({
format: "png",
@@ -371,6 +374,41 @@ class Compositor4 {
// Redraw the new images on the canvas
this.setupImages();
}
dataURLToBlob(dataURL){
const parts = dataURL.split(',');
const mime = parts[0].match(/:(.*?);/)[1];
const binary = atob(parts[1]);
const array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: mime});
}
// take #compositor3.js as example and make a version of uploadImage that takes the ouptupt of exportAsBase64and uploads it to the /upload/image endpoint, make the method async, keep the naming convention and the logic to hanle the subfolder
async uploadImage(dataURL){
const b64 = this.dataURLToBlob(dataURL);
const UPLOAD_ENDPOINT = "/upload/image";
const name = `${+new Date()}.png`;
const file = new File([b64], name);
const body = new FormData();
body.append("image", file);
body.append("subfolder", "compositor");
body.append("type", "temp");
const result = await api.fetchApi(UPLOAD_ENDPOINT, {
method: "POST",
body,
})
return await result.json()
}
}
export default Compositor4;
+48 -34
View File
@@ -1,6 +1,8 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
import Compositor4 from "./compositor4.js";
import { fabric } from "./fabric.js";
import {PREFERENCES, addCompositorPreferences, getPreferences} from "./compositor4preferences.js";
import Init from "./init.js";
const COMPOSITOR = Symbol();
@@ -21,23 +23,26 @@ function getCompositorWidget(node, widgetName) {
app.registerExtension({
name: "Comfy.Compositor4",
// async getCustomWidgets(app) {
// return {
// async COMPOSITOR(node, inputName, inputData, app) {
// const container = document.createElement("div");
// await this.initEditor(container);
// async getCustomWidgets(app) {
// return {
// async COMPOSITOR(node, inputName, inputData, app) {
// /**
// * NOTE: hideOnZoom:false FIXES not being able to take screenshot and disappearing on zoom out
// * but creates some inconsistencies as lines get too small to be rendered properly
// */
// return {widget: node.addDOMWidget(inputName, "COMPOSITOR4", container, {hideOnZoom: false})};
// },
// };
// },
// const container = document.createElement("div");
// await this.initEditor(container);
// /**
// * NOTE: hideOnZoom:false FIXES not being able to take screenshot and disappearing on zoom out
// * but creates some inconsistencies as lines get too small to be rendered properly
// */
// return {widget: node.addDOMWidget(inputName, "COMPOSITOR4", container, {hideOnZoom: false})};
// },
// };
// },
async setup(app) {
addCompositorPreferences(PREFERENCES);
function executingMessageHandler(event) {}
function executedMessageHandler(event, a, b) {}
@@ -82,31 +87,40 @@ app.registerExtension({
el.style.backgroundColor = "transparent";
el.width = 800;
el.height = 600;
el.id="compositor4container";
el.id = "compositor4container";
el.value = "foobar.jpg";
const imageNameWidget = getCompositorWidget(node, "imageName");
node.editorWidget = node.addDOMWidget("test", "test", el, {
serialize: false,
serialize: true,
hideOnZoom: false,
resizable: false,
getValue() {
console.log("getValue", el.value);
return el.value;
},
setValue(v2) {
// imageNameWidget.value = v2;
console.log("setValue", v2);
el.value = v2;
},
});
// const originalSerializeValue = node.editorWidget.serializeValue;
// node.editorWidget.serializeValue = (e) => {
// console.log("serializeValue",e);
// //return el.value;
// };
const init = new Init();
const compositor = await init.initEditor(el);
console.log("compositor", compositor);
node.setSize(compositor.getWidgetDimensions());
const preferences = getPreferences()
const editor = await init.initEditor(el, preferences);
console.log("editor", editor);
node.setSize(editor.getWidgetDimensions());
node.setDirtyCanvas(true, true);
}
},
});
+285
View File
@@ -0,0 +1,285 @@
import { app } from "../../scripts/app.js";
const PREFERENCES = {
composition: {
fill: "#444444", // Dark gray color for the rectangle
stroke: "green", // Green border
strokeWidth: 1,
},
toolbar: {
fill: "#666666",
height: 40,
position: { left: 0, top: 0 },
buttonSpacing: 4,
iconSize: 40, // Set the icon size to 30
},
fabricCanvas: {
backgroundColor: "#555555", // Darker gray color for the canvas background
},
equalizeHeight: {
enabled: true,
},
snapToGrid: {
gridSize: 20,
enabled: false,
isGridVisible: false,
},
ignoreTransparentPixels: {
enabled: false,
},
erosColor: "magenta", // Add eros color preference
activeBorderColor: "magenta", // Border color when button is active
inactiveBorderColor: "black", // Border color when button is inactive
toggledBorderColor: "orange", // Border color when button is toggled
standalone: false, // whether we are testing this in index.html or in the comfy editor
};
function addCompositorPreferences(preferences) {
app.ui.settings.addSetting({
id: "Compositor4.Composition.FILL",
name: "Composition Fill",
tooltip: "Fill color for the composition rectangle",
type: "text",
defaultValue: preferences.composition.fill,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Composition.STROKE",
name: "Composition Stroke",
tooltip: "Stroke color for the composition rectangle",
type: "text",
defaultValue: preferences.composition.stroke,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Composition.STROKE_WIDTH",
name: "Composition Stroke Width",
tooltip: "Stroke width for the composition rectangle",
type: "number",
defaultValue: preferences.composition.strokeWidth,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Toolbar.FILL",
name: "Toolbar Fill",
tooltip: "Fill color for the toolbar",
type: "text",
defaultValue: preferences.toolbar.fill,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Toolbar.HEIGHT",
name: "Toolbar Height",
tooltip: "Height of the toolbar",
type: "number",
defaultValue: preferences.toolbar.height,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Toolbar.POSITION",
name: "Toolbar Position",
tooltip: "Position of the toolbar",
type: "object",
defaultValue: preferences.toolbar.position,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Toolbar.BUTTON_SPACING",
name: "Toolbar Button Spacing",
tooltip: "Spacing between toolbar buttons",
type: "number",
defaultValue: preferences.toolbar.buttonSpacing,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Toolbar.ICON_SIZE",
name: "Toolbar Icon Size",
tooltip: "Size of the toolbar icons",
type: "number",
defaultValue: preferences.toolbar.iconSize,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.FabricCanvas.BACKGROUND_COLOR",
name: "Fabric Canvas Background Color",
tooltip: "Background color for the fabric canvas",
type: "text",
defaultValue: preferences.fabricCanvas.backgroundColor,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.EqualizeHeight.ENABLED",
name: "Equalize Height Enabled",
tooltip: "Enable or disable equalize height",
type: "boolean",
defaultValue: preferences.equalizeHeight.enabled,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.SnapToGrid.GRID_SIZE",
name: "Snap to Grid Size",
tooltip: "Grid size for snap to grid",
type: "number",
defaultValue: preferences.snapToGrid.gridSize,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.SnapToGrid.ENABLED",
name: "Snap to Grid Enabled",
tooltip: "Enable or disable snap to grid",
type: "boolean",
defaultValue: preferences.snapToGrid.enabled,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.SnapToGrid.IS_GRID_VISIBLE",
name: "Snap to Grid Visibility",
tooltip: "Visibility of the snap to grid",
type: "boolean",
defaultValue: preferences.snapToGrid.isGridVisible,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.IgnoreTransparentPixels.ENABLED",
name: "Ignore Transparent Pixels Enabled",
tooltip: "Enable or disable ignoring transparent pixels",
type: "boolean",
defaultValue: preferences.ignoreTransparentPixels.enabled,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.ErosColor",
name: "Eros Color",
tooltip: "Color for eros",
type: "text",
defaultValue: preferences.erosColor,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.ActiveBorderColor",
name: "Active Border Color",
tooltip: "Border color when button is active",
type: "text",
defaultValue: preferences.activeBorderColor,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.InactiveBorderColor",
name: "Inactive Border Color",
tooltip: "Border color when button is inactive",
type: "text",
defaultValue: preferences.inactiveBorderColor,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.ToggledBorderColor",
name: "Toggled Border Color",
tooltip: "Border color when button is toggled",
type: "text",
defaultValue: preferences.toggledBorderColor,
onChange: (newVal, oldVal) => {
// Handle change
},
});
app.ui.settings.addSetting({
id: "Compositor4.Standalone",
name: "Standalone Mode",
tooltip: "Whether we are testing this in index.html or in the comfy editor",
type: "boolean",
defaultValue: preferences.standalone,
onChange: (newVal, oldVal) => {
// Handle change
},
});
}
function getPreferences() {
return {
composition: {
fill: app.ui.settings.getSettingValue("Compositor4.Composition.FILL", "#444444"),
stroke: app.ui.settings.getSettingValue("Compositor4.Composition.STROKE", "green"),
strokeWidth: app.ui.settings.getSettingValue("Compositor4.Composition.STROKE_WIDTH", 1),
},
toolbar: {
fill: app.ui.settings.getSettingValue("Compositor4.Toolbar.FILL", "#666666"),
height: app.ui.settings.getSettingValue("Compositor4.Toolbar.HEIGHT", 40),
position: app.ui.settings.getSettingValue("Compositor4.Toolbar.POSITION", { left: 0, top: 0 }),
buttonSpacing: app.ui.settings.getSettingValue("Compositor4.Toolbar.BUTTON_SPACING", 4),
iconSize: app.ui.settings.getSettingValue("Compositor4.Toolbar.ICON_SIZE", 40),
},
fabricCanvas: {
backgroundColor: app.ui.settings.getSettingValue("Compositor4.FabricCanvas.BACKGROUND_COLOR", "#555555"),
},
equalizeHeight: {
enabled: app.ui.settings.getSettingValue("Compositor4.EqualizeHeight.ENABLED", true),
},
snapToGrid: {
gridSize: app.ui.settings.getSettingValue("Compositor4.SnapToGrid.GRID_SIZE", 20),
enabled: app.ui.settings.getSettingValue("Compositor4.SnapToGrid.ENABLED", false),
isGridVisible: app.ui.settings.getSettingValue("Compositor4.SnapToGrid.IS_GRID_VISIBLE", false),
},
ignoreTransparentPixels: {
enabled: app.ui.settings.getSettingValue("Compositor4.IgnoreTransparentPixels.ENABLED", false),
},
erosColor: app.ui.settings.getSettingValue("Compositor4.ErosColor", "magenta"),
activeBorderColor: app.ui.settings.getSettingValue("Compositor4.ActiveBorderColor", "magenta"),
inactiveBorderColor: app.ui.settings.getSettingValue("Compositor4.InactiveBorderColor", "black"),
toggledBorderColor: app.ui.settings.getSettingValue("Compositor4.ToggledBorderColor", "orange"),
standalone: app.ui.settings.getSettingValue("Compositor4.Standalone", false),
};
}
// Call the function to add settings
export { addCompositorPreferences, PREFERENCES, getPreferences};
+1
View File
@@ -45,6 +45,7 @@
activeBorderColor: "magenta", // Border color when button is active
inactiveBorderColor: "black", // Border color when button is inactive
toggledBorderColor: "orange", // Border color when button is toggled
standalone:true,
};
const config = JSON.stringify({
+3 -36
View File
@@ -1,45 +1,12 @@
import Compositor4 from "./compositor4.js";
import { fabric } from "./fabric.js";
class Init {
async initEditor(container) {
async initEditor(container, preferences) {
// const query = 'cats'; // Change this to your desired search query
const query = "matisse"; // Change this to your desired search query
try {
const images = await this.fetchArtInstituteImages(query, 6);
const PREFERENCES = {
composition: {
fill: "#444444", // Dark gray color for the rectangle
stroke: "green", // Green border
strokeWidth: 1,
},
toolbar: {
fill: "#666666",
height: 40,
position: { left: 0, top: 0 },
buttonSpacing: 4,
iconSize: 40, // Set the icon size to 30
},
fabricCanvas: {
backgroundColor: "#555555", // Darker gray color for the canvas background
},
equalizeHeight: {
enabled: true,
},
snapToGrid: {
gridSize: 20,
enabled: false,
isGridVisible: false,
},
ignoreTransparentPixels: {
enabled: false,
},
erosColor: "magenta", // Add eros color preference
activeBorderColor: "magenta", // Border color when button is active
inactiveBorderColor: "black", // Border color when button is inactive
toggledBorderColor: "orange", // Border color when button is toggled
};
const config = JSON.stringify({
width: 800,
height: 600,
@@ -52,7 +19,7 @@ class Init {
});
// const container = document.createElement("div");
// container.id = "compositor4";
const compositor = new Compositor4(container, config, PREFERENCES);
const compositor = new Compositor4(container, config, preferences);
// trigger the executed event
const event = new CustomEvent("executed", { detail: config });
document.dispatchEvent(event);
+14 -2
View File
@@ -1,3 +1,5 @@
export const ICON_URLS = {
loadPreset: "https://icons.getbootstrap.com/assets/icons/file-earmark-arrow-up.svg",
savePreset: "https://icons.getbootstrap.com/assets/icons/file-earmark-arrow-down.svg",
@@ -203,10 +205,20 @@ export class Toolbar {
}
async addExportButton() {
const onClick = () => {
const onClick = async() => {
console.log("Exporting image...");
const base64Image = this.compositor.exportAsBase64();
this.compositor.downloadFile(base64Image, `${this.compositor.seed}.png`);
//
if(this.preferences.standalone){
this.compositor.downloadFile(base64Image, `${this.compositor.seed}.png`);
}else{
const result = await this.compositor.uploadImage(base64Image);
//
this.compositor.containerEl.value = `compositor/${result.name} [temp]`;
console.log(result);
}
};
await this.addToolbarButton(ICON_URLS.export, onClick, BUTTON_INDICES.indexOf("export"));