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:
Dariusz L
2025-07-01 06:44:26 +02:00
parent a0ceb3b97c
commit b89956d2ba
10 changed files with 142 additions and 297 deletions

View File

@@ -1,5 +1,5 @@
import { app, ComfyApp } from "../../scripts/app.js";
import { api } from "../../scripts/api.js";
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,13 +9,13 @@ 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, 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');
/**
* Canvas - Fasada dla systemu rysowania
*
*
* Klasa Canvas pełni rolę fasady, oferując uproszczony interfejs wysokiego poziomu
* 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
@@ -69,21 +69,21 @@ export class Canvas {
return new Promise((resolve, reject) => {
const check = () => {
const widget = node.widgets.find(w => w.name === name);
if (widget) {
resolve(widget);
} else if (Date.now() - startTime > timeout) {
reject(new Error(`Widget "${name}" not found within timeout.`));
} else {
setTimeout(check, interval);
}
const widget = node.widgets.find(w => w.name === name);
if (widget) {
resolve(widget);
} else if (Date.now() - startTime > timeout) {
reject(new Error(`Widget "${name}" not found within timeout.`));
} else {
setTimeout(check, interval);
}
};
check();
});
}
/**
* Kontroluje widoczność podglądu canvas
* @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);
if (imagePreviewWidget) {
console.log("Found $$canvas-image-preview widget, controlling visibility");
if (visible) {
console.log("=== SHOWING WIDGET ===");
@@ -110,10 +110,10 @@ export class Canvas {
}
console.log("Setting computeSize to fixed height 250");
imagePreviewWidget.computeSize = function() {
imagePreviewWidget.computeSize = function () {
return [0, 250]; // Szerokość 0 (auto), wysokość 250
};
console.log("ImagePreviewWidget shown");
} else {
console.log("=== HIDING WIDGET ===");
@@ -127,14 +127,14 @@ export class Canvas {
if ('hidden' in imagePreviewWidget) {
imagePreviewWidget.hidden = true;
}
imagePreviewWidget.computeSize = function() {
imagePreviewWidget.computeSize = function () {
return [0, 0]; // Szerokość 0, wysokość 0
};
};
console.log("ImagePreviewWidget hidden with zero size");
}
console.log("=== FINAL WIDGET STATE ===");
this.render()
} else {
@@ -173,8 +173,6 @@ export class Canvas {
}
/**
* Ładuje stan canvas z bazy danych
*/
@@ -292,8 +290,6 @@ export class Canvas {
}
/**
* Uruchamia edytor masek
* @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();
}
if (!blob) {
log.warn("Canvas is empty, cannot open mask editor.");
return;
@@ -344,28 +340,28 @@ export class Canvas {
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();
ComfyApp.copyToClipspace(this.node);
ComfyApp.clipspace_return_node = this.node;
ComfyApp.open_maskeditor();
this.setupCancelListener();
this.editorWasShowing = false;
this.waitWhileMaskEditing();
if (predefinedMask) {
this.waitForMaskEditorAndApplyMask();
}
this.setupCancelListener();
if (predefinedMask) {
this.waitForMaskEditorAndApplyMask();
}
} catch (error) {
log.error("Error preparing image for mask editor:", error);
@@ -374,8 +370,6 @@ export class Canvas {
}
/**
* Inicjalizuje podstawowe właściwości canvas
*/
@@ -428,7 +422,7 @@ export class Canvas {
const mouseX_Canvas = mouseX_DOM * scaleX;
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ę
*/
waitForMaskEditorAndApplyMask() {
let attempts = 0;
const maxAttempts = 100; // Zwiększone do 10 sekund oczekiwania
const checkEditor = () => {
attempts++;
if (mask_editor_showing(app)) {
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
let editorReady = false;
if (useNewEditor) {
const MaskEditorDialog = window.MaskEditorDialog;
@@ -541,7 +533,7 @@ export class Canvas {
log.info("Old mask editor detected as ready");
}
}
if (editorReady) {
log.info("Applying mask to editor after", attempts * 100, "ms wait");
@@ -572,7 +564,7 @@ export class Canvas {
this.pendingMask = null;
}
};
checkEditor();
}
@@ -584,7 +576,7 @@ export class Canvas {
try {
const useNewEditor = app.ui.settings.getSettingValue('Comfy.MaskEditor.UseNewEditor');
if (useNewEditor) {
const MaskEditorDialog = window.MaskEditorDialog;
@@ -599,7 +591,7 @@ export class Canvas {
await this.applyMaskToOldEditor(maskData);
}
log.info("Predefined mask applied to mask editor successfully");
} catch (error) {
log.error("Failed to apply predefined mask to editor:", error);
@@ -653,7 +645,7 @@ export class Canvas {
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);
maskCtx.clearRect(0, 0, maskCanvas.width, maskCanvas.height);
@@ -671,11 +663,11 @@ export class Canvas {
async processMaskForEditor(maskData, targetWidth, targetHeight, maskColor) {
const originalWidth = maskData.width || maskData.naturalWidth || this.width;
const originalHeight = maskData.height || maskData.naturalHeight || this.height;
log.info("Processing mask for editor:", {
originalSize: { width: originalWidth, height: originalHeight },
targetSize: { width: targetWidth, height: targetHeight },
canvasSize: { width: this.width, height: this.height }
originalSize: {width: originalWidth, height: originalHeight},
targetSize: {width: targetWidth, height: targetHeight},
canvasSize: {width: this.width, height: this.height}
});
const tempCanvas = document.createElement('canvas');
@@ -693,16 +685,16 @@ export class Canvas {
const offsetX = (targetWidth - scaledWidth) / 2;
const offsetY = (targetHeight - scaledHeight) / 2;
tempCtx.drawImage(maskData, offsetX, offsetY, scaledWidth, scaledHeight);
log.info("Mask drawn scaled to original image size:", {
originalSize: { width: originalWidth, height: originalHeight },
targetSize: { width: targetWidth, height: targetHeight },
canvasSize: { width: this.width, height: this.height },
log.info("Mask drawn scaled to original image size:", {
originalSize: {width: originalWidth, height: originalHeight},
targetSize: {width: targetWidth, height: targetHeight},
canvasSize: {width: this.width, height: this.height},
scaleToOriginal: scaleToOriginal,
finalSize: { width: scaledWidth, height: scaledHeight },
offset: { x: offsetX, y: offsetY }
finalSize: {width: scaledWidth, height: scaledHeight},
offset: {x: offsetX, y: offsetY}
});
const imageData = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
@@ -718,7 +710,7 @@ export class Canvas {
}
tempCtx.putImageData(imageData, 0, 0);
log.info("Mask processing completed - full size scaling applied");
return tempCanvas;
}
@@ -744,10 +736,10 @@ export class Canvas {
if (mask_editor_showing(app)) {
this.editorWasShowing = true;
}
if (!mask_editor_showing(app) && this.editorWasShowing) {
this.editorWasShowing = false;
setTimeout(() => this.handleMaskEditorClose(), 100);
this.editorWasShowing = false;
setTimeout(() => this.handleMaskEditorClose(), 100);
} else {
setTimeout(this.waitWhileMaskEditing.bind(this), 100);
}
@@ -778,7 +770,7 @@ export class Canvas {
tempCanvas.width = this.width;
tempCanvas.height = this.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(resultImage, 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) {
const originalAlpha = data[i + 3];
data[i] = 255;
data[i] = 255;
data[i + 1] = 255;
data[i + 2] = 255;
data[i + 3] = 255 - originalAlpha;
@@ -797,7 +789,7 @@ export class Canvas {
const maskAsImage = new Image();
maskAsImage.src = tempCanvas.toDataURL();
await new Promise(resolve => maskAsImage.onload = resolve);
const maskCtx = this.maskTool.maskCtx;
const destX = -this.maskTool.x;
const destY = -this.maskTool.y;
@@ -807,10 +799,10 @@ export class Canvas {
maskCtx.clearRect(destX, destY, this.width, this.height);
maskCtx.drawImage(maskAsImage, destX, destY);
this.render();
this.saveState();
const new_preview = new Image();
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();
@@ -826,8 +818,6 @@ export class Canvas {
}
/**
* Zapisuje obecny stan maski przed otwarciem editora
* @returns {Object} Zapisany stan maski
@@ -929,7 +919,7 @@ export class Canvas {
tempCanvas.width = this.width;
tempCanvas.height = this.height;
const tempCtx = tempCanvas.getContext('2d');
tempCtx.drawImage(resultImage, 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) {
const originalAlpha = data[i + 3];
data[i] = 255;
data[i] = 255;
data[i + 1] = 255;
data[i + 2] = 255;
data[i + 3] = 255 - originalAlpha;
@@ -948,7 +938,7 @@ export class Canvas {
const maskAsImage = new Image();
maskAsImage.src = tempCanvas.toDataURL();
await new Promise(resolve => maskAsImage.onload = resolve);
const maskCtx = this.maskTool.maskCtx;
const destX = -this.maskTool.x;
const destY = -this.maskTool.y;
@@ -958,10 +948,10 @@ export class Canvas {
maskCtx.clearRect(destX, destY, this.width, this.height);
maskCtx.drawImage(maskAsImage, destX, destY);
this.render();
this.saveState();
const new_preview = new Image();
const blob = await this.canvasLayers.getFlattenedCanvasWithMaskAsBlob();

View File

@@ -2,7 +2,7 @@ import {saveImage, removeImage} from "./db.js";
import {createModuleLogger} from "./utils/LoggerUtils.js";
import {generateUUID, generateUniqueFileName} from "./utils/CommonUtils.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');
@@ -141,7 +141,7 @@ export class CanvasLayers {
try {
log.info("Attempting to paste from system clipboard");
const clipboardItems = await navigator.clipboard.read();
for (const item of clipboardItems) {
const imageType = item.types.find(type => type.startsWith('image/'));
@@ -160,7 +160,7 @@ export class CanvasLayers {
return true;
}
}
log.info("No image found in system clipboard");
return false;
} catch (error) {
@@ -178,7 +178,7 @@ export class CanvasLayers {
const imageId = generateUUID();
await saveImage(imageId, image.src);
this.canvas.imageCache.set(imageId, image.src);
let finalWidth = image.width;
let finalHeight = image.height;
let finalX, finalY;
@@ -268,7 +268,7 @@ export class CanvasLayers {
*/
resizeLayer(scale) {
if (this.canvas.selectedLayers.length === 0) return;
this.canvas.selectedLayers.forEach(layer => {
layer.width *= scale;
layer.height *= scale;
@@ -283,7 +283,7 @@ export class CanvasLayers {
*/
rotateLayer(angle) {
if (this.canvas.selectedLayers.length === 0) return;
this.canvas.selectedLayers.forEach(layer => {
layer.rotation += angle;
});

View File

@@ -488,7 +488,7 @@ async function createCanvasWidget(node, widget, app) {
helpTooltip.style.visibility = 'hidden';
helpTooltip.style.display = 'block';
const buttonRect = e.target.getBoundingClientRect();
const tooltipRect = helpTooltip.getBoundingClientRect();
const viewportWidth = window.innerWidth;
@@ -1004,7 +1004,7 @@ async function createCanvasWidget(node, widget, app) {
log.debug("Image object loaded from dropped data:URL.");
const fitOnAddWidget = node.widgets.find(w => w.name === "fit_on_add");
const addMode = fitOnAddWidget && fitOnAddWidget.value ? 'fit' : 'center';
await canvas.addLayer(img, {}, addMode);
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");
if (showPreviewWidget) {
const originalCallback = showPreviewWidget.callback;
showPreviewWidget.callback = function(value) {
showPreviewWidget.callback = function (value) {
if (originalCallback) {
originalCallback.call(this, value);
}
@@ -1124,7 +1124,6 @@ async function createCanvasWidget(node, widget, app) {
}
return {
canvas: canvas,
panel: controlPanel
@@ -1251,13 +1250,13 @@ app.registerExtension({
const self = this;
const maskEditorIndex = options.findIndex(option =>
const maskEditorIndex = options.findIndex(option =>
option && option.content === "Open in MaskEditor"
);
if (maskEditorIndex !== -1) {
options.splice(maskEditorIndex, 1);
}
const newOptions = [
{
content: "Open in MaskEditor",

View File

@@ -283,7 +283,6 @@ export class MaskTool {
setMask(image) {
const destX = -this.x;
const destY = -this.y;

View File

@@ -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
};

View File

@@ -8,7 +8,7 @@
* @returns {string} UUID w formacie xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
*/
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);
return v.toString(16);
});
@@ -42,7 +42,7 @@ export function getSnapAdjustment(layer, gridSize = 64, snapThreshold = 10) {
top: layer.y,
bottom: layer.y + layer.height
};
const x_adjustments = [
{type: 'x', delta: snapToGrid(layerEdges.left, gridSize) - layerEdges.left},
{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.bottom, gridSize) - layerEdges.bottom}
];
x_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
y_adjustments.forEach(adj => adj.abs = Math.abs(adj.delta));
const bestXSnap = x_adjustments
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
.sort((a, b) => a.abs - b.abs)[0];
const bestYSnap = y_adjustments
.filter(adj => adj.abs < snapThreshold && adj.abs > 1e-9)
.sort((a, b) => a.abs - b.abs)[0];
return {
dx: bestXSnap ? bestXSnap.delta : 0,
dy: bestYSnap ? bestYSnap.delta : 0
@@ -145,7 +145,7 @@ export function getStateSignature(layers) {
if (layer.image && layer.image.src) {
sig.imageSrc = layer.image.src.substring(0, 100); // First 100 chars to avoid huge signatures
}
return sig;
}));
}
@@ -179,7 +179,7 @@ export function debounce(func, wait, immediate) {
*/
export function throttle(func, limit) {
let inThrottle;
return function(...args) {
return function (...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
@@ -241,7 +241,7 @@ export function createCanvas(width, height, contextType = '2d', contextOptions =
if (width) canvas.width = width;
if (height) canvas.height = height;
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) {
return pointX >= rectX && pointX <= rectX + rectWidth &&
pointY >= rectY && pointY <= rectY + rectHeight;
pointY >= rectY && pointY <= rectY + rectHeight;
}

View File

@@ -1,5 +1,6 @@
import {createModuleLogger} from "./LoggerUtils.js";
import {withErrorHandling, createValidationError} from "../ErrorHandler.js";
const log = createModuleLogger('ImageUtils');
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);
if (Array.isArray(inputImage)) {
@@ -122,7 +123,7 @@ export const prepareImageForCanvas = withErrorHandling(function(inputImage) {
}
if (!inputImage || !inputImage.shape || !inputImage.data) {
throw createValidationError("Invalid input image format", { inputImage });
throw createValidationError("Invalid input image format", {inputImage});
}
const shape = inputImage.shape;
@@ -161,29 +162,29 @@ export const prepareImageForCanvas = withErrorHandling(function(inputImage) {
* @param {HTMLImageElement|HTMLCanvasElement} image - Obraz do konwersji
* @returns {Promise<Object>} Tensor z danymi obrazu
*/
export const imageToTensor = withErrorHandling(async function(image) {
export const imageToTensor = withErrorHandling(async function (image) {
if (!image) {
throw createValidationError("Image is required");
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = image.width || image.naturalWidth;
canvas.height = image.height || image.naturalHeight;
ctx.drawImage(image, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = new Float32Array(canvas.width * canvas.height * 3);
for (let i = 0; i < imageData.data.length; i += 4) {
const pixelIndex = i / 4;
data[pixelIndex * 3] = imageData.data[i] / 255;
data[pixelIndex * 3 + 1] = imageData.data[i + 1] / 255;
data[pixelIndex * 3 + 2] = imageData.data[i + 2] / 255;
}
return {
data: data,
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
* @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) {
throw createValidationError("Invalid tensor format", { tensor });
throw createValidationError("Invalid tensor format", {tensor});
}
const [, height, width, channels] = tensor.shape;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
const imageData = ctx.createImageData(width, height);
const data = tensor.data;
for (let i = 0; i < width * height; i++) {
const pixelIndex = i * 4;
const tensorIndex = i * channels;
imageData.data[pixelIndex] = Math.round(data[tensorIndex] * 255);
imageData.data[pixelIndex + 1] = Math.round(data[tensorIndex + 1] * 255);
imageData.data[pixelIndex + 2] = Math.round(data[tensorIndex + 2] * 255);
imageData.data[pixelIndex + 3] = 255;
}
ctx.putImageData(imageData, 0, 0);
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
@@ -239,27 +240,27 @@ export const tensorToImage = withErrorHandling(async function(tensor) {
* @param {number} maxHeight - Maksymalna wysokość
* @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) {
throw createValidationError("Image is required");
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const originalWidth = image.width || image.naturalWidth;
const originalHeight = image.height || image.naturalHeight;
const scale = Math.min(maxWidth / originalWidth, maxHeight / originalHeight);
const newWidth = Math.round(originalWidth * scale);
const newHeight = Math.round(originalHeight * scale);
canvas.width = newWidth;
canvas.height = newHeight;
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = 'high';
ctx.drawImage(image, 0, 0, newWidth, newHeight);
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
@@ -274,7 +275,7 @@ export const resizeImage = withErrorHandling(async function(image, maxWidth, max
* @param {number} size - Rozmiar miniatury (kwadrat)
* @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);
}, 'createThumbnail');
@@ -285,19 +286,19 @@ export const createThumbnail = withErrorHandling(async function(image, size = 12
* @param {number} quality - Jakość (0-1) dla formatów stratnych
* @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) {
throw createValidationError("Image is required");
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = image.width || image.naturalWidth;
canvas.height = image.height || image.naturalHeight;
ctx.drawImage(image, 0, 0);
const mimeType = `image/${format}`;
return canvas.toDataURL(mimeType, quality);
}, 'imageToBase64');
@@ -307,7 +308,7 @@ export const imageToBase64 = withErrorHandling(function(image, format = 'png', q
* @param {string} base64 - Base64 string
* @returns {Promise<HTMLImageElement>} Obraz
*/
export const base64ToImage = withErrorHandling(function(base64) {
export const base64ToImage = withErrorHandling(function (base64) {
if (!base64) {
throw createValidationError("Base64 string is required");
}
@@ -326,10 +327,10 @@ export const base64ToImage = withErrorHandling(function(base64) {
* @returns {boolean} Czy obraz jest prawidłowy
*/
export function isValidImage(image) {
return image &&
(image instanceof HTMLImageElement || image instanceof HTMLCanvasElement) &&
image.width > 0 &&
image.height > 0;
return image &&
(image instanceof HTMLImageElement || image instanceof HTMLCanvasElement) &&
image.width > 0 &&
image.height > 0;
}
/**
@@ -371,18 +372,18 @@ export function createImageFromSource(source) {
* @param {string} color - Kolor tła (CSS color)
* @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 ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
if (color !== 'transparent') {
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
}
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);

View File

@@ -13,7 +13,7 @@ import {logger, LogLevel} from "../logger.js";
*/
export function createModuleLogger(moduleName, level = LogLevel.DEBUG) {
logger.setModuleLevel(moduleName, level);
return {
debug: (...args) => logger.debug(moduleName, ...args),
info: (...args) => logger.info(moduleName, ...args),
@@ -31,7 +31,7 @@ export function createAutoLogger(level = LogLevel.DEBUG) {
const stack = new Error().stack;
const match = stack.match(/\/([^\/]+)\.js/);
const moduleName = match ? match[1] : 'Unknown';
return createModuleLogger(moduleName, level);
}
@@ -43,7 +43,7 @@ export function createAutoLogger(level = LogLevel.DEBUG) {
* @returns {Function} Opakowana funkcja
*/
export function withErrorLogging(operation, log, operationName) {
return async function(...args) {
return async function (...args) {
try {
log.debug(`Starting ${operationName}`);
const result = await operation.apply(this, args);
@@ -62,10 +62,10 @@ export function withErrorLogging(operation, log, operationName) {
* @param {string} methodName - Nazwa metody
*/
export function logMethod(log, methodName) {
return function(target, propertyKey, descriptor) {
return function (target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function(...args) {
descriptor.value = async function (...args) {
try {
log.debug(`${methodName || propertyKey} started`);
const result = await originalMethod.apply(this, args);
@@ -76,7 +76,7 @@ export function logMethod(log, methodName) {
throw error;
}
};
return descriptor;
};
}

View File

@@ -45,7 +45,7 @@ class WebSocketManager {
try {
const data = JSON.parse(event.data);
log.debug("Received message:", data);
if (data.type === 'ack' && data.nodeId) {
const callback = this.ackCallbacks.get(data.nodeId);
if (callback) {
@@ -130,7 +130,6 @@ class WebSocketManager {
log.warn("WebSocket not open. Queuing message.");
this.messageQueue.push(message);
if (!this.isConnecting) {
this.connect();
@@ -147,7 +146,6 @@ class WebSocketManager {
log.debug(`Flushing ${this.messageQueue.length} queued messages.`);
while (this.messageQueue.length > 0) {
const message = this.messageQueue.shift();
this.socket.send(message);

View File

@@ -33,7 +33,7 @@ function get_mask_editor_cancel_button(app) {
'button[onclick*="Cancel"]',
'input[value="Cancel"]'
];
for (const selector of cancelSelectors) {
try {
const button = document.querySelector(selector);
@@ -59,7 +59,7 @@ function get_mask_editor_cancel_button(app) {
if (editorElement) {
return editorElement?.parentElement?.lastChild?.childNodes[2];
}
return null;
}
@@ -72,11 +72,11 @@ export function mask_editor_listen_for_cancel(app, callback) {
let attempts = 0;
const maxAttempts = 50; // 5 sekund
const findAndAttachListener = () => {
attempts++;
const cancel_button = get_mask_editor_cancel_button(app);
if (cancel_button && !cancel_button.filter_listener_added) {
log.info("Cancel button found, attaching listener");
cancel_button.addEventListener('click', callback);
@@ -91,7 +91,7 @@ export function mask_editor_listen_for_cancel(app, callback) {
const globalClickHandler = (event) => {
const target = event.target;
const text = target.textContent || target.value || '';
if (text.toLowerCase().includes('cancel') ||
if (text.toLowerCase().includes('cancel') ||
target.id.toLowerCase().includes('cancel') ||
target.className.toLowerCase().includes('cancel')) {
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.addEventListener('click', globalClickHandler);
log.debug("Added global click handler for cancel detection");
}
};
findAndAttachListener();
}
@@ -127,7 +127,7 @@ export function start_mask_editor_with_predefined_mask(canvasInstance, maskImage
log.error('Canvas instance and mask image are required');
return;
}
canvasInstance.startMaskEditor(maskImage, sendCleanImage);
}
@@ -142,7 +142,6 @@ export function start_mask_editor_auto(canvasInstance) {
}
canvasInstance.startMaskEditor();
}