Files
Comfyui-LayerForge/js/Mask_tool.js
2025-06-26 03:30:44 +02:00

189 lines
6.3 KiB
JavaScript

import {createModuleLogger} from "./LoggerUtils.js";
// Inicjalizacja loggera dla modułu Mask_tool
const log = createModuleLogger('Mask_tool');
export class MaskTool {
constructor(canvasInstance) {
this.canvasInstance = canvasInstance;
this.mainCanvas = canvasInstance.canvas;
this.maskCanvas = document.createElement('canvas');
this.maskCtx = this.maskCanvas.getContext('2d');
this.isActive = false;
this.brushSize = 20;
this.brushStrength = 0.5;
this.brushSoftness = 0.5; // Domyślna miękkość pędzla (0 - twardy, 1 - bardzo miękki)
this.isDrawing = false;
this.lastPosition = null;
this.initMaskCanvas();
}
setBrushSoftness(softness) {
this.brushSoftness = Math.max(0, Math.min(1, softness));
}
initMaskCanvas() {
this.maskCanvas.width = this.mainCanvas.width;
this.maskCanvas.height = this.mainCanvas.height;
// Wyczyść canvas bez zapisywania do historii
this.maskCtx.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height);
}
activate() {
this.isActive = true;
this.canvasInstance.interaction.mode = 'drawingMask';
// Zapisz początkowy stan maski tylko jeśli historia jest pusta
if (this.canvasInstance.canvasState && this.canvasInstance.canvasState.maskUndoStack.length === 0) {
this.canvasInstance.canvasState.saveMaskState();
}
// Aktualizuj przyciski historii po przełączeniu na tryb maski
this.canvasInstance.updateHistoryButtons();
log.info("Mask tool activated");
}
deactivate() {
this.isActive = false;
this.canvasInstance.interaction.mode = 'none';
// Aktualizuj przyciski historii po przełączeniu z trybu maski
this.canvasInstance.updateHistoryButtons();
log.info("Mask tool deactivated");
}
setBrushSize(size) {
this.brushSize = Math.max(1, size);
}
setBrushStrength(strength) {
this.brushStrength = Math.max(0, Math.min(1, strength));
}
handleMouseDown(worldCoords) {
if (!this.isActive) return;
this.isDrawing = true;
this.lastPosition = worldCoords;
this.draw(worldCoords);
}
handleMouseMove(worldCoords) {
if (!this.isActive || !this.isDrawing) return;
this.draw(worldCoords);
this.lastPosition = worldCoords;
}
handleMouseUp() {
if (!this.isActive) return;
// Jeśli narzędzie rysowało, zapisz stan maski
if (this.isDrawing) {
// Zakończ rysowanie
this.isDrawing = false;
this.lastPosition = null;
// Zapisz stan maski do historii
if (this.canvasInstance.canvasState) {
this.canvasInstance.canvasState.saveMaskState();
}
}
}
draw(worldCoords) {
if (!this.lastPosition) {
this.lastPosition = worldCoords;
}
this.maskCtx.beginPath();
this.maskCtx.moveTo(this.lastPosition.x, this.lastPosition.y);
this.maskCtx.lineTo(worldCoords.x, worldCoords.y);
// Utwórz styl pędzla w zależności od miękkości
const gradientRadius = this.brushSize / 2;
if (this.brushSoftness === 0) {
// Twardy pędzel - użyj jednolitego koloru
this.maskCtx.strokeStyle = `rgba(255, 255, 255, ${this.brushStrength})`;
} else {
// Miękki pędzel - użyj gradientu radialnego
const innerRadius = gradientRadius * this.brushSoftness;
const gradient = this.maskCtx.createRadialGradient(
worldCoords.x, worldCoords.y, innerRadius,
worldCoords.x, worldCoords.y, gradientRadius
);
gradient.addColorStop(0, `rgba(255, 255, 255, ${this.brushStrength})`);
gradient.addColorStop(1, `rgba(255, 255, 255, 0)`);
this.maskCtx.strokeStyle = gradient;
}
this.maskCtx.lineWidth = this.brushSize;
this.maskCtx.lineCap = 'round';
this.maskCtx.lineJoin = 'round';
this.maskCtx.globalCompositeOperation = 'source-over';
this.maskCtx.stroke();
}
clear() {
this.maskCtx.clearRect(0, 0, this.maskCanvas.width, this.maskCanvas.height);
// Zapisz stan po wyczyszczeniu maski tylko jeśli narzędzie jest aktywne
if (this.isActive && this.canvasInstance.canvasState) {
this.canvasInstance.canvasState.saveMaskState();
}
}
getMask() {
return this.maskCanvas;
}
getMaskImageWithAlpha() {
const tempCanvas = document.createElement('canvas');
tempCanvas.width = this.maskCanvas.width;
tempCanvas.height = this.maskCanvas.height;
const tempCtx = tempCanvas.getContext('2d');
// Kopiuj maskę na tymczasowy canvas
tempCtx.drawImage(this.maskCanvas, 0, 0);
// Pobierz dane pikseli
const imageData = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
const data = imageData.data;
// Modyfikuj kanał alfa, aby zachować zróżnicowaną przezroczystość
for (let i = 0; i < data.length; i += 4) {
const alpha = data[i]; // Wartość alfa (0-255)
data[i] = 255; // Czerwony
data[i + 1] = 255; // Zielony
data[i + 2] = 255; // Niebieski
data[i + 3] = alpha; // Alfa (zachowaj oryginalną wartość)
}
// Zapisz zmodyfikowane dane pikseli
tempCtx.putImageData(imageData, 0, 0);
// Utwórz obraz z tymczasowego canvasu
const maskImage = new Image();
maskImage.src = tempCanvas.toDataURL();
return maskImage;
}
resize(width, height) {
const oldMask = this.maskCanvas;
this.maskCanvas = document.createElement('canvas');
this.maskCanvas.width = width;
this.maskCanvas.height = height;
this.maskCtx = this.maskCanvas.getContext('2d');
// Zachowaj zawartość starej maski
if (oldMask.width > 0 && oldMask.height > 0) {
this.maskCtx.drawImage(oldMask, 0, 0);
}
log.info(`Mask canvas resized to ${width}x${height}`);
}
}