diff --git a/js/Canvas.js b/js/Canvas.js index 3e73d20..ac66003 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -1,5 +1,3 @@ -import { app, ComfyApp } from "../../scripts/app.js"; -import { api } from "../../scripts/api.js"; import {removeImage} from "./db.js"; import {MaskTool} from "./MaskTool.js"; import {CanvasState} from "./CanvasState.js"; @@ -9,7 +7,6 @@ import {CanvasRenderer} from "./CanvasRenderer.js"; import {CanvasIO} from "./CanvasIO.js"; import {ImageReferenceManager} from "./ImageReferenceManager.js"; import {createModuleLogger} from "./utils/LoggerUtils.js"; -import { mask_editor_showing } from "./utils/mask_utils.js"; const log = createModuleLogger('Canvas'); @@ -464,142 +461,4 @@ export class Canvas { } log.info("Canvas destroyed"); } - - async startMaskEditor() { - const blob = await this.canvasLayers.getFlattenedCanvasAsBlob(); - if (!blob) { - log.warn("Canvas is empty, cannot open mask editor."); - return; - } - - try { - const formData = new FormData(); - const filename = `layerforge-mask-edit-${+new Date()}.png`; - formData.append("image", blob, filename); - formData.append("overwrite", "true"); - formData.append("type", "temp"); - - const response = await api.fetchApi("/upload/image", { - method: "POST", - body: formData, - }); - - if (!response.ok) { - throw new Error(`Failed to upload image: ${response.statusText}`); - } - const data = await response.json(); - - const img = new Image(); - img.src = api.apiURL(`/view?filename=${encodeURIComponent(data.name)}&type=${data.type}&subfolder=${data.subfolder}`); - await new Promise((res, rej) => { - img.onload = res; - img.onerror = rej; - }); - - this.node.imgs = [img]; - - ComfyApp.copyToClipspace(this.node); - ComfyApp.clipspace_return_node = this.node; - ComfyApp.open_maskeditor(); - - this.editorWasShowing = false; - this.waitWhileMaskEditing(); - - } catch (error) { - log.error("Error preparing image for mask editor:", error); - alert(`Error: ${error.message}`); - } - } - - waitWhileMaskEditing() { - // Czekamy, aż edytor się pojawi, a potem zniknie. - if (mask_editor_showing(app)) { - this.editorWasShowing = true; - } - - if (!mask_editor_showing(app) && this.editorWasShowing) { - // Edytor był widoczny i już go nie ma - this.editorWasShowing = false; - setTimeout(() => this.handleMaskEditorClose(), 100); // Dajemy chwilę na aktualizację - } else { - setTimeout(this.waitWhileMaskEditing.bind(this), 100); - } - } - - async handleMaskEditorClose() { - console.log("Node object after mask editor close:", this.node); - if (!this.node.imgs || !this.node.imgs.length === 0 || !this.node.imgs[0].src) { - log.warn("Mask editor was closed without a result."); - return; - } - - const resultImage = new Image(); - resultImage.src = this.node.imgs[0].src; - - try { - await new Promise((resolve, reject) => { - resultImage.onload = resolve; - resultImage.onerror = reject; - }); - } catch (error) { - log.error("Failed to load image from mask editor.", error); - this.node.imgs = []; - return; - } - - // Używamy wymiarów naszego płótna, aby zapewnić spójność - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = this.width; - tempCanvas.height = this.height; - const tempCtx = tempCanvas.getContext('2d'); - - // Rysujemy obrazek z edytora, który zawiera maskę w kanale alfa - tempCtx.drawImage(resultImage, 0, 0, this.width, this.height); - - const imageData = tempCtx.getImageData(0, 0, this.width, this.height); - const data = imageData.data; - - for (let i = 0; i < data.length; i += 4) { - const originalAlpha = data[i + 3]; - - // Ustawiamy biały kolor - data[i] = 255; // R - data[i + 1] = 255; // G - data[i + 2] = 255; // B - - // Odwracamy kanał alfa - data[i + 3] = 255 - originalAlpha; - } - - tempCtx.putImageData(imageData, 0, 0); - - const maskAsImage = new Image(); - maskAsImage.src = tempCanvas.toDataURL(); - await new Promise(resolve => maskAsImage.onload = resolve); - - // Łączymy nową maskę z istniejącą, zamiast ją nadpisywać - const maskCtx = this.maskTool.maskCtx; - const destX = -this.maskTool.x; - const destY = -this.maskTool.y; - - maskCtx.globalCompositeOperation = 'screen'; - maskCtx.drawImage(maskAsImage, destX, destY); - maskCtx.globalCompositeOperation = 'source-over'; // Przywracamy domyślny tryb - - this.render(); - this.saveState(); - - // Zaktualizuj podgląd węzła nowym, spłaszczonym obrazem - const new_preview = new Image(); - const blob = await this.canvasLayers.getFlattenedCanvasAsBlob(); - if (blob) { - new_preview.src = URL.createObjectURL(blob); - await new Promise(r => new_preview.onload = r); - this.node.imgs = [new_preview]; - } else { - this.node.imgs = []; - } - - this.render(); - } } diff --git a/js/CanvasLayers.js b/js/CanvasLayers.js index afeed8b..a44e662 100644 --- a/js/CanvasLayers.js +++ b/js/CanvasLayers.js @@ -734,36 +734,4 @@ export class CanvasLayers { }, 'image/png'); }); } - - async getFlattenedCanvasAsDataURL() { - if (this.canvasLayers.layers.length === 0) return null; - - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = this.canvasLayers.width; - tempCanvas.height = this.canvasLayers.height; - const tempCtx = tempCanvas.getContext('2d'); - - const sortedLayers = [...this.canvasLayers.layers].sort((a, b) => a.zIndex - b.zIndex); - sortedLayers.forEach(layer => { - if (!layer.image) return; - - tempCtx.save(); - tempCtx.globalCompositeOperation = layer.blendMode || 'normal'; - tempCtx.globalAlpha = layer.opacity !== undefined ? layer.opacity : 1; - const centerX = layer.x + layer.width / 2; - const centerY = layer.y + layer.height / 2; - tempCtx.translate(centerX, centerY); - tempCtx.rotate(layer.rotation * Math.PI / 180); - tempCtx.drawImage( - layer.image, - -layer.width / 2, - -layer.height / 2, - layer.width, - layer.height - ); - tempCtx.restore(); - }); - - return tempCanvas.toDataURL('image/png'); - } } diff --git a/js/CanvasView.js b/js/CanvasView.js index fed9607..47063f8 100644 --- a/js/CanvasView.js +++ b/js/CanvasView.js @@ -761,13 +761,6 @@ async function createCanvasWidget(node, widget, app) { ]), $el("div.painter-separator"), $el("div.painter-button-group", {id: "mask-controls"}, [ - $el("button.painter-button", { - textContent: "Edit Mask", - title: "Open the current canvas view in the mask editor", - onclick: () => { - canvas.startMaskEditor(); - } - }), $el("button.painter-button", { id: "mask-mode-btn", textContent: "Draw Mask", diff --git a/js/MaskTool.js b/js/MaskTool.js index 5320d0a..456689f 100644 --- a/js/MaskTool.js +++ b/js/MaskTool.js @@ -279,26 +279,4 @@ export class MaskTool { this.y += dy; log.info(`Mask position updated to (${this.x}, ${this.y})`); } - - setMask(image) { - // `this.x` i `this.y` przechowują pozycję lewego górnego rogu płótna maski - // względem lewego górnego rogu widoku. Zatem (-this.x, -this.y) to pozycja - // lewego górnego rogu widoku na płótnie maski. - const destX = -this.x; - const destY = -this.y; - - // Wyczyść tylko ten obszar na dużym płótnie maski, który odpowiada - // widocznemu obszarowi wyjściowemu. - this.maskCtx.clearRect(destX, destY, this.canvasInstance.width, this.canvasInstance.height); - - // Narysuj nowy obraz maski (który ma rozmiar obszaru wyjściowego) - // dokładnie w tym wyczyszczonym miejscu. - this.maskCtx.drawImage(image, destX, destY); - - if (this.onStateChange) { - this.onStateChange(); - } - this.canvasInstance.render(); // Wymuś odświeżenie, aby zobaczyć zmianę - log.info(`MaskTool updated with a new mask image at correct canvas position (${destX}, ${destY}).`); - } } diff --git a/js/utils/mask_utils.js b/js/utils/mask_utils.js deleted file mode 100644 index 21b62a2..0000000 --- a/js/utils/mask_utils.js +++ /dev/null @@ -1,43 +0,0 @@ -export function new_editor(app) { - if (!app) return false; - return app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor') -} - -function get_mask_editor_element(app) { - return new_editor(app) ? document.getElementById('maskEditor') : document.getElementById('maskCanvas')?.parentElement -} - -export function mask_editor_showing(app) { - const editor = get_mask_editor_element(app); - return editor && editor.style.display !== "none"; -} - -export function hide_mask_editor() { - if (mask_editor_showing()) document.getElementById('maskEditor').style.display = 'none' -} - -function get_mask_editor_cancel_button(app) { - if (document.getElementById("maskEditor_topBarCancelButton")) return document.getElementById("maskEditor_topBarCancelButton") - return get_mask_editor_element(app)?.parentElement?.lastChild?.childNodes[2] -} - -function get_mask_editor_save_button(app) { - if (document.getElementById("maskEditor_topBarSaveButton")) return document.getElementById("maskEditor_topBarSaveButton") - return get_mask_editor_element(app)?.parentElement?.lastChild?.childNodes[2] -} - -export function mask_editor_listen_for_cancel(app, callback) { - const cancel_button = get_mask_editor_cancel_button(app); - if (cancel_button && !cancel_button.filter_listener_added) { - cancel_button.addEventListener('click', callback); - cancel_button.filter_listener_added = true; - } -} - -export function press_maskeditor_save(app) { - get_mask_editor_save_button(app)?.click() -} - -export function press_maskeditor_cancel(app) { - get_mask_editor_cancel_button(app)?.click() -}