diff --git a/canvas_node.py b/canvas_node.py index c7bab11..06f2926 100644 --- a/canvas_node.py +++ b/canvas_node.py @@ -167,6 +167,7 @@ class CanvasNode: def INPUT_TYPES(cls): return { "required": { + "fit_on_add": ("BOOLEAN", {"default": False, "label_on": "Fit on Add/Paste", "label_off": "Default Behavior"}), "trigger": ("INT", {"default": 0, "min": 0, "max": 99999999, "step": 1, "hidden": True}), "node_id": ("STRING", {"default": "0", "hidden": True}), }, @@ -230,7 +231,7 @@ class CanvasNode: _processing_lock = threading.Lock() - def process_canvas_image(self, trigger, node_id, prompt=None, unique_id=None): + def process_canvas_image(self, fit_on_add, trigger, node_id, prompt=None, unique_id=None): try: diff --git a/js/Canvas.js b/js/Canvas.js index fdcafa8..ac66003 100644 --- a/js/Canvas.js +++ b/js/Canvas.js @@ -157,8 +157,8 @@ export class Canvas { return this.canvasLayers.pasteLayers(); } - async handlePaste(pasteMode) { - return this.canvasLayers.handlePaste(pasteMode); + async handlePaste(addMode) { + return this.canvasLayers.handlePaste(addMode); } @@ -194,13 +194,13 @@ export class Canvas { return this.canvasLayers.isRotationHandle(x, y); } - async addLayerWithImage(image, layerProps = {}) { - return this.canvasLayers.addLayerWithImage(image, layerProps); + async addLayerWithImage(image, layerProps = {}, addMode = 'default') { + return this.canvasLayers.addLayerWithImage(image, layerProps, addMode); } - async addLayer(image) { - return this.addLayerWithImage(image); + async addLayer(image, addMode = 'default') { + return this.addLayerWithImage(image, {}, addMode); } async removeLayer(index) { diff --git a/js/CanvasLayers.js b/js/CanvasLayers.js index 05238e1..109dbca 100644 --- a/js/CanvasLayers.js +++ b/js/CanvasLayers.js @@ -66,7 +66,7 @@ export class CanvasLayers { log.info(`Pasted ${newLayers.length} layer(s).`); } - async handlePaste(pasteMode = 'mouse') { + async handlePaste(addMode = 'mouse') { try { if (!navigator.clipboard?.read) { log.info("Browser does not support clipboard read API. Falling back to internal paste."); @@ -86,15 +86,7 @@ export class CanvasLayers { reader.onload = (event) => { const img = new Image(); img.onload = async () => { - let layerProps = {}; - if (pasteMode === 'center') { - layerProps.x = (this.canvasLayers.width - img.width) / 2; - layerProps.y = (this.canvasLayers.height - img.height) / 2; - } else { // 'mouse' or default - layerProps.x = this.canvasLayers.lastMousePosition.x - img.width / 2; - layerProps.y = this.canvasLayers.lastMousePosition.y - img.height / 2; - } - await this.addLayerWithImage(img, layerProps); + await this.addLayerWithImage(img, {}, addMode); }; img.src = event.target.result; }; @@ -113,23 +105,41 @@ export class CanvasLayers { } } - addLayerWithImage = withErrorHandling(async (image, layerProps = {}) => { + addLayerWithImage = withErrorHandling(async (image, layerProps = {}, addMode = 'default') => { if (!image) { throw createValidationError("Image is required for layer creation"); } - log.debug("Adding layer with image:", image); + log.debug("Adding layer with image:", image, "with mode:", addMode); const imageId = generateUUID(); await saveImage(imageId, image.src); this.canvasLayers.imageCache.set(imageId, image.src); + + let finalWidth = image.width; + let finalHeight = image.height; + let finalX, finalY; + + if (addMode === 'fit') { + const scale = Math.min(this.canvasLayers.width / image.width, this.canvasLayers.height / image.height); + finalWidth = image.width * scale; + finalHeight = image.height * scale; + finalX = (this.canvasLayers.width - finalWidth) / 2; + finalY = (this.canvasLayers.height - finalHeight) / 2; + } else if (addMode === 'mouse') { + finalX = this.canvasLayers.lastMousePosition.x - finalWidth / 2; + finalY = this.canvasLayers.lastMousePosition.y - finalHeight / 2; + } else { // 'center' or 'default' + finalX = (this.canvasLayers.width - finalWidth) / 2; + finalY = (this.canvasLayers.height - finalHeight) / 2; + } const layer = { image: image, imageId: imageId, - x: (this.canvasLayers.width - image.width) / 2, - y: (this.canvasLayers.height - image.height) / 2, - width: image.width, - height: image.height, + x: finalX, + y: finalY, + width: finalWidth, + height: finalHeight, rotation: 0, zIndex: this.canvasLayers.layers.length, blendMode: 'normal', diff --git a/js/CanvasView.js b/js/CanvasView.js index a4a377b..47063f8 100644 --- a/js/CanvasView.js +++ b/js/CanvasView.js @@ -527,6 +527,8 @@ async function createCanvasWidget(node, widget, app) { textContent: "Add Image", title: "Add image from file", onclick: () => { + const fitOnAddWidget = node.widgets.find(w => w.name === "fit_on_add"); + const addMode = fitOnAddWidget && fitOnAddWidget.value ? 'fit' : 'center'; const input = document.createElement('input'); input.type = 'file'; input.accept = 'image/*'; @@ -537,7 +539,7 @@ async function createCanvasWidget(node, widget, app) { reader.onload = (event) => { const img = new Image(); img.onload = () => { - canvas.addLayer(img); + canvas.addLayer(img, addMode); }; img.src = event.target.result; }; @@ -555,7 +557,11 @@ async function createCanvasWidget(node, widget, app) { $el("button.painter-button.primary", { textContent: "Paste Image", title: "Paste image from clipboard", - onclick: () => canvas.handlePaste('center') + onclick: () => { + const fitOnAddWidget = node.widgets.find(w => w.name === "fit_on_add"); + const addMode = fitOnAddWidget && fitOnAddWidget.value ? 'fit' : 'center'; + canvas.handlePaste(addMode); + } }), ]),