From 64ee2c6abb3c6c7203406ac00adee88ed86024b7 Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Sun, 27 Jul 2025 20:02:45 +0200 Subject: [PATCH] createElement to createCanvas --- js/Canvas.js | 11 ++++++----- js/CanvasIO.js | 25 +++++-------------------- js/CanvasLayers.js | 30 ++++++------------------------ js/CanvasLayersPanel.js | 16 ++++------------ js/CanvasState.js | 12 +++--------- js/CanvasView.js | 6 ++---- js/MaskEditorIntegration.js | 6 ++---- js/MaskTool.js | 20 +++++++++----------- src/Canvas.ts | 11 ++++++----- src/CanvasIO.ts | 25 +++++-------------------- src/CanvasLayers.ts | 31 ++++++------------------------- src/CanvasLayersPanel.ts | 16 ++++------------ src/CanvasState.ts | 12 +++--------- src/CanvasView.ts | 7 ++----- src/MaskEditorIntegration.ts | 6 ++---- src/MaskTool.ts | 20 +++++++++----------- 16 files changed, 74 insertions(+), 180 deletions(-) diff --git a/js/Canvas.js b/js/Canvas.js index 56a66eb..f1cbb39 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -12,7 +12,7 @@ import { CanvasIO } from "./CanvasIO.js"; import { ImageReferenceManager } from "./ImageReferenceManager.js"; import { BatchPreviewManager } from "./BatchPreviewManager.js"; import { createModuleLogger } from "./utils/LoggerUtils.js"; -import { debounce } from "./utils/CommonUtils.js"; +import { debounce, createCanvas } from "./utils/CommonUtils.js"; import { MaskEditorIntegration } from "./MaskEditorIntegration.js"; import { CanvasSelection } from "./CanvasSelection.js"; const useChainCallback = (original, next) => { @@ -38,10 +38,10 @@ export class Canvas { constructor(node, widget, callbacks = {}) { this.node = node; this.widget = widget; - this.canvas = document.createElement('canvas'); - const ctx = this.canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(0, 0, '2d', { willReadFrequently: true }); if (!ctx) throw new Error("Could not create canvas context"); + this.canvas = canvas; this.ctx = ctx; this.width = 512; this.height = 512; @@ -54,11 +54,12 @@ export class Canvas { y: -(this.height / 4), zoom: 0.8, }; - this.offscreenCanvas = document.createElement('canvas'); - this.offscreenCtx = this.offscreenCanvas.getContext('2d', { + const { canvas: offscreenCanvas, ctx: offscreenCtx } = createCanvas(0, 0, '2d', { alpha: false, willReadFrequently: true }); + this.offscreenCanvas = offscreenCanvas; + this.offscreenCtx = offscreenCtx; this.dataInitialized = false; this.pendingDataCheck = null; this.imageCache = new Map(); diff --git a/js/CanvasIO.js b/js/CanvasIO.js index 5cb776b..303666a 100644 --- a/js/CanvasIO.js +++ b/js/CanvasIO.js @@ -52,10 +52,7 @@ export class CanvasIO { const { canvas: maskCanvas, ctx: maskCtx } = createCanvas(this.canvas.width, this.canvas.height); const originalShape = this.canvas.outputAreaShape; this.canvas.outputAreaShape = null; - const visibilityCanvas = document.createElement('canvas'); - visibilityCanvas.width = this.canvas.width; - visibilityCanvas.height = this.canvas.height; - const visibilityCtx = visibilityCanvas.getContext('2d', { alpha: true }); + const { canvas: visibilityCanvas, ctx: visibilityCtx } = createCanvas(this.canvas.width, this.canvas.height, '2d', { alpha: true }); if (!visibilityCtx) throw new Error("Could not create visibility context"); if (!maskCtx) @@ -94,17 +91,11 @@ export class CanvasIO { tempMaskData.data[i + 3] = alpha; } // Create a temporary canvas to hold the processed mask - const tempMaskCanvas = document.createElement('canvas'); - tempMaskCanvas.width = this.canvas.width; - tempMaskCanvas.height = this.canvas.height; - const tempMaskCtx = tempMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempMaskCanvas, ctx: tempMaskCtx } = createCanvas(this.canvas.width, this.canvas.height, '2d', { willReadFrequently: true }); if (!tempMaskCtx) throw new Error("Could not create temp mask context"); // Put the processed mask data into a canvas that matches the output area size - const outputMaskCanvas = document.createElement('canvas'); - outputMaskCanvas.width = toolMaskCanvas.width; - outputMaskCanvas.height = toolMaskCanvas.height; - const outputMaskCtx = outputMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: outputMaskCanvas, ctx: outputMaskCtx } = createCanvas(toolMaskCanvas.width, toolMaskCanvas.height, '2d', { willReadFrequently: true }); if (!outputMaskCtx) throw new Error("Could not create output mask context"); outputMaskCtx.putImageData(tempMaskData, 0, 0); @@ -289,12 +280,9 @@ export class CanvasIO { if (!tensor || !tensor.data || !tensor.width || !tensor.height) { throw new Error("Invalid tensor data"); } - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(tensor.width, tensor.height, '2d', { willReadFrequently: true }); if (!ctx) throw new Error("Could not create canvas context"); - canvas.width = tensor.width; - canvas.height = tensor.height; const imageData = new ImageData(new Uint8ClampedArray(tensor.data), tensor.width, tensor.height); ctx.putImageData(imageData, 0, 0); return new Promise((resolve, reject) => { @@ -468,10 +456,7 @@ export class CanvasIO { } async createImageFromData(imageData) { return new Promise((resolve, reject) => { - const canvas = document.createElement('canvas'); - canvas.width = imageData.width; - canvas.height = imageData.height; - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(imageData.width, imageData.height, '2d', { willReadFrequently: true }); if (!ctx) throw new Error("Could not create canvas context"); ctx.putImageData(imageData, 0, 0); diff --git a/js/CanvasLayers.js b/js/CanvasLayers.js index d61c8ee..e755197 100644 --- a/js/CanvasLayers.js +++ b/js/CanvasLayers.js @@ -456,12 +456,9 @@ export class CanvasLayers { } async getLayerImageData(layer) { try { - const tempCanvas = document.createElement('canvas'); - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(layer.width, layer.height, '2d', { willReadFrequently: true }); if (!tempCtx) throw new Error("Could not create canvas context"); - tempCanvas.width = layer.width; - tempCanvas.height = layer.height; // We need to draw the layer relative to the new canvas, so we "move" it to 0,0 // by creating a temporary layer object for drawing. const layerToDraw = { @@ -803,10 +800,7 @@ export class CanvasLayers { } bounds = { x: minX, y: minY, width: newWidth, height: newHeight }; } - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = bounds.width; - tempCanvas.height = bounds.height; - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!tempCtx) { reject(new Error("Could not create canvas context")); return; @@ -896,10 +890,7 @@ export class CanvasLayers { async getFlattenedMaskAsBlob() { return new Promise((resolve, reject) => { const bounds = this.canvas.outputAreaBounds; - const maskCanvas = document.createElement('canvas'); - maskCanvas.width = bounds.width; - maskCanvas.height = bounds.height; - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: maskCanvas, ctx: maskCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!maskCtx) { reject(new Error("Could not create mask context")); return; @@ -910,10 +901,7 @@ export class CanvasLayers { maskCtx.fillStyle = '#ffffff'; maskCtx.fillRect(0, 0, bounds.width, bounds.height); // Stwórz canvas do sprawdzenia przezroczystości warstw - const visibilityCanvas = document.createElement('canvas'); - visibilityCanvas.width = bounds.width; - visibilityCanvas.height = bounds.height; - const visibilityCtx = visibilityCanvas.getContext('2d', { alpha: true }); + const { canvas: visibilityCanvas, ctx: visibilityCtx } = createCanvas(bounds.width, bounds.height, '2d', { alpha: true }); if (!visibilityCtx) { reject(new Error("Could not create visibility context")); return; @@ -946,10 +934,7 @@ export class CanvasLayers { tempMaskData.data[i + 3] = 255; // Solidna alpha } // Stwórz tymczasowy canvas dla przetworzonej maski - const tempMaskCanvas = document.createElement('canvas'); - tempMaskCanvas.width = toolMaskCanvas.width; - tempMaskCanvas.height = toolMaskCanvas.height; - const tempMaskCtx = tempMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempMaskCanvas, ctx: tempMaskCtx } = createCanvas(toolMaskCanvas.width, toolMaskCanvas.height, '2d', { willReadFrequently: true }); if (tempMaskCtx) { tempMaskCtx.putImageData(tempMaskData, 0, 0); maskCtx.globalCompositeOperation = 'screen'; @@ -1007,10 +992,7 @@ export class CanvasLayers { showErrorNotification("Cannot fuse layers: invalid dimensions calculated."); return; } - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = fusedWidth; - tempCanvas.height = fusedHeight; - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(fusedWidth, fusedHeight, '2d', { willReadFrequently: true }); if (!tempCtx) throw new Error("Could not create canvas context"); tempCtx.translate(-minX, -minY); diff --git a/js/CanvasLayersPanel.js b/js/CanvasLayersPanel.js index c8128e3..d5afa15 100644 --- a/js/CanvasLayersPanel.js +++ b/js/CanvasLayersPanel.js @@ -1,5 +1,6 @@ import { createModuleLogger } from "./utils/LoggerUtils.js"; import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js"; +import { createCanvas } from "./utils/CommonUtils.js"; const log = createModuleLogger('CanvasLayersPanel'); export class CanvasLayersPanel { constructor(canvas) { @@ -49,10 +50,7 @@ export class CanvasLayersPanel { iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = size; - canvas.height = size; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(size, size); if (ctx) { ctx.drawImage(icon, 0, 0, size, size); } @@ -95,10 +93,7 @@ export class CanvasLayersPanel { iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = 16; - canvas.height = 16; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(16, 16); if (ctx) { ctx.globalAlpha = 0.3; ctx.drawImage(icon, 0, 0, 16, 16); @@ -423,12 +418,9 @@ export class CanvasLayersPanel { thumbnailContainer.style.background = '#4a4a4a'; return; } - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(48, 48, '2d', { willReadFrequently: true }); if (!ctx) return; - canvas.width = 48; - canvas.height = 48; const scale = Math.min(48 / layer.image.width, 48 / layer.image.height); const scaledWidth = layer.image.width * scale; const scaledHeight = layer.image.height * scale; diff --git a/js/CanvasState.js b/js/CanvasState.js index cbc62e0..93530a0 100644 --- a/js/CanvasState.js +++ b/js/CanvasState.js @@ -1,6 +1,6 @@ import { getCanvasState, setCanvasState, saveImage, getImage } from "./db.js"; import { createModuleLogger } from "./utils/LoggerUtils.js"; -import { generateUUID, cloneLayers, getStateSignature, debounce } from "./utils/CommonUtils.js"; +import { generateUUID, cloneLayers, getStateSignature, debounce, createCanvas } from "./utils/CommonUtils.js"; const log = createModuleLogger('CanvasState'); export class CanvasState { constructor(canvas) { @@ -196,10 +196,7 @@ export class CanvasState { img.src = imageSrc; } else { - const canvas = document.createElement('canvas'); - canvas.width = imageSrc.width; - canvas.height = imageSrc.height; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(imageSrc.width, imageSrc.height); if (ctx) { ctx.drawImage(imageSrc, 0, 0); const img = new Image(); @@ -315,10 +312,7 @@ export class CanvasState { this.maskUndoStack.pop(); } const maskCanvas = this.canvas.maskTool.getMask(); - const clonedCanvas = document.createElement('canvas'); - clonedCanvas.width = maskCanvas.width; - clonedCanvas.height = maskCanvas.height; - const clonedCtx = clonedCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: clonedCanvas, ctx: clonedCtx } = createCanvas(maskCanvas.width, maskCanvas.height, '2d', { willReadFrequently: true }); if (clonedCtx) { clonedCtx.drawImage(maskCanvas, 0, 0); } diff --git a/js/CanvasView.js b/js/CanvasView.js index 5c2ef8b..9e4aaba 100644 --- a/js/CanvasView.js +++ b/js/CanvasView.js @@ -6,6 +6,7 @@ import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js" import { Canvas } from "./Canvas.js"; import { clearAllCanvasStates } from "./db.js"; import { ImageCache } from "./ImageCache.js"; +import { createCanvas } from "./utils/CommonUtils.js"; import { createModuleLogger } from "./utils/LoggerUtils.js"; import { showErrorNotification, showSuccessNotification } from "./utils/NotificationUtils.js"; import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js"; @@ -541,10 +542,7 @@ async function createCanvasWidget(node, widget, app) { iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = 16; - canvas.height = 16; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(16, 16); if (ctx) { ctx.drawImage(icon, 0, 0, 16, 16); } diff --git a/js/MaskEditorIntegration.js b/js/MaskEditorIntegration.js index 63e4eb6..0aab9f5 100644 --- a/js/MaskEditorIntegration.js +++ b/js/MaskEditorIntegration.js @@ -9,6 +9,7 @@ import { processImageToMask, processMaskForViewport } from "./utils/MaskProcessi import { convertToImage } from "./utils/ImageUtils.js"; import { updateNodePreview } from "./utils/PreviewUtils.js"; import { mask_editor_showing, mask_editor_listen_for_cancel } from "./utils/mask_utils.js"; +import { createCanvas } from "./utils/CommonUtils.js"; const log = createModuleLogger('MaskEditorIntegration'); export class MaskEditorIntegration { constructor(canvas) { @@ -283,10 +284,7 @@ export class MaskEditorIntegration { return null; } const maskCanvas = this.maskTool.maskCanvas; - const savedCanvas = document.createElement('canvas'); - savedCanvas.width = maskCanvas.width; - savedCanvas.height = maskCanvas.height; - const savedCtx = savedCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: savedCanvas, ctx: savedCtx } = createCanvas(maskCanvas.width, maskCanvas.height, '2d', { willReadFrequently: true }); if (savedCtx) { savedCtx.drawImage(maskCanvas, 0, 0); } diff --git a/js/MaskTool.js b/js/MaskTool.js index e91c8e4..ca53eee 100644 --- a/js/MaskTool.js +++ b/js/MaskTool.js @@ -17,11 +17,11 @@ export class MaskTool { this.currentDrawingChunk = null; this.maxActiveChunks = 25; // Safety limit to prevent memory issues (5x5 grid max) // Create active mask canvas (composite of chunks) - this.activeMaskCanvas = document.createElement('canvas'); - const activeMaskCtx = this.activeMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: activeMaskCanvas, ctx: activeMaskCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!activeMaskCtx) { throw new Error("Failed to get 2D context for active mask canvas"); } + this.activeMaskCanvas = activeMaskCanvas; this.activeMaskCtx = activeMaskCtx; this.x = 0; this.y = 0; @@ -32,20 +32,20 @@ export class MaskTool { this.brushHardness = 0.5; this.isDrawing = false; this.lastPosition = null; - this.previewCanvas = document.createElement('canvas'); - const previewCtx = this.previewCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: previewCanvas, ctx: previewCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!previewCtx) { throw new Error("Failed to get 2D context for preview canvas"); } + this.previewCanvas = previewCanvas; this.previewCtx = previewCtx; this.previewVisible = false; this.previewCanvasInitialized = false; // Initialize shape preview system - this.shapePreviewCanvas = document.createElement('canvas'); - const shapePreviewCtx = this.shapePreviewCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: shapePreviewCanvas, ctx: shapePreviewCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!shapePreviewCtx) { throw new Error("Failed to get 2D context for shape preview canvas"); } + this.shapePreviewCanvas = shapePreviewCanvas; this.shapePreviewCtx = shapePreviewCtx; this.shapePreviewVisible = false; this.isPreviewMode = false; @@ -1262,10 +1262,7 @@ export class MaskTool { getMaskForOutputArea() { const bounds = this.canvasInstance.outputAreaBounds; // Create canvas sized to output area - const outputMaskCanvas = document.createElement('canvas'); - outputMaskCanvas.width = bounds.width; - outputMaskCanvas.height = bounds.height; - const outputMaskCtx = outputMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: outputMaskCanvas, ctx: outputMaskCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!outputMaskCtx) { throw new Error("Failed to get 2D context for output area mask canvas"); } @@ -1304,7 +1301,8 @@ export class MaskTool { const oldHeight = oldMask.height; const isIncreasingWidth = width > this.canvasInstance.width; const isIncreasingHeight = height > this.canvasInstance.height; - this.activeMaskCanvas = document.createElement('canvas'); + const { canvas: activeMaskCanvas } = createCanvas(1, 1, '2d', { willReadFrequently: true }); + this.activeMaskCanvas = activeMaskCanvas; const extraSpace = 2000; const newWidth = isIncreasingWidth ? width + extraSpace : Math.max(oldWidth, width + extraSpace); const newHeight = isIncreasingHeight ? height + extraSpace : Math.max(oldHeight, height + extraSpace); diff --git a/src/Canvas.ts b/src/Canvas.ts index 577811d..707a415 100644 --- a/src/Canvas.ts +++ b/src/Canvas.ts @@ -18,7 +18,7 @@ import {CanvasIO} from "./CanvasIO.js"; import {ImageReferenceManager} from "./ImageReferenceManager.js"; import {BatchPreviewManager} from "./BatchPreviewManager.js"; import {createModuleLogger} from "./utils/LoggerUtils.js"; -import { debounce } from "./utils/CommonUtils.js"; +import { debounce, createCanvas } from "./utils/CommonUtils.js"; import {MaskEditorIntegration} from "./MaskEditorIntegration.js"; import {CanvasSelection} from "./CanvasSelection.js"; import type { ComfyNode, Layer, Viewport, Point, AddMode, Shape, OutputAreaBounds } from './types'; @@ -96,9 +96,9 @@ export class Canvas { constructor(node: ComfyNode, widget: any, callbacks: { onStateChange?: () => void, onHistoryChange?: (historyInfo: { canUndo: boolean; canRedo: boolean; }) => void } = {}) { this.node = node; this.widget = widget; - this.canvas = document.createElement('canvas'); - const ctx = this.canvas.getContext('2d', {willReadFrequently: true}); + const { canvas, ctx } = createCanvas(0, 0, '2d', {willReadFrequently: true}); if (!ctx) throw new Error("Could not create canvas context"); + this.canvas = canvas; this.ctx = ctx; this.width = 512; this.height = 512; @@ -113,11 +113,12 @@ export class Canvas { zoom: 0.8, }; - this.offscreenCanvas = document.createElement('canvas'); - this.offscreenCtx = this.offscreenCanvas.getContext('2d', { + const { canvas: offscreenCanvas, ctx: offscreenCtx } = createCanvas(0, 0, '2d', { alpha: false, willReadFrequently: true }); + this.offscreenCanvas = offscreenCanvas; + this.offscreenCtx = offscreenCtx; this.dataInitialized = false; this.pendingDataCheck = null; diff --git a/src/CanvasIO.ts b/src/CanvasIO.ts index 13199e1..00fe5d4 100644 --- a/src/CanvasIO.ts +++ b/src/CanvasIO.ts @@ -65,10 +65,7 @@ export class CanvasIO { const originalShape = this.canvas.outputAreaShape; this.canvas.outputAreaShape = null; - const visibilityCanvas = document.createElement('canvas'); - visibilityCanvas.width = this.canvas.width; - visibilityCanvas.height = this.canvas.height; - const visibilityCtx = visibilityCanvas.getContext('2d', { alpha: true }); + const { canvas: visibilityCanvas, ctx: visibilityCtx } = createCanvas(this.canvas.width, this.canvas.height, '2d', { alpha: true }); if (!visibilityCtx) throw new Error("Could not create visibility context"); if (!maskCtx) throw new Error("Could not create mask context"); if (!tempCtx) throw new Error("Could not create temp context"); @@ -111,17 +108,11 @@ export class CanvasIO { } // Create a temporary canvas to hold the processed mask - const tempMaskCanvas = document.createElement('canvas'); - tempMaskCanvas.width = this.canvas.width; - tempMaskCanvas.height = this.canvas.height; - const tempMaskCtx = tempMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempMaskCanvas, ctx: tempMaskCtx } = createCanvas(this.canvas.width, this.canvas.height, '2d', { willReadFrequently: true }); if (!tempMaskCtx) throw new Error("Could not create temp mask context"); // Put the processed mask data into a canvas that matches the output area size - const outputMaskCanvas = document.createElement('canvas'); - outputMaskCanvas.width = toolMaskCanvas.width; - outputMaskCanvas.height = toolMaskCanvas.height; - const outputMaskCtx = outputMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: outputMaskCanvas, ctx: outputMaskCtx } = createCanvas(toolMaskCanvas.width, toolMaskCanvas.height, '2d', { willReadFrequently: true }); if (!outputMaskCtx) throw new Error("Could not create output mask context"); outputMaskCtx.putImageData(tempMaskData, 0, 0); @@ -337,11 +328,8 @@ export class CanvasIO { throw new Error("Invalid tensor data"); } - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(tensor.width, tensor.height, '2d', { willReadFrequently: true }); if (!ctx) throw new Error("Could not create canvas context"); - canvas.width = tensor.width; - canvas.height = tensor.height; const imageData = new ImageData( new Uint8ClampedArray(tensor.data), @@ -550,10 +538,7 @@ export class CanvasIO { async createImageFromData(imageData: ImageData): Promise { return new Promise((resolve, reject) => { - const canvas = document.createElement('canvas'); - canvas.width = imageData.width; - canvas.height = imageData.height; - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(imageData.width, imageData.height, '2d', { willReadFrequently: true }); if (!ctx) throw new Error("Could not create canvas context"); ctx.putImageData(imageData, 0, 0); diff --git a/src/CanvasLayers.ts b/src/CanvasLayers.ts index 7508299..0baad27 100644 --- a/src/CanvasLayers.ts +++ b/src/CanvasLayers.ts @@ -522,13 +522,9 @@ export class CanvasLayers { async getLayerImageData(layer: Layer): Promise { try { - const tempCanvas = document.createElement('canvas'); - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(layer.width, layer.height, '2d', { willReadFrequently: true }); if (!tempCtx) throw new Error("Could not create canvas context"); - tempCanvas.width = layer.width; - tempCanvas.height = layer.height; - // We need to draw the layer relative to the new canvas, so we "move" it to 0,0 // by creating a temporary layer object for drawing. const layerToDraw = { @@ -937,10 +933,7 @@ export class CanvasLayers { bounds = { x: minX, y: minY, width: newWidth, height: newHeight }; } - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = bounds.width; - tempCanvas.height = bounds.height; - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!tempCtx) { reject(new Error("Could not create canvas context")); return; @@ -1042,10 +1035,7 @@ export class CanvasLayers { async getFlattenedMaskAsBlob(): Promise { return new Promise((resolve, reject) => { const bounds = this.canvas.outputAreaBounds; - const maskCanvas = document.createElement('canvas'); - maskCanvas.width = bounds.width; - maskCanvas.height = bounds.height; - const maskCtx = maskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: maskCanvas, ctx: maskCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!maskCtx) { reject(new Error("Could not create mask context")); @@ -1060,10 +1050,7 @@ export class CanvasLayers { maskCtx.fillRect(0, 0, bounds.width, bounds.height); // Stwórz canvas do sprawdzenia przezroczystości warstw - const visibilityCanvas = document.createElement('canvas'); - visibilityCanvas.width = bounds.width; - visibilityCanvas.height = bounds.height; - const visibilityCtx = visibilityCanvas.getContext('2d', { alpha: true }); + const { canvas: visibilityCanvas, ctx: visibilityCtx } = createCanvas(bounds.width, bounds.height, '2d', { alpha: true }); if (!visibilityCtx) { reject(new Error("Could not create visibility context")); return; @@ -1101,10 +1088,7 @@ export class CanvasLayers { } // Stwórz tymczasowy canvas dla przetworzonej maski - const tempMaskCanvas = document.createElement('canvas'); - tempMaskCanvas.width = toolMaskCanvas.width; - tempMaskCanvas.height = toolMaskCanvas.height; - const tempMaskCtx = tempMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempMaskCanvas, ctx: tempMaskCtx } = createCanvas(toolMaskCanvas.width, toolMaskCanvas.height, '2d', { willReadFrequently: true }); if (tempMaskCtx) { tempMaskCtx.putImageData(tempMaskData, 0, 0); @@ -1174,10 +1158,7 @@ export class CanvasLayers { return; } - const tempCanvas = document.createElement('canvas'); - tempCanvas.width = fusedWidth; - tempCanvas.height = fusedHeight; - const tempCtx = tempCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: tempCanvas, ctx: tempCtx } = createCanvas(fusedWidth, fusedHeight, '2d', { willReadFrequently: true }); if (!tempCtx) throw new Error("Could not create canvas context"); tempCtx.translate(-minX, -minY); diff --git a/src/CanvasLayersPanel.ts b/src/CanvasLayersPanel.ts index f4f594c..105613a 100644 --- a/src/CanvasLayersPanel.ts +++ b/src/CanvasLayersPanel.ts @@ -1,5 +1,6 @@ import { createModuleLogger } from "./utils/LoggerUtils.js"; import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js"; +import { createCanvas } from "./utils/CommonUtils.js"; import type { Canvas } from './Canvas'; import type { Layer } from './types'; @@ -65,10 +66,7 @@ export class CanvasLayersPanel { `; iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = size; - canvas.height = size; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(size, size); if (ctx) { ctx.drawImage(icon, 0, 0, size, size); } @@ -111,10 +109,7 @@ export class CanvasLayersPanel { `; iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = 16; - canvas.height = 16; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(16, 16); if (ctx) { ctx.globalAlpha = 0.3; ctx.drawImage(icon, 0, 0, 16, 16); @@ -465,11 +460,8 @@ export class CanvasLayersPanel { return; } - const canvas = document.createElement('canvas'); - const ctx = canvas.getContext('2d', { willReadFrequently: true }); + const { canvas, ctx } = createCanvas(48, 48, '2d', { willReadFrequently: true }); if (!ctx) return; - canvas.width = 48; - canvas.height = 48; const scale = Math.min(48 / layer.image.width, 48 / layer.image.height); const scaledWidth = layer.image.width * scale; diff --git a/src/CanvasState.ts b/src/CanvasState.ts index cdbd1ea..c3477e7 100644 --- a/src/CanvasState.ts +++ b/src/CanvasState.ts @@ -1,6 +1,6 @@ import {getCanvasState, setCanvasState, saveImage, getImage} from "./db.js"; import {createModuleLogger} from "./utils/LoggerUtils.js"; -import {generateUUID, cloneLayers, getStateSignature, debounce} from "./utils/CommonUtils.js"; +import {generateUUID, cloneLayers, getStateSignature, debounce, createCanvas} from "./utils/CommonUtils.js"; import {withErrorHandling} from "./ErrorHandler.js"; import type { Canvas } from './Canvas'; import type { Layer, ComfyNode } from './types'; @@ -230,10 +230,7 @@ export class CanvasState { }; img.src = imageSrc; } else { - const canvas = document.createElement('canvas'); - canvas.width = imageSrc.width; - canvas.height = imageSrc.height; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(imageSrc.width, imageSrc.height); if (ctx) { ctx.drawImage(imageSrc, 0, 0); const img = new Image(); @@ -358,10 +355,7 @@ export class CanvasState { this.maskUndoStack.pop(); } const maskCanvas = this.canvas.maskTool.getMask(); - const clonedCanvas = document.createElement('canvas'); - clonedCanvas.width = maskCanvas.width; - clonedCanvas.height = maskCanvas.height; - const clonedCtx = clonedCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: clonedCanvas, ctx: clonedCtx } = createCanvas(maskCanvas.width, maskCanvas.height, '2d', { willReadFrequently: true }); if (clonedCtx) { clonedCtx.drawImage(maskCanvas, 0, 0); } diff --git a/src/CanvasView.ts b/src/CanvasView.ts index dd4af9f..620516c 100644 --- a/src/CanvasView.ts +++ b/src/CanvasView.ts @@ -12,7 +12,7 @@ import { addStylesheet, getUrl, loadTemplate } from "./utils/ResourceManager.js" import {Canvas} from "./Canvas.js"; import {clearAllCanvasStates} from "./db.js"; import {ImageCache} from "./ImageCache.js"; -import {generateUniqueFileName} from "./utils/CommonUtils.js"; +import {generateUniqueFileName, createCanvas} from "./utils/CommonUtils.js"; import {createModuleLogger} from "./utils/LoggerUtils.js"; import {showErrorNotification, showSuccessNotification} from "./utils/NotificationUtils.js"; import { iconLoader, LAYERFORGE_TOOLS } from "./utils/IconLoader.js"; @@ -577,10 +577,7 @@ async function createCanvasWidget(node: ComfyNode, widget: any, app: ComfyApp): `; iconContainer.appendChild(img); } else if (icon instanceof HTMLCanvasElement) { - const canvas = document.createElement('canvas'); - canvas.width = 16; - canvas.height = 16; - const ctx = canvas.getContext('2d'); + const { canvas, ctx } = createCanvas(16, 16); if (ctx) { ctx.drawImage(icon, 0, 0, 16, 16); } diff --git a/src/MaskEditorIntegration.ts b/src/MaskEditorIntegration.ts index ff0dc4f..30852da 100644 --- a/src/MaskEditorIntegration.ts +++ b/src/MaskEditorIntegration.ts @@ -11,6 +11,7 @@ import { processImageToMask, processMaskForViewport } from "./utils/MaskProcessi import { convertToImage } from "./utils/ImageUtils.js"; import { updateNodePreview } from "./utils/PreviewUtils.js"; import { mask_editor_showing, mask_editor_listen_for_cancel } from "./utils/mask_utils.js"; +import { createCanvas } from "./utils/CommonUtils.js"; const log = createModuleLogger('MaskEditorIntegration'); @@ -347,10 +348,7 @@ export class MaskEditorIntegration { } const maskCanvas = this.maskTool.maskCanvas; - const savedCanvas = document.createElement('canvas'); - savedCanvas.width = maskCanvas.width; - savedCanvas.height = maskCanvas.height; - const savedCtx = savedCanvas.getContext('2d', {willReadFrequently: true}); + const { canvas: savedCanvas, ctx: savedCtx } = createCanvas(maskCanvas.width, maskCanvas.height, '2d', {willReadFrequently: true}); if (savedCtx) { savedCtx.drawImage(maskCanvas, 0, 0); } diff --git a/src/MaskTool.ts b/src/MaskTool.ts index e6bfd43..0dd8ac4 100644 --- a/src/MaskTool.ts +++ b/src/MaskTool.ts @@ -83,11 +83,11 @@ export class MaskTool { this.maxActiveChunks = 25; // Safety limit to prevent memory issues (5x5 grid max) // Create active mask canvas (composite of chunks) - this.activeMaskCanvas = document.createElement('canvas'); - const activeMaskCtx = this.activeMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: activeMaskCanvas, ctx: activeMaskCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!activeMaskCtx) { throw new Error("Failed to get 2D context for active mask canvas"); } + this.activeMaskCanvas = activeMaskCanvas; this.activeMaskCtx = activeMaskCtx; this.x = 0; @@ -101,21 +101,21 @@ export class MaskTool { this.isDrawing = false; this.lastPosition = null; - this.previewCanvas = document.createElement('canvas'); - const previewCtx = this.previewCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: previewCanvas, ctx: previewCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!previewCtx) { throw new Error("Failed to get 2D context for preview canvas"); } + this.previewCanvas = previewCanvas; this.previewCtx = previewCtx; this.previewVisible = false; this.previewCanvasInitialized = false; // Initialize shape preview system - this.shapePreviewCanvas = document.createElement('canvas'); - const shapePreviewCtx = this.shapePreviewCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: shapePreviewCanvas, ctx: shapePreviewCtx } = createCanvas(1, 1, '2d', { willReadFrequently: true }); if (!shapePreviewCtx) { throw new Error("Failed to get 2D context for shape preview canvas"); } + this.shapePreviewCanvas = shapePreviewCanvas; this.shapePreviewCtx = shapePreviewCtx; this.shapePreviewVisible = false; this.isPreviewMode = false; @@ -1558,10 +1558,7 @@ export class MaskTool { const bounds = this.canvasInstance.outputAreaBounds; // Create canvas sized to output area - const outputMaskCanvas = document.createElement('canvas'); - outputMaskCanvas.width = bounds.width; - outputMaskCanvas.height = bounds.height; - const outputMaskCtx = outputMaskCanvas.getContext('2d', { willReadFrequently: true }); + const { canvas: outputMaskCanvas, ctx: outputMaskCtx } = createCanvas(bounds.width, bounds.height, '2d', { willReadFrequently: true }); if (!outputMaskCtx) { throw new Error("Failed to get 2D context for output area mask canvas"); @@ -1612,7 +1609,8 @@ export class MaskTool { const isIncreasingWidth = width > this.canvasInstance.width; const isIncreasingHeight = height > this.canvasInstance.height; - this.activeMaskCanvas = document.createElement('canvas'); + const { canvas: activeMaskCanvas } = createCanvas(1, 1, '2d', { willReadFrequently: true }); + this.activeMaskCanvas = activeMaskCanvas; const extraSpace = 2000;