mirror of
https://github.com/Azornes/Comfyui-LayerForge.git
synced 2026-03-24 14:02:11 -03:00
Refactor code style and remove mask editor examples
This commit applies consistent code style changes (mainly spacing and formatting) across multiple JS files for improved readability and maintainability. Additionally, it removes the unused 'js/examples/mask_editor_examples.js' file.
This commit is contained in:
148
js/Canvas.js
148
js/Canvas.js
@@ -1,5 +1,5 @@
|
|||||||
import { app, ComfyApp } from "../../scripts/app.js";
|
import {app, ComfyApp} from "../../scripts/app.js";
|
||||||
import { api } from "../../scripts/api.js";
|
import {api} from "../../scripts/api.js";
|
||||||
import {removeImage} from "./db.js";
|
import {removeImage} from "./db.js";
|
||||||
import {MaskTool} from "./MaskTool.js";
|
import {MaskTool} from "./MaskTool.js";
|
||||||
import {CanvasState} from "./CanvasState.js";
|
import {CanvasState} from "./CanvasState.js";
|
||||||
@@ -9,13 +9,13 @@ import {CanvasRenderer} from "./CanvasRenderer.js";
|
|||||||
import {CanvasIO} from "./CanvasIO.js";
|
import {CanvasIO} from "./CanvasIO.js";
|
||||||
import {ImageReferenceManager} from "./ImageReferenceManager.js";
|
import {ImageReferenceManager} from "./ImageReferenceManager.js";
|
||||||
import {createModuleLogger} from "./utils/LoggerUtils.js";
|
import {createModuleLogger} from "./utils/LoggerUtils.js";
|
||||||
import { mask_editor_showing, mask_editor_listen_for_cancel } from "./utils/mask_utils.js";
|
import {mask_editor_showing, mask_editor_listen_for_cancel} from "./utils/mask_utils.js";
|
||||||
|
|
||||||
const log = createModuleLogger('Canvas');
|
const log = createModuleLogger('Canvas');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Canvas - Fasada dla systemu rysowania
|
* Canvas - Fasada dla systemu rysowania
|
||||||
*
|
*
|
||||||
* Klasa Canvas pełni rolę fasady, oferując uproszczony interfejs wysokiego poziomu
|
* Klasa Canvas pełni rolę fasady, oferując uproszczony interfejs wysokiego poziomu
|
||||||
* dla złożonego systemu rysowania. Zamiast eksponować wszystkie metody modułów,
|
* dla złożonego systemu rysowania. Zamiast eksponować wszystkie metody modułów,
|
||||||
* udostępnia tylko kluczowe operacje i umożliwia bezpośredni dostęp do modułów
|
* udostępnia tylko kluczowe operacje i umożliwia bezpośredni dostęp do modułów
|
||||||
@@ -69,21 +69,21 @@ export class Canvas {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const check = () => {
|
const check = () => {
|
||||||
const widget = node.widgets.find(w => w.name === name);
|
const widget = node.widgets.find(w => w.name === name);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
resolve(widget);
|
resolve(widget);
|
||||||
} else if (Date.now() - startTime > timeout) {
|
} else if (Date.now() - startTime > timeout) {
|
||||||
reject(new Error(`Widget "${name}" not found within timeout.`));
|
reject(new Error(`Widget "${name}" not found within timeout.`));
|
||||||
} else {
|
} else {
|
||||||
setTimeout(check, interval);
|
setTimeout(check, interval);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
check();
|
check();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kontroluje widoczność podglądu canvas
|
* Kontroluje widoczność podglądu canvas
|
||||||
* @param {boolean} visible - Czy podgląd ma być widoczny
|
* @param {boolean} visible - Czy podgląd ma być widoczny
|
||||||
@@ -95,7 +95,7 @@ export class Canvas {
|
|||||||
const imagePreviewWidget = await this.waitForWidget("$$canvas-image-preview", this.node);
|
const imagePreviewWidget = await this.waitForWidget("$$canvas-image-preview", this.node);
|
||||||
if (imagePreviewWidget) {
|
if (imagePreviewWidget) {
|
||||||
console.log("Found $$canvas-image-preview widget, controlling visibility");
|
console.log("Found $$canvas-image-preview widget, controlling visibility");
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
console.log("=== SHOWING WIDGET ===");
|
console.log("=== SHOWING WIDGET ===");
|
||||||
|
|
||||||
@@ -110,10 +110,10 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log("Setting computeSize to fixed height 250");
|
console.log("Setting computeSize to fixed height 250");
|
||||||
imagePreviewWidget.computeSize = function() {
|
imagePreviewWidget.computeSize = function () {
|
||||||
return [0, 250]; // Szerokość 0 (auto), wysokość 250
|
return [0, 250]; // Szerokość 0 (auto), wysokość 250
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("ImagePreviewWidget shown");
|
console.log("ImagePreviewWidget shown");
|
||||||
} else {
|
} else {
|
||||||
console.log("=== HIDING WIDGET ===");
|
console.log("=== HIDING WIDGET ===");
|
||||||
@@ -127,14 +127,14 @@ export class Canvas {
|
|||||||
if ('hidden' in imagePreviewWidget) {
|
if ('hidden' in imagePreviewWidget) {
|
||||||
imagePreviewWidget.hidden = true;
|
imagePreviewWidget.hidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
imagePreviewWidget.computeSize = function() {
|
imagePreviewWidget.computeSize = function () {
|
||||||
return [0, 0]; // Szerokość 0, wysokość 0
|
return [0, 0]; // Szerokość 0, wysokość 0
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("ImagePreviewWidget hidden with zero size");
|
console.log("ImagePreviewWidget hidden with zero size");
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("=== FINAL WIDGET STATE ===");
|
console.log("=== FINAL WIDGET STATE ===");
|
||||||
this.render()
|
this.render()
|
||||||
} else {
|
} else {
|
||||||
@@ -173,8 +173,6 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ładuje stan canvas z bazy danych
|
* Ładuje stan canvas z bazy danych
|
||||||
*/
|
*/
|
||||||
@@ -292,8 +290,6 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uruchamia edytor masek
|
* Uruchamia edytor masek
|
||||||
* @param {Image|HTMLCanvasElement|null} predefinedMask - Opcjonalna maska do nałożenia po otwarciu editora
|
* @param {Image|HTMLCanvasElement|null} predefinedMask - Opcjonalna maska do nałożenia po otwarciu editora
|
||||||
@@ -322,7 +318,7 @@ export class Canvas {
|
|||||||
|
|
||||||
blob = await this.canvasLayers.getFlattenedCanvasForMaskEditor();
|
blob = await this.canvasLayers.getFlattenedCanvasForMaskEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!blob) {
|
if (!blob) {
|
||||||
log.warn("Canvas is empty, cannot open mask editor.");
|
log.warn("Canvas is empty, cannot open mask editor.");
|
||||||
return;
|
return;
|
||||||
@@ -344,28 +340,28 @@ export class Canvas {
|
|||||||
throw new Error(`Failed to upload image: ${response.statusText}`);
|
throw new Error(`Failed to upload image: ${response.statusText}`);
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src = api.apiURL(`/view?filename=${encodeURIComponent(data.name)}&type=${data.type}&subfolder=${data.subfolder}`);
|
img.src = api.apiURL(`/view?filename=${encodeURIComponent(data.name)}&type=${data.type}&subfolder=${data.subfolder}`);
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
img.onload = res;
|
img.onload = res;
|
||||||
img.onerror = rej;
|
img.onerror = rej;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.node.imgs = [img];
|
this.node.imgs = [img];
|
||||||
|
|
||||||
ComfyApp.copyToClipspace(this.node);
|
ComfyApp.copyToClipspace(this.node);
|
||||||
ComfyApp.clipspace_return_node = this.node;
|
ComfyApp.clipspace_return_node = this.node;
|
||||||
ComfyApp.open_maskeditor();
|
ComfyApp.open_maskeditor();
|
||||||
|
|
||||||
this.editorWasShowing = false;
|
|
||||||
this.waitWhileMaskEditing();
|
|
||||||
|
|
||||||
this.setupCancelListener();
|
this.editorWasShowing = false;
|
||||||
|
this.waitWhileMaskEditing();
|
||||||
|
|
||||||
if (predefinedMask) {
|
this.setupCancelListener();
|
||||||
this.waitForMaskEditorAndApplyMask();
|
|
||||||
}
|
if (predefinedMask) {
|
||||||
|
this.waitForMaskEditorAndApplyMask();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Error preparing image for mask editor:", error);
|
log.error("Error preparing image for mask editor:", error);
|
||||||
@@ -374,8 +370,6 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inicjalizuje podstawowe właściwości canvas
|
* Inicjalizuje podstawowe właściwości canvas
|
||||||
*/
|
*/
|
||||||
@@ -428,7 +422,7 @@ export class Canvas {
|
|||||||
const mouseX_Canvas = mouseX_DOM * scaleX;
|
const mouseX_Canvas = mouseX_DOM * scaleX;
|
||||||
const mouseY_Canvas = mouseY_DOM * scaleY;
|
const mouseY_Canvas = mouseY_DOM * scaleY;
|
||||||
|
|
||||||
return { x: mouseX_Canvas, y: mouseY_Canvas };
|
return {x: mouseX_Canvas, y: mouseY_Canvas};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -488,23 +482,21 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Czeka na otwarcie mask editora i automatycznie nakłada predefiniowaną maskę
|
* Czeka na otwarcie mask editora i automatycznie nakłada predefiniowaną maskę
|
||||||
*/
|
*/
|
||||||
waitForMaskEditorAndApplyMask() {
|
waitForMaskEditorAndApplyMask() {
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const maxAttempts = 100; // Zwiększone do 10 sekund oczekiwania
|
const maxAttempts = 100; // Zwiększone do 10 sekund oczekiwania
|
||||||
|
|
||||||
const checkEditor = () => {
|
const checkEditor = () => {
|
||||||
attempts++;
|
attempts++;
|
||||||
|
|
||||||
if (mask_editor_showing(app)) {
|
if (mask_editor_showing(app)) {
|
||||||
|
|
||||||
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
|
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
|
||||||
let editorReady = false;
|
let editorReady = false;
|
||||||
|
|
||||||
if (useNewEditor) {
|
if (useNewEditor) {
|
||||||
|
|
||||||
const MaskEditorDialog = window.MaskEditorDialog;
|
const MaskEditorDialog = window.MaskEditorDialog;
|
||||||
@@ -541,7 +533,7 @@ export class Canvas {
|
|||||||
log.info("Old mask editor detected as ready");
|
log.info("Old mask editor detected as ready");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editorReady) {
|
if (editorReady) {
|
||||||
|
|
||||||
log.info("Applying mask to editor after", attempts * 100, "ms wait");
|
log.info("Applying mask to editor after", attempts * 100, "ms wait");
|
||||||
@@ -572,7 +564,7 @@ export class Canvas {
|
|||||||
this.pendingMask = null;
|
this.pendingMask = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
checkEditor();
|
checkEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,7 +576,7 @@ export class Canvas {
|
|||||||
try {
|
try {
|
||||||
|
|
||||||
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
|
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
|
||||||
|
|
||||||
if (useNewEditor) {
|
if (useNewEditor) {
|
||||||
|
|
||||||
const MaskEditorDialog = window.MaskEditorDialog;
|
const MaskEditorDialog = window.MaskEditorDialog;
|
||||||
@@ -599,7 +591,7 @@ export class Canvas {
|
|||||||
|
|
||||||
await this.applyMaskToOldEditor(maskData);
|
await this.applyMaskToOldEditor(maskData);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("Predefined mask applied to mask editor successfully");
|
log.info("Predefined mask applied to mask editor successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error("Failed to apply predefined mask to editor:", error);
|
log.error("Failed to apply predefined mask to editor:", error);
|
||||||
@@ -653,7 +645,7 @@ export class Canvas {
|
|||||||
|
|
||||||
const maskCtx = maskCanvas.getContext('2d');
|
const maskCtx = maskCanvas.getContext('2d');
|
||||||
|
|
||||||
const maskColor = { r: 255, g: 255, b: 255 };
|
const maskColor = {r: 255, g: 255, b: 255};
|
||||||
const processedMask = await this.processMaskForEditor(maskData, maskCanvas.width, maskCanvas.height, maskColor);
|
const processedMask = await this.processMaskForEditor(maskData, maskCanvas.width, maskCanvas.height, maskColor);
|
||||||
|
|
||||||
maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height);
|
maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height);
|
||||||
@@ -671,11 +663,11 @@ export class Canvas {
|
|||||||
async processMaskForEditor(maskData, targetWidth, targetHeight, maskColor) {
|
async processMaskForEditor(maskData, targetWidth, targetHeight, maskColor) {
|
||||||
const originalWidth = maskData.width || maskData.naturalWidth || this.width;
|
const originalWidth = maskData.width || maskData.naturalWidth || this.width;
|
||||||
const originalHeight = maskData.height || maskData.naturalHeight || this.height;
|
const originalHeight = maskData.height || maskData.naturalHeight || this.height;
|
||||||
|
|
||||||
log.info("Processing mask for editor:", {
|
log.info("Processing mask for editor:", {
|
||||||
originalSize: { width: originalWidth, height: originalHeight },
|
originalSize: {width: originalWidth, height: originalHeight},
|
||||||
targetSize: { width: targetWidth, height: targetHeight },
|
targetSize: {width: targetWidth, height: targetHeight},
|
||||||
canvasSize: { width: this.width, height: this.height }
|
canvasSize: {width: this.width, height: this.height}
|
||||||
});
|
});
|
||||||
|
|
||||||
const tempCanvas = document.createElement('canvas');
|
const tempCanvas = document.createElement('canvas');
|
||||||
@@ -693,16 +685,16 @@ export class Canvas {
|
|||||||
|
|
||||||
const offsetX = (targetWidth - scaledWidth) / 2;
|
const offsetX = (targetWidth - scaledWidth) / 2;
|
||||||
const offsetY = (targetHeight - scaledHeight) / 2;
|
const offsetY = (targetHeight - scaledHeight) / 2;
|
||||||
|
|
||||||
tempCtx.drawImage(maskData, offsetX, offsetY, scaledWidth, scaledHeight);
|
tempCtx.drawImage(maskData, offsetX, offsetY, scaledWidth, scaledHeight);
|
||||||
|
|
||||||
log.info("Mask drawn scaled to original image size:", {
|
log.info("Mask drawn scaled to original image size:", {
|
||||||
originalSize: { width: originalWidth, height: originalHeight },
|
originalSize: {width: originalWidth, height: originalHeight},
|
||||||
targetSize: { width: targetWidth, height: targetHeight },
|
targetSize: {width: targetWidth, height: targetHeight},
|
||||||
canvasSize: { width: this.width, height: this.height },
|
canvasSize: {width: this.width, height: this.height},
|
||||||
scaleToOriginal: scaleToOriginal,
|
scaleToOriginal: scaleToOriginal,
|
||||||
finalSize: { width: scaledWidth, height: scaledHeight },
|
finalSize: {width: scaledWidth, height: scaledHeight},
|
||||||
offset: { x: offsetX, y: offsetY }
|
offset: {x: offsetX, y: offsetY}
|
||||||
});
|
});
|
||||||
|
|
||||||
const imageData = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
const imageData = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||||
@@ -718,7 +710,7 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tempCtx.putImageData(imageData, 0, 0);
|
tempCtx.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
log.info("Mask processing completed - full size scaling applied");
|
log.info("Mask processing completed - full size scaling applied");
|
||||||
return tempCanvas;
|
return tempCanvas;
|
||||||
}
|
}
|
||||||
@@ -744,10 +736,10 @@ export class Canvas {
|
|||||||
if (mask_editor_showing(app)) {
|
if (mask_editor_showing(app)) {
|
||||||
this.editorWasShowing = true;
|
this.editorWasShowing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mask_editor_showing(app) && this.editorWasShowing) {
|
if (!mask_editor_showing(app) && this.editorWasShowing) {
|
||||||
this.editorWasShowing = false;
|
this.editorWasShowing = false;
|
||||||
setTimeout(() => this.handleMaskEditorClose(), 100);
|
setTimeout(() => this.handleMaskEditorClose(), 100);
|
||||||
} else {
|
} else {
|
||||||
setTimeout(this.waitWhileMaskEditing.bind(this), 100);
|
setTimeout(this.waitWhileMaskEditing.bind(this), 100);
|
||||||
}
|
}
|
||||||
@@ -778,7 +770,7 @@ export class Canvas {
|
|||||||
tempCanvas.width = this.width;
|
tempCanvas.width = this.width;
|
||||||
tempCanvas.height = this.height;
|
tempCanvas.height = this.height;
|
||||||
const tempCtx = tempCanvas.getContext('2d');
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
|
||||||
tempCtx.drawImage(resultImage, 0, 0, this.width, this.height);
|
tempCtx.drawImage(resultImage, 0, 0, this.width, this.height);
|
||||||
|
|
||||||
const imageData = tempCtx.getImageData(0, 0, this.width, this.height);
|
const imageData = tempCtx.getImageData(0, 0, this.width, this.height);
|
||||||
@@ -786,7 +778,7 @@ export class Canvas {
|
|||||||
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
const originalAlpha = data[i + 3];
|
const originalAlpha = data[i + 3];
|
||||||
data[i] = 255;
|
data[i] = 255;
|
||||||
data[i + 1] = 255;
|
data[i + 1] = 255;
|
||||||
data[i + 2] = 255;
|
data[i + 2] = 255;
|
||||||
data[i + 3] = 255 - originalAlpha;
|
data[i + 3] = 255 - originalAlpha;
|
||||||
@@ -797,7 +789,7 @@ export class Canvas {
|
|||||||
const maskAsImage = new Image();
|
const maskAsImage = new Image();
|
||||||
maskAsImage.src = tempCanvas.toDataURL();
|
maskAsImage.src = tempCanvas.toDataURL();
|
||||||
await new Promise(resolve => maskAsImage.onload = resolve);
|
await new Promise(resolve => maskAsImage.onload = resolve);
|
||||||
|
|
||||||
const maskCtx = this.maskTool.maskCtx;
|
const maskCtx = this.maskTool.maskCtx;
|
||||||
const destX = -this.maskTool.x;
|
const destX = -this.maskTool.x;
|
||||||
const destY = -this.maskTool.y;
|
const destY = -this.maskTool.y;
|
||||||
@@ -807,10 +799,10 @@ export class Canvas {
|
|||||||
maskCtx.clearRect(destX, destY, this.width, this.height);
|
maskCtx.clearRect(destX, destY, this.width, this.height);
|
||||||
|
|
||||||
maskCtx.drawImage(maskAsImage, destX, destY);
|
maskCtx.drawImage(maskAsImage, destX, destY);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
this.saveState();
|
this.saveState();
|
||||||
|
|
||||||
const new_preview = new Image();
|
const new_preview = new Image();
|
||||||
|
|
||||||
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();
|
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();
|
||||||
@@ -826,8 +818,6 @@ export class Canvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zapisuje obecny stan maski przed otwarciem editora
|
* Zapisuje obecny stan maski przed otwarciem editora
|
||||||
* @returns {Object} Zapisany stan maski
|
* @returns {Object} Zapisany stan maski
|
||||||
@@ -929,7 +919,7 @@ export class Canvas {
|
|||||||
tempCanvas.width = this.width;
|
tempCanvas.width = this.width;
|
||||||
tempCanvas.height = this.height;
|
tempCanvas.height = this.height;
|
||||||
const tempCtx = tempCanvas.getContext('2d');
|
const tempCtx = tempCanvas.getContext('2d');
|
||||||
|
|
||||||
tempCtx.drawImage(resultImage, 0, 0, this.width, this.height);
|
tempCtx.drawImage(resultImage, 0, 0, this.width, this.height);
|
||||||
|
|
||||||
const imageData = tempCtx.getImageData(0, 0, this.width, this.height);
|
const imageData = tempCtx.getImageData(0, 0, this.width, this.height);
|
||||||
@@ -937,7 +927,7 @@ export class Canvas {
|
|||||||
|
|
||||||
for (let i = 0; i < data.length; i += 4) {
|
for (let i = 0; i < data.length; i += 4) {
|
||||||
const originalAlpha = data[i + 3];
|
const originalAlpha = data[i + 3];
|
||||||
data[i] = 255;
|
data[i] = 255;
|
||||||
data[i + 1] = 255;
|
data[i + 1] = 255;
|
||||||
data[i + 2] = 255;
|
data[i + 2] = 255;
|
||||||
data[i + 3] = 255 - originalAlpha;
|
data[i + 3] = 255 - originalAlpha;
|
||||||
@@ -948,7 +938,7 @@ export class Canvas {
|
|||||||
const maskAsImage = new Image();
|
const maskAsImage = new Image();
|
||||||
maskAsImage.src = tempCanvas.toDataURL();
|
maskAsImage.src = tempCanvas.toDataURL();
|
||||||
await new Promise(resolve => maskAsImage.onload = resolve);
|
await new Promise(resolve => maskAsImage.onload = resolve);
|
||||||
|
|
||||||
const maskCtx = this.maskTool.maskCtx;
|
const maskCtx = this.maskTool.maskCtx;
|
||||||
const destX = -this.maskTool.x;
|
const destX = -this.maskTool.x;
|
||||||
const destY = -this.maskTool.y;
|
const destY = -this.maskTool.y;
|
||||||
@@ -958,10 +948,10 @@ export class Canvas {
|
|||||||
maskCtx.clearRect(destX, destY, this.width, this.height);
|
maskCtx.clearRect(destX, destY, this.width, this.height);
|
||||||
|
|
||||||
maskCtx.drawImage(maskAsImage, destX, destY);
|
maskCtx.drawImage(maskAsImage, destX, destY);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
this.saveState();
|
this.saveState();
|
||||||
|
|
||||||
const new_preview = new Image();
|
const new_preview = new Image();
|
||||||
|
|
||||||
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();
|
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {saveImage, removeImage} from "./db.js";
|
|||||||
import {createModuleLogger} from "./utils/LoggerUtils.js";
|
import {createModuleLogger} from "./utils/LoggerUtils.js";
|
||||||
import {generateUUID, generateUniqueFileName} from "./utils/CommonUtils.js";
|
import {generateUUID, generateUniqueFileName} from "./utils/CommonUtils.js";
|
||||||
import {withErrorHandling, createValidationError} from "./ErrorHandler.js";
|
import {withErrorHandling, createValidationError} from "./ErrorHandler.js";
|
||||||
import { app, ComfyApp } from "../../scripts/app.js";
|
import {app, ComfyApp} from "../../scripts/app.js";
|
||||||
|
|
||||||
const log = createModuleLogger('CanvasLayers');
|
const log = createModuleLogger('CanvasLayers');
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ export class CanvasLayers {
|
|||||||
try {
|
try {
|
||||||
log.info("Attempting to paste from system clipboard");
|
log.info("Attempting to paste from system clipboard");
|
||||||
const clipboardItems = await navigator.clipboard.read();
|
const clipboardItems = await navigator.clipboard.read();
|
||||||
|
|
||||||
for (const item of clipboardItems) {
|
for (const item of clipboardItems) {
|
||||||
const imageType = item.types.find(type => type.startsWith('image/'));
|
const imageType = item.types.find(type => type.startsWith('image/'));
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ export class CanvasLayers {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info("No image found in system clipboard");
|
log.info("No image found in system clipboard");
|
||||||
return false;
|
return false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -178,7 +178,7 @@ export class CanvasLayers {
|
|||||||
const imageId = generateUUID();
|
const imageId = generateUUID();
|
||||||
await saveImage(imageId, image.src);
|
await saveImage(imageId, image.src);
|
||||||
this.canvas.imageCache.set(imageId, image.src);
|
this.canvas.imageCache.set(imageId, image.src);
|
||||||
|
|
||||||
let finalWidth = image.width;
|
let finalWidth = image.width;
|
||||||
let finalHeight = image.height;
|
let finalHeight = image.height;
|
||||||
let finalX, finalY;
|
let finalX, finalY;
|
||||||
@@ -268,7 +268,7 @@ export class CanvasLayers {
|
|||||||
*/
|
*/
|
||||||
resizeLayer(scale) {
|
resizeLayer(scale) {
|
||||||
if (this.canvas.selectedLayers.length === 0) return;
|
if (this.canvas.selectedLayers.length === 0) return;
|
||||||
|
|
||||||
this.canvas.selectedLayers.forEach(layer => {
|
this.canvas.selectedLayers.forEach(layer => {
|
||||||
layer.width *= scale;
|
layer.width *= scale;
|
||||||
layer.height *= scale;
|
layer.height *= scale;
|
||||||
@@ -283,7 +283,7 @@ export class CanvasLayers {
|
|||||||
*/
|
*/
|
||||||
rotateLayer(angle) {
|
rotateLayer(angle) {
|
||||||
if (this.canvas.selectedLayers.length === 0) return;
|
if (this.canvas.selectedLayers.length === 0) return;
|
||||||
|
|
||||||
this.canvas.selectedLayers.forEach(layer => {
|
this.canvas.selectedLayers.forEach(layer => {
|
||||||
layer.rotation += angle;
|
layer.rotation += angle;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
|
|
||||||
helpTooltip.style.visibility = 'hidden';
|
helpTooltip.style.visibility = 'hidden';
|
||||||
helpTooltip.style.display = 'block';
|
helpTooltip.style.display = 'block';
|
||||||
|
|
||||||
const buttonRect = e.target.getBoundingClientRect();
|
const buttonRect = e.target.getBoundingClientRect();
|
||||||
const tooltipRect = helpTooltip.getBoundingClientRect();
|
const tooltipRect = helpTooltip.getBoundingClientRect();
|
||||||
const viewportWidth = window.innerWidth;
|
const viewportWidth = window.innerWidth;
|
||||||
@@ -1004,7 +1004,7 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
log.debug("Image object loaded from dropped data:URL.");
|
log.debug("Image object loaded from dropped data:URL.");
|
||||||
const fitOnAddWidget = node.widgets.find(w => w.name === "fit_on_add");
|
const fitOnAddWidget = node.widgets.find(w => w.name === "fit_on_add");
|
||||||
const addMode = fitOnAddWidget && fitOnAddWidget.value ? 'fit' : 'center';
|
const addMode = fitOnAddWidget && fitOnAddWidget.value ? 'fit' : 'center';
|
||||||
|
|
||||||
await canvas.addLayer(img, {}, addMode);
|
await canvas.addLayer(img, {}, addMode);
|
||||||
log.info("Dropped layer added and state saved.");
|
log.info("Dropped layer added and state saved.");
|
||||||
};
|
};
|
||||||
@@ -1105,8 +1105,8 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
const showPreviewWidget = node.widgets.find(w => w.name === "show_preview");
|
const showPreviewWidget = node.widgets.find(w => w.name === "show_preview");
|
||||||
if (showPreviewWidget) {
|
if (showPreviewWidget) {
|
||||||
const originalCallback = showPreviewWidget.callback;
|
const originalCallback = showPreviewWidget.callback;
|
||||||
|
|
||||||
showPreviewWidget.callback = function(value) {
|
showPreviewWidget.callback = function (value) {
|
||||||
if (originalCallback) {
|
if (originalCallback) {
|
||||||
originalCallback.call(this, value);
|
originalCallback.call(this, value);
|
||||||
}
|
}
|
||||||
@@ -1124,7 +1124,6 @@ async function createCanvasWidget(node, widget, app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canvas: canvas,
|
canvas: canvas,
|
||||||
panel: controlPanel
|
panel: controlPanel
|
||||||
@@ -1251,13 +1250,13 @@ app.registerExtension({
|
|||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
const maskEditorIndex = options.findIndex(option =>
|
const maskEditorIndex = options.findIndex(option =>
|
||||||
option && option.content === "Open in MaskEditor"
|
option && option.content === "Open in MaskEditor"
|
||||||
);
|
);
|
||||||
if (maskEditorIndex !== -1) {
|
if (maskEditorIndex !== -1) {
|
||||||
options.splice(maskEditorIndex, 1);
|
options.splice(maskEditorIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newOptions = [
|
const newOptions = [
|
||||||
{
|
{
|
||||||
content: "Open in MaskEditor",
|
content: "Open in MaskEditor",
|
||||||
|
|||||||
@@ -283,7 +283,6 @@ export class MaskTool {
|
|||||||
setMask(image) {
|
setMask(image) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const destX = -this.x;
|
const destX = -this.x;
|
||||||
const destY = -this.y;
|
const destY = -this.y;
|
||||||
|
|
||||||
|
|||||||
@@ -1,141 +0,0 @@
|
|||||||
/**
|
|
||||||
* Przykłady użycia automatycznego nakładania masek w mask editorze
|
|
||||||
*
|
|
||||||
* Te przykłady pokazują jak używać nowej funkcjonalności do automatycznego
|
|
||||||
* nakładania predefiniowanych masek po otwarciu mask editora ComfyUI.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
start_mask_editor_with_predefined_mask,
|
|
||||||
create_mask_from_image_src,
|
|
||||||
canvas_to_mask_image
|
|
||||||
} from '../utils/mask_utils.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 1: Podstawowe użycie z obrazem maski
|
|
||||||
*/
|
|
||||||
async function example1_basic_usage(canvasInstance) {
|
|
||||||
|
|
||||||
const maskImage = await create_mask_from_image_src('/path/to/mask.png');
|
|
||||||
|
|
||||||
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 2: Użycie z canvas jako maska
|
|
||||||
*/
|
|
||||||
async function example2_canvas_mask(canvasInstance) {
|
|
||||||
|
|
||||||
const maskCanvas = document.createElement('canvas');
|
|
||||||
maskCanvas.width = 512;
|
|
||||||
maskCanvas.height = 512;
|
|
||||||
const ctx = maskCanvas.getContext('2d');
|
|
||||||
|
|
||||||
ctx.fillStyle = 'black';
|
|
||||||
ctx.fillRect(0, 0, 512, 512);
|
|
||||||
ctx.fillStyle = 'white';
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(256, 256, 100, 0, 2 * Math.PI);
|
|
||||||
ctx.fill();
|
|
||||||
|
|
||||||
const maskImage = await canvas_to_mask_image(maskCanvas);
|
|
||||||
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 3: Bezpośrednie użycie metody Canvas
|
|
||||||
*/
|
|
||||||
async function example3_direct_canvas_method(canvasInstance) {
|
|
||||||
|
|
||||||
const maskImage = await create_mask_from_image_src('/path/to/mask.png');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
await canvasInstance.startMaskEditor(maskImage, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 4: Tworzenie maski z danych binarnych
|
|
||||||
*/
|
|
||||||
async function example4_binary_data_mask(canvasInstance, binaryData) {
|
|
||||||
|
|
||||||
const blob = new Blob([binaryData], { type: 'image/png' });
|
|
||||||
const dataUrl = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
const maskImage = await create_mask_from_image_src(dataUrl);
|
|
||||||
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
|
|
||||||
URL.revokeObjectURL(dataUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 5: Maska z gradientem
|
|
||||||
*/
|
|
||||||
async function example5_gradient_mask(canvasInstance) {
|
|
||||||
const maskCanvas = document.createElement('canvas');
|
|
||||||
maskCanvas.width = 512;
|
|
||||||
maskCanvas.height = 512;
|
|
||||||
const ctx = maskCanvas.getContext('2d');
|
|
||||||
|
|
||||||
const gradient = ctx.createLinearGradient(0, 0, 512, 0);
|
|
||||||
gradient.addColorStop(0, 'rgba(0, 0, 0, 0)'); // Przezroczysty
|
|
||||||
gradient.addColorStop(1, 'rgba(255, 255, 255, 1)'); // Biały
|
|
||||||
|
|
||||||
ctx.fillStyle = gradient;
|
|
||||||
ctx.fillRect(0, 0, 512, 512);
|
|
||||||
|
|
||||||
const maskImage = await canvas_to_mask_image(maskCanvas);
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 6: Obsługa błędów
|
|
||||||
*/
|
|
||||||
async function example6_error_handling(canvasInstance) {
|
|
||||||
try {
|
|
||||||
const maskImage = await create_mask_from_image_src('/path/to/nonexistent.png');
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Błąd podczas ładowania maski:', error);
|
|
||||||
|
|
||||||
await canvasInstance.startMaskEditor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 7: Maska z istniejącego elementu canvas na stronie
|
|
||||||
*/
|
|
||||||
async function example7_existing_canvas_element(canvasInstance, canvasElementId) {
|
|
||||||
const existingCanvas = document.getElementById(canvasElementId);
|
|
||||||
if (!existingCanvas) {
|
|
||||||
console.error('Canvas element not found:', canvasElementId);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const maskImage = await canvas_to_mask_image(existingCanvas);
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Przykład 8: Kombinowanie z istniejącą maską
|
|
||||||
*/
|
|
||||||
async function example8_combine_with_existing_mask(canvasInstance) {
|
|
||||||
const maskImage = await create_mask_from_image_src('/path/to/mask.png');
|
|
||||||
|
|
||||||
|
|
||||||
start_mask_editor_with_predefined_mask(canvasInstance, maskImage, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
|
||||||
example1_basic_usage,
|
|
||||||
example2_canvas_mask,
|
|
||||||
example3_direct_canvas_method,
|
|
||||||
example4_binary_data_mask,
|
|
||||||
example5_gradient_mask,
|
|
||||||
example6_error_handling,
|
|
||||||
example7_existing_canvas_element,
|
|
||||||
example8_combine_with_existing_mask
|
|
||||||
};
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
* @returns {string} UUID w formacie xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
* @returns {string} UUID w formacie xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
||||||
*/
|
*/
|
||||||
export function generateUUID() {
|
export function generateUUID() {
|
||||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||||
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
const r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
|
||||||
return v.toString(16);
|
return v.toString(16);
|
||||||
});
|
});
|
||||||
@@ -42,7 +42,7 @@ export function getSnapAdjustment(layer, gridSize = 64, snapThreshold = 10) {
|
|||||||
top: layer.y,
|
top: layer.y,
|
||||||
bottom: layer.y + layer.height
|
bottom: layer.y + layer.height
|
||||||
};
|
};
|
||||||
|
|
||||||
const x_adjustments = [
|
const x_adjustments = [
|
||||||
{type: 'x', delta: snapToGrid(layerEdges.left, gridSize) - layerEdges.left},
|
{type: 'x', delta: snapToGrid(layerEdges.left, gridSize) - layerEdges.left},
|
||||||
{type: 'x', delta: snapToGrid(layerEdges.right, gridSize) - layerEdges.right}
|
{type: 'x', delta: snapToGrid(layerEdges.right, gridSize) - layerEdges.right}
|
||||||
@@ -52,17 +52,17 @@ export function getSnapAdjustment(layer, gridSize = 64, snapThreshold = 10) {
|
|||||||
{type: 'y', delta: snapToGrid(layerEdges.top, gridSize) - layerEdges.top},
|
{type: 'y', delta: snapToGrid(layerEdges.top, gridSize) - layerEdges.top},
|
||||||
{type: 'y', delta: snapToGrid(layerEdges.bottom, gridSize) - layerEdges.bottom}
|
{type: 'y', delta: snapToGrid(layerEdges.bottom, gridSize) - layerEdges.bottom}
|
||||||
];
|
];
|
||||||
|
|
||||||
x_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
|
x_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
|
||||||
y_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
|
y_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
|
||||||
|
|
||||||
const bestXSnap = x_adjustments
|
const bestXSnap = x_adjustments
|
||||||
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
|
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
|
||||||
.sort((a, b) => a.abs - b.abs)[0];
|
.sort((a, b) => a.abs - b.abs)[0];
|
||||||
const bestYSnap = y_adjustments
|
const bestYSnap = y_adjustments
|
||||||
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
|
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
|
||||||
.sort((a, b) => a.abs - b.abs)[0];
|
.sort((a, b) => a.abs - b.abs)[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dx: bestXSnap ? bestXSnap.delta : 0,
|
dx: bestXSnap ? bestXSnap.delta : 0,
|
||||||
dy: bestYSnap ? bestYSnap.delta : 0
|
dy: bestYSnap ? bestYSnap.delta : 0
|
||||||
@@ -145,7 +145,7 @@ export function getStateSignature(layers) {
|
|||||||
if (layer.image && layer.image.src) {
|
if (layer.image && layer.image.src) {
|
||||||
sig.imageSrc = layer.image.src.substring(0, 100); // First 100 chars to avoid huge signatures
|
sig.imageSrc = layer.image.src.substring(0, 100); // First 100 chars to avoid huge signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
return sig;
|
return sig;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ export function debounce(func, wait, immediate) {
|
|||||||
*/
|
*/
|
||||||
export function throttle(func, limit) {
|
export function throttle(func, limit) {
|
||||||
let inThrottle;
|
let inThrottle;
|
||||||
return function(...args) {
|
return function (...args) {
|
||||||
if (!inThrottle) {
|
if (!inThrottle) {
|
||||||
func.apply(this, args);
|
func.apply(this, args);
|
||||||
inThrottle = true;
|
inThrottle = true;
|
||||||
@@ -241,7 +241,7 @@ export function createCanvas(width, height, contextType = '2d', contextOptions =
|
|||||||
if (width) canvas.width = width;
|
if (width) canvas.width = width;
|
||||||
if (height) canvas.height = height;
|
if (height) canvas.height = height;
|
||||||
const ctx = canvas.getContext(contextType, contextOptions);
|
const ctx = canvas.getContext(contextType, contextOptions);
|
||||||
return { canvas, ctx };
|
return {canvas, ctx};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,5 +284,5 @@ export function generateUniqueFileName(baseName, nodeId) {
|
|||||||
*/
|
*/
|
||||||
export function isPointInRect(pointX, pointY, rectX, rectY, rectWidth, rectHeight) {
|
export function isPointInRect(pointX, pointY, rectX, rectY, rectWidth, rectHeight) {
|
||||||
return pointX >= rectX && pointX <= rectX + rectWidth &&
|
return pointX >= rectX && pointX <= rectX + rectWidth &&
|
||||||
pointY >= rectY && pointY <= rectY + rectHeight;
|
pointY >= rectY && pointY <= rectY + rectHeight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {createModuleLogger} from "./LoggerUtils.js";
|
import {createModuleLogger} from "./LoggerUtils.js";
|
||||||
import {withErrorHandling, createValidationError} from "../ErrorHandler.js";
|
import {withErrorHandling, createValidationError} from "../ErrorHandler.js";
|
||||||
|
|
||||||
const log = createModuleLogger('ImageUtils');
|
const log = createModuleLogger('ImageUtils');
|
||||||
|
|
||||||
export function validateImageData(data) {
|
export function validateImageData(data) {
|
||||||
@@ -114,7 +115,7 @@ export function applyMaskToImageData(imageData, maskData) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const prepareImageForCanvas = withErrorHandling(function(inputImage) {
|
export const prepareImageForCanvas = withErrorHandling(function (inputImage) {
|
||||||
log.info("Preparing image for canvas:", inputImage);
|
log.info("Preparing image for canvas:", inputImage);
|
||||||
|
|
||||||
if (Array.isArray(inputImage)) {
|
if (Array.isArray(inputImage)) {
|
||||||
@@ -122,7 +123,7 @@ export const prepareImageForCanvas = withErrorHandling(function(inputImage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!inputImage || !inputImage.shape || !inputImage.data) {
|
if (!inputImage || !inputImage.shape || !inputImage.data) {
|
||||||
throw createValidationError("Invalid input image format", { inputImage });
|
throw createValidationError("Invalid input image format", {inputImage});
|
||||||
}
|
}
|
||||||
|
|
||||||
const shape = inputImage.shape;
|
const shape = inputImage.shape;
|
||||||
@@ -161,29 +162,29 @@ export const prepareImageForCanvas = withErrorHandling(function(inputImage) {
|
|||||||
* @param {HTMLImageElement|HTMLCanvasElement} image - Obraz do konwersji
|
* @param {HTMLImageElement|HTMLCanvasElement} image - Obraz do konwersji
|
||||||
* @returns {Promise<Object>} Tensor z danymi obrazu
|
* @returns {Promise<Object>} Tensor z danymi obrazu
|
||||||
*/
|
*/
|
||||||
export const imageToTensor = withErrorHandling(async function(image) {
|
export const imageToTensor = withErrorHandling(async function (image) {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
throw createValidationError("Image is required");
|
throw createValidationError("Image is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
canvas.width = image.width || image.naturalWidth;
|
canvas.width = image.width || image.naturalWidth;
|
||||||
canvas.height = image.height || image.naturalHeight;
|
canvas.height = image.height || image.naturalHeight;
|
||||||
|
|
||||||
ctx.drawImage(image, 0, 0);
|
ctx.drawImage(image, 0, 0);
|
||||||
|
|
||||||
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
const data = new Float32Array(canvas.width * canvas.height * 3);
|
const data = new Float32Array(canvas.width * canvas.height * 3);
|
||||||
|
|
||||||
for (let i = 0; i < imageData.data.length; i += 4) {
|
for (let i = 0; i < imageData.data.length; i += 4) {
|
||||||
const pixelIndex = i / 4;
|
const pixelIndex = i / 4;
|
||||||
data[pixelIndex * 3] = imageData.data[i] / 255;
|
data[pixelIndex * 3] = imageData.data[i] / 255;
|
||||||
data[pixelIndex * 3 + 1] = imageData.data[i + 1] / 255;
|
data[pixelIndex * 3 + 1] = imageData.data[i + 1] / 255;
|
||||||
data[pixelIndex * 3 + 2] = imageData.data[i + 2] / 255;
|
data[pixelIndex * 3 + 2] = imageData.data[i + 2] / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: data,
|
data: data,
|
||||||
shape: [1, canvas.height, canvas.width, 3],
|
shape: [1, canvas.height, canvas.width, 3],
|
||||||
@@ -197,33 +198,33 @@ export const imageToTensor = withErrorHandling(async function(image) {
|
|||||||
* @param {Object} tensor - Tensor z danymi obrazu
|
* @param {Object} tensor - Tensor z danymi obrazu
|
||||||
* @returns {Promise<HTMLImageElement>} Obraz HTML
|
* @returns {Promise<HTMLImageElement>} Obraz HTML
|
||||||
*/
|
*/
|
||||||
export const tensorToImage = withErrorHandling(async function(tensor) {
|
export const tensorToImage = withErrorHandling(async function (tensor) {
|
||||||
if (!tensor || !tensor.data || !tensor.shape) {
|
if (!tensor || !tensor.data || !tensor.shape) {
|
||||||
throw createValidationError("Invalid tensor format", { tensor });
|
throw createValidationError("Invalid tensor format", {tensor});
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, height, width, channels] = tensor.shape;
|
const [, height, width, channels] = tensor.shape;
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
const imageData = ctx.createImageData(width, height);
|
const imageData = ctx.createImageData(width, height);
|
||||||
const data = tensor.data;
|
const data = tensor.data;
|
||||||
|
|
||||||
for (let i = 0; i < width * height; i++) {
|
for (let i = 0; i < width * height; i++) {
|
||||||
const pixelIndex = i * 4;
|
const pixelIndex = i * 4;
|
||||||
const tensorIndex = i * channels;
|
const tensorIndex = i * channels;
|
||||||
|
|
||||||
imageData.data[pixelIndex] = Math.round(data[tensorIndex] * 255);
|
imageData.data[pixelIndex] = Math.round(data[tensorIndex] * 255);
|
||||||
imageData.data[pixelIndex + 1] = Math.round(data[tensorIndex + 1] * 255);
|
imageData.data[pixelIndex + 1] = Math.round(data[tensorIndex + 1] * 255);
|
||||||
imageData.data[pixelIndex + 2] = Math.round(data[tensorIndex + 2] * 255);
|
imageData.data[pixelIndex + 2] = Math.round(data[tensorIndex + 2] * 255);
|
||||||
imageData.data[pixelIndex + 3] = 255;
|
imageData.data[pixelIndex + 3] = 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.putImageData(imageData, 0, 0);
|
ctx.putImageData(imageData, 0, 0);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => resolve(img);
|
img.onload = () => resolve(img);
|
||||||
@@ -239,27 +240,27 @@ export const tensorToImage = withErrorHandling(async function(tensor) {
|
|||||||
* @param {number} maxHeight - Maksymalna wysokość
|
* @param {number} maxHeight - Maksymalna wysokość
|
||||||
* @returns {Promise<HTMLImageElement>} Przeskalowany obraz
|
* @returns {Promise<HTMLImageElement>} Przeskalowany obraz
|
||||||
*/
|
*/
|
||||||
export const resizeImage = withErrorHandling(async function(image, maxWidth, maxHeight) {
|
export const resizeImage = withErrorHandling(async function (image, maxWidth, maxHeight) {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
throw createValidationError("Image is required");
|
throw createValidationError("Image is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
const originalWidth = image.width || image.naturalWidth;
|
const originalWidth = image.width || image.naturalWidth;
|
||||||
const originalHeight = image.height || image.naturalHeight;
|
const originalHeight = image.height || image.naturalHeight;
|
||||||
const scale = Math.min(maxWidth / originalWidth, maxHeight / originalHeight);
|
const scale = Math.min(maxWidth / originalWidth, maxHeight / originalHeight);
|
||||||
const newWidth = Math.round(originalWidth * scale);
|
const newWidth = Math.round(originalWidth * scale);
|
||||||
const newHeight = Math.round(originalHeight * scale);
|
const newHeight = Math.round(originalHeight * scale);
|
||||||
|
|
||||||
canvas.width = newWidth;
|
canvas.width = newWidth;
|
||||||
canvas.height = newHeight;
|
canvas.height = newHeight;
|
||||||
ctx.imageSmoothingEnabled = true;
|
ctx.imageSmoothingEnabled = true;
|
||||||
ctx.imageSmoothingQuality = 'high';
|
ctx.imageSmoothingQuality = 'high';
|
||||||
|
|
||||||
ctx.drawImage(image, 0, 0, newWidth, newHeight);
|
ctx.drawImage(image, 0, 0, newWidth, newHeight);
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => resolve(img);
|
img.onload = () => resolve(img);
|
||||||
@@ -274,7 +275,7 @@ export const resizeImage = withErrorHandling(async function(image, maxWidth, max
|
|||||||
* @param {number} size - Rozmiar miniatury (kwadrat)
|
* @param {number} size - Rozmiar miniatury (kwadrat)
|
||||||
* @returns {Promise<HTMLImageElement>} Miniatura
|
* @returns {Promise<HTMLImageElement>} Miniatura
|
||||||
*/
|
*/
|
||||||
export const createThumbnail = withErrorHandling(async function(image, size = 128) {
|
export const createThumbnail = withErrorHandling(async function (image, size = 128) {
|
||||||
return resizeImage(image, size, size);
|
return resizeImage(image, size, size);
|
||||||
}, 'createThumbnail');
|
}, 'createThumbnail');
|
||||||
|
|
||||||
@@ -285,19 +286,19 @@ export const createThumbnail = withErrorHandling(async function(image, size = 12
|
|||||||
* @param {number} quality - Jakość (0-1) dla formatów stratnych
|
* @param {number} quality - Jakość (0-1) dla formatów stratnych
|
||||||
* @returns {string} Base64 string
|
* @returns {string} Base64 string
|
||||||
*/
|
*/
|
||||||
export const imageToBase64 = withErrorHandling(function(image, format = 'png', quality = 0.9) {
|
export const imageToBase64 = withErrorHandling(function (image, format = 'png', quality = 0.9) {
|
||||||
if (!image) {
|
if (!image) {
|
||||||
throw createValidationError("Image is required");
|
throw createValidationError("Image is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
canvas.width = image.width || image.naturalWidth;
|
canvas.width = image.width || image.naturalWidth;
|
||||||
canvas.height = image.height || image.naturalHeight;
|
canvas.height = image.height || image.naturalHeight;
|
||||||
|
|
||||||
ctx.drawImage(image, 0, 0);
|
ctx.drawImage(image, 0, 0);
|
||||||
|
|
||||||
const mimeType = `image/${format}`;
|
const mimeType = `image/${format}`;
|
||||||
return canvas.toDataURL(mimeType, quality);
|
return canvas.toDataURL(mimeType, quality);
|
||||||
}, 'imageToBase64');
|
}, 'imageToBase64');
|
||||||
@@ -307,7 +308,7 @@ export const imageToBase64 = withErrorHandling(function(image, format = 'png', q
|
|||||||
* @param {string} base64 - Base64 string
|
* @param {string} base64 - Base64 string
|
||||||
* @returns {Promise<HTMLImageElement>} Obraz
|
* @returns {Promise<HTMLImageElement>} Obraz
|
||||||
*/
|
*/
|
||||||
export const base64ToImage = withErrorHandling(function(base64) {
|
export const base64ToImage = withErrorHandling(function (base64) {
|
||||||
if (!base64) {
|
if (!base64) {
|
||||||
throw createValidationError("Base64 string is required");
|
throw createValidationError("Base64 string is required");
|
||||||
}
|
}
|
||||||
@@ -326,10 +327,10 @@ export const base64ToImage = withErrorHandling(function(base64) {
|
|||||||
* @returns {boolean} Czy obraz jest prawidłowy
|
* @returns {boolean} Czy obraz jest prawidłowy
|
||||||
*/
|
*/
|
||||||
export function isValidImage(image) {
|
export function isValidImage(image) {
|
||||||
return image &&
|
return image &&
|
||||||
(image instanceof HTMLImageElement || image instanceof HTMLCanvasElement) &&
|
(image instanceof HTMLImageElement || image instanceof HTMLCanvasElement) &&
|
||||||
image.width > 0 &&
|
image.width > 0 &&
|
||||||
image.height > 0;
|
image.height > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -371,18 +372,18 @@ export function createImageFromSource(source) {
|
|||||||
* @param {string} color - Kolor tła (CSS color)
|
* @param {string} color - Kolor tła (CSS color)
|
||||||
* @returns {Promise<HTMLImageElement>} Pusty obraz
|
* @returns {Promise<HTMLImageElement>} Pusty obraz
|
||||||
*/
|
*/
|
||||||
export const createEmptyImage = withErrorHandling(function(width, height, color = 'transparent') {
|
export const createEmptyImage = withErrorHandling(function (width, height, color = 'transparent') {
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
|
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
if (color !== 'transparent') {
|
if (color !== 'transparent') {
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.fillRect(0, 0, width, height);
|
ctx.fillRect(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.onload = () => resolve(img);
|
img.onload = () => resolve(img);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import {logger, LogLevel} from "../logger.js";
|
|||||||
*/
|
*/
|
||||||
export function createModuleLogger(moduleName, level = LogLevel.DEBUG) {
|
export function createModuleLogger(moduleName, level = LogLevel.DEBUG) {
|
||||||
logger.setModuleLevel(moduleName, level);
|
logger.setModuleLevel(moduleName, level);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
debug: (...args) => logger.debug(moduleName, ...args),
|
debug: (...args) => logger.debug(moduleName, ...args),
|
||||||
info: (...args) => logger.info(moduleName, ...args),
|
info: (...args) => logger.info(moduleName, ...args),
|
||||||
@@ -31,7 +31,7 @@ export function createAutoLogger(level = LogLevel.DEBUG) {
|
|||||||
const stack = new Error().stack;
|
const stack = new Error().stack;
|
||||||
const match = stack.match(/\/([^\/]+)\.js/);
|
const match = stack.match(/\/([^\/]+)\.js/);
|
||||||
const moduleName = match ? match[1] : 'Unknown';
|
const moduleName = match ? match[1] : 'Unknown';
|
||||||
|
|
||||||
return createModuleLogger(moduleName, level);
|
return createModuleLogger(moduleName, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ export function createAutoLogger(level = LogLevel.DEBUG) {
|
|||||||
* @returns {Function} Opakowana funkcja
|
* @returns {Function} Opakowana funkcja
|
||||||
*/
|
*/
|
||||||
export function withErrorLogging(operation, log, operationName) {
|
export function withErrorLogging(operation, log, operationName) {
|
||||||
return async function(...args) {
|
return async function (...args) {
|
||||||
try {
|
try {
|
||||||
log.debug(`Starting ${operationName}`);
|
log.debug(`Starting ${operationName}`);
|
||||||
const result = await operation.apply(this, args);
|
const result = await operation.apply(this, args);
|
||||||
@@ -62,10 +62,10 @@ export function withErrorLogging(operation, log, operationName) {
|
|||||||
* @param {string} methodName - Nazwa metody
|
* @param {string} methodName - Nazwa metody
|
||||||
*/
|
*/
|
||||||
export function logMethod(log, methodName) {
|
export function logMethod(log, methodName) {
|
||||||
return function(target, propertyKey, descriptor) {
|
return function (target, propertyKey, descriptor) {
|
||||||
const originalMethod = descriptor.value;
|
const originalMethod = descriptor.value;
|
||||||
|
|
||||||
descriptor.value = async function(...args) {
|
descriptor.value = async function (...args) {
|
||||||
try {
|
try {
|
||||||
log.debug(`${methodName || propertyKey} started`);
|
log.debug(`${methodName || propertyKey} started`);
|
||||||
const result = await originalMethod.apply(this, args);
|
const result = await originalMethod.apply(this, args);
|
||||||
@@ -76,7 +76,7 @@ export function logMethod(log, methodName) {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class WebSocketManager {
|
|||||||
try {
|
try {
|
||||||
const data = JSON.parse(event.data);
|
const data = JSON.parse(event.data);
|
||||||
log.debug("Received message:", data);
|
log.debug("Received message:", data);
|
||||||
|
|
||||||
if (data.type === 'ack' && data.nodeId) {
|
if (data.type === 'ack' && data.nodeId) {
|
||||||
const callback = this.ackCallbacks.get(data.nodeId);
|
const callback = this.ackCallbacks.get(data.nodeId);
|
||||||
if (callback) {
|
if (callback) {
|
||||||
@@ -130,7 +130,6 @@ class WebSocketManager {
|
|||||||
log.warn("WebSocket not open. Queuing message.");
|
log.warn("WebSocket not open. Queuing message.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
this.messageQueue.push(message);
|
this.messageQueue.push(message);
|
||||||
if (!this.isConnecting) {
|
if (!this.isConnecting) {
|
||||||
this.connect();
|
this.connect();
|
||||||
@@ -147,7 +146,6 @@ class WebSocketManager {
|
|||||||
log.debug(`Flushing ${this.messageQueue.length} queued messages.`);
|
log.debug(`Flushing ${this.messageQueue.length} queued messages.`);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while (this.messageQueue.length > 0) {
|
while (this.messageQueue.length > 0) {
|
||||||
const message = this.messageQueue.shift();
|
const message = this.messageQueue.shift();
|
||||||
this.socket.send(message);
|
this.socket.send(message);
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function get_mask_editor_cancel_button(app) {
|
|||||||
'button[onclick*="Cancel"]',
|
'button[onclick*="Cancel"]',
|
||||||
'input[value="Cancel"]'
|
'input[value="Cancel"]'
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const selector of cancelSelectors) {
|
for (const selector of cancelSelectors) {
|
||||||
try {
|
try {
|
||||||
const button = document.querySelector(selector);
|
const button = document.querySelector(selector);
|
||||||
@@ -59,7 +59,7 @@ function get_mask_editor_cancel_button(app) {
|
|||||||
if (editorElement) {
|
if (editorElement) {
|
||||||
return editorElement?.parentElement?.lastChild?.childNodes[2];
|
return editorElement?.parentElement?.lastChild?.childNodes[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,11 +72,11 @@ export function mask_editor_listen_for_cancel(app, callback) {
|
|||||||
|
|
||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
const maxAttempts = 50; // 5 sekund
|
const maxAttempts = 50; // 5 sekund
|
||||||
|
|
||||||
const findAndAttachListener = () => {
|
const findAndAttachListener = () => {
|
||||||
attempts++;
|
attempts++;
|
||||||
const cancel_button = get_mask_editor_cancel_button(app);
|
const cancel_button = get_mask_editor_cancel_button(app);
|
||||||
|
|
||||||
if (cancel_button && !cancel_button.filter_listener_added) {
|
if (cancel_button && !cancel_button.filter_listener_added) {
|
||||||
log.info("Cancel button found, attaching listener");
|
log.info("Cancel button found, attaching listener");
|
||||||
cancel_button.addEventListener('click', callback);
|
cancel_button.addEventListener('click', callback);
|
||||||
@@ -91,7 +91,7 @@ export function mask_editor_listen_for_cancel(app, callback) {
|
|||||||
const globalClickHandler = (event) => {
|
const globalClickHandler = (event) => {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
const text = target.textContent || target.value || '';
|
const text = target.textContent || target.value || '';
|
||||||
if (text.toLowerCase().includes('cancel') ||
|
if (text.toLowerCase().includes('cancel') ||
|
||||||
target.id.toLowerCase().includes('cancel') ||
|
target.id.toLowerCase().includes('cancel') ||
|
||||||
target.className.toLowerCase().includes('cancel')) {
|
target.className.toLowerCase().includes('cancel')) {
|
||||||
log.info("Cancel detected via global click handler");
|
log.info("Cancel detected via global click handler");
|
||||||
@@ -99,12 +99,12 @@ export function mask_editor_listen_for_cancel(app, callback) {
|
|||||||
document.removeEventListener('click', globalClickHandler);
|
document.removeEventListener('click', globalClickHandler);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener('click', globalClickHandler);
|
document.addEventListener('click', globalClickHandler);
|
||||||
log.debug("Added global click handler for cancel detection");
|
log.debug("Added global click handler for cancel detection");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
findAndAttachListener();
|
findAndAttachListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +127,7 @@ export function start_mask_editor_with_predefined_mask(canvasInstance, maskImage
|
|||||||
log.error('Canvas instance and mask image are required');
|
log.error('Canvas instance and mask image are required');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasInstance.startMaskEditor(maskImage, sendCleanImage);
|
canvasInstance.startMaskEditor(maskImage, sendCleanImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +142,6 @@ export function start_mask_editor_auto(canvasInstance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
canvasInstance.startMaskEditor();
|
canvasInstance.startMaskEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user