From dbf9a59addce2d388b5138f4e877282d2dc5d736 Mon Sep 17 00:00:00 2001 From: CMonk Date: Tue, 7 May 2024 19:08:00 +0800 Subject: [PATCH] Convert http to socketio, simplify by removing push from PS. --- comfy/apis.py | 23 +---- comfy/nodes.py | 35 ++----- comfy/photoshop_instance.py | 96 +++++++++++-------- comfy/sdppp.py | 58 +++++++++--- comfy/static/js/sd-ppp.js | 31 +++++-- photoshop/src/panels/Main.jsx | 9 -- photoshop/src/system/ComfyConnection.js | 25 ++--- photoshop/src/system/HistoryChecker.js | 43 --------- photoshop/src/system/events/send_images.js | 102 +++++++++++++-------- photoshop/src/system/util.js | 2 +- 10 files changed, 213 insertions(+), 211 deletions(-) delete mode 100644 photoshop/src/system/HistoryChecker.js diff --git a/comfy/apis.py b/comfy/apis.py index 18d36f8..0c66cce 100644 --- a/comfy/apis.py +++ b/comfy/apis.py @@ -46,25 +46,4 @@ def define_http_endpoints(PromptServer, sdppp): print('=============error============', e) return web.json_response({ 'error': str(e) - }) - - @PromptServer.instance.routes.get("/sd-ppp/checkchanges") - async def check_changes(request): - is_changed = False - if sdppp.has_ps_instance(): - is_changed = await sdppp.get_ps_instance().is_ps_history_changed() - return web.json_response({'is_changed': is_changed}, content_type='application/json') - - @PromptServer.instance.routes.get("/sd-ppp/resetchanges") - async def reset_changes(request): - if sdppp.has_ps_instance(): - sdppp.get_ps_instance().reset_change_tracker() - return web.json_response({}, content_type='application/json') - - @PromptServer.instance.routes.get("/sd-ppp/getlayers") - async def get_layers(request): - layer_strs = [] - bounds_strs = [] - if sdppp.has_ps_instance(): - layer_strs, bounds_strs = sdppp.get_ps_instance().get_layers() - return web.json_response({'layer_strs': layer_strs, 'bounds_strs': bounds_strs}, content_type='application/json') + }) \ No newline at end of file diff --git a/comfy/nodes.py b/comfy/nodes.py index c398ba1..7d50c14 100644 --- a/comfy/nodes.py +++ b/comfy/nodes.py @@ -20,7 +20,8 @@ def define_comfyui_nodes(sdppp): return np.random.rand() else: photoshopInstance = sdppp.get_ps_instance() - id, bounds_id = self.LAYER_BOUNDS_NAME_TO_ID(layer, use_layer_bounds) + id = photoshopInstance.layer_name_to_id(layer) + bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id) is_changed, history_state_id = photoshopInstance.check_layer_bounds_combo_changed(id, bounds_id) if is_changed and history_state_id is None: return np.random.rand() @@ -33,7 +34,8 @@ def define_comfyui_nodes(sdppp): layer_strs = [] bounds_strs = [] else: - layer_strs, bounds_strs = sdppp.get_ps_instance().get_layers() + layer_strs = sdppp.get_ps_instance().get_base_layers() + bounds_strs = sdppp.get_ps_instance().get_bounds_layers() return { "required": { @@ -41,26 +43,6 @@ def define_comfyui_nodes(sdppp): "use_layer_bounds": (bounds_strs, {"default": bounds_strs[0] if len(bounds_strs) > 0 else None}), } } - - @classmethod - def LAYER_BOUNDS_NAME_TO_ID(self, layer, use_layer_bounds): - id = 0 - if layer == '### Use canvas ###': - id = 0 - else: - layer_name_and_id_split = layer.split('(id:') - id = int(layer_name_and_id_split.pop().strip()[:-1]) - bounds_id = 0 - if use_layer_bounds == '### Use canvas ###': - bounds_id = 0 - elif use_layer_bounds == '### Use selection ###': - bounds_id = -1 - elif use_layer_bounds == '### Same as layer ###': - bounds_id = id - else: - bounds_layer_name_and_id_split = use_layer_bounds.split('(id:') - bounds_id = int(bounds_layer_name_and_id_split.pop().strip()[:-1]) - return id, bounds_id RETURN_TYPES = ("IMAGE", "MASK", "FLOAT") RETURN_NAMES = ("image_out", "mask_out", "layer_opacity") @@ -72,7 +54,8 @@ def define_comfyui_nodes(sdppp): raise ValueError('Photoshop is not connected') photoshopInstance = sdppp.get_ps_instance() - id, bounds_id = self.LAYER_BOUNDS_NAME_TO_ID(layer, use_layer_bounds) + id = photoshopInstance.layer_name_to_id(layer) + bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id) image_id, layer_opacity = photoshopInstance.get_image_from_remote(layer_id=id, bounds_id=bounds_id) loadImage = LoadImage() (output_image, output_mask) = loadImage.load_image(image_id) @@ -89,8 +72,7 @@ def define_comfyui_nodes(sdppp): if validate_sdppp() is not True: layer_strs = [] else: - layer_strs, b = sdppp.get_ps_instance().get_layers() - layer_strs.insert(0, '### New Layer ###') + layer_strs = sdppp.get_ps_instance().get_set_layers() return { "required": { @@ -110,7 +92,8 @@ def define_comfyui_nodes(sdppp): photoshopInstance = sdppp.get_ps_instance() ret = cache_images(images) - photoshopInstance.send_images_to_remote(image_ids=ret, layer_name=layer) + layer_id = photoshopInstance.layer_name_to_id(layer) + photoshopInstance.send_images_to_remote(image_ids=ret, layer_id=layer_id) return (None,) diff --git a/comfy/photoshop_instance.py b/comfy/photoshop_instance.py index b130e7b..3c3b23f 100644 --- a/comfy/photoshop_instance.py +++ b/comfy/photoshop_instance.py @@ -1,4 +1,18 @@ +import time + + class PhotoshopInstance: + SPECIAL_LAYER_NEW_LAYER = '### New Layer ###' + SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###' + SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###' + SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###' + SPECIAL_LAYER_NAME_TO_ID = { + SPECIAL_LAYER_USE_CANVAS: 0, + SPECIAL_LAYER_USE_SELECTION: -1, + SPECIAL_LAYER_NEW_LAYER: -2, + SPECIAL_LAYER_SAME_AS_LAYER: -3 + } + def __init__(self, sdppp, sid): self.sdppp = sdppp self.sid = sid @@ -10,39 +24,61 @@ class PhotoshopInstance: 'done': False, 'result': None } - self.sdppp.onNextTick(fn, handle) - while not handle['done']: + self.sdppp.onNextTick(fn, handle, self.sid) + start_time = time.time() + while not handle['done'] and self.sdppp.check_state_true(self.sid) and time.time() - start_time < 15: pass return handle['result'] def get_layers(self): - layer_strs = [] - bounds_strs = [] - - layer_strs = list(map(lambda layer: f"{layer['name']} (id:{layer['id']})", self.layers)) - layer_strs.insert(0, '### Use canvas ###') + return list(map(lambda layer: f"{layer['name']} (id:{layer['id']})", self.layers)) + + def get_base_layers(self): + raw_layer_strs = self.get_layers() + layer_strs = list(raw_layer_strs) + layer_strs.insert(0, self.SPECIAL_LAYER_USE_CANVAS) + return layer_strs + + def get_bounds_layers(self): + bounds_strs = list(self.get_layers()) + bounds_strs.insert(0, self.SPECIAL_LAYER_USE_CANVAS) + bounds_strs.insert(1, self.SPECIAL_LAYER_USE_SELECTION) + bounds_strs.insert(1, self.SPECIAL_LAYER_SAME_AS_LAYER) + return bounds_strs - bounds_strs = list(layer_strs) - bounds_strs.insert(1, '### Use selection ###') - bounds_strs.insert(1, '### Same as layer ###') - - return layer_strs, bounds_strs + def get_set_layers(self): + raw_layer_strs = self.get_layers() + set_layer_strs = list(raw_layer_strs) + set_layer_strs.insert(0, self.SPECIAL_LAYER_NEW_LAYER) + return set_layer_strs + + def layer_name_to_id(self, layer_name, refrence_id=None): + id = 0 + if layer_name == self.SPECIAL_LAYER_SAME_AS_LAYER: + id = refrence_id + elif self.SPECIAL_LAYER_NAME_TO_ID.get(layer_name, None) is not None: + id = self.SPECIAL_LAYER_NAME_TO_ID[layer_name] + else: + layer_name_and_id_split = layer_name.split('(id:') + id = int(layer_name_and_id_split.pop().strip()[:-1]) + return id # for nodes call def get_image_from_remote(self, layer_id, bounds_id=False): async def _get_image(sio): return await sio.call('get_image', data={'layer_id': layer_id, 'use_layer_bounds': bounds_id}, to=self.sid) result = self._run_in_next_server_event(_get_image) - + if not result: + return None, None history_state_id = self._update_layer_bounds_history_state_id(layer_id, bounds_id) self._update_history_state_id_after_internal_change(history_state_id) return result['upload_name'], result['layer_opacity'] # for nodes call - def send_images_to_remote(self, image_ids, layer_name=""): + def send_images_to_remote(self, image_ids, layer_id=""): async def _send_images(sio): - return await sio.call('send_images', data={'image_ids': image_ids, 'layer_name': layer_name}, to=self.sid) + return await sio.call('send_images', data={'image_ids': image_ids, 'layer_id': layer_id}, to=self.sid) result = self._run_in_next_server_event(_send_images) self._update_history_state_id_after_internal_change() return result @@ -50,14 +86,11 @@ class PhotoshopInstance: # for nodes call def get_active_history_state_id_from_remote(self): async def get_active_history_state_id_from_remote(sio): - return await sio.call('get_active_history_state_id', data={}, to=self.sid) + res = await sio.call('get_active_history_state_id', data={}, to=self.sid) + return res result = self._run_in_next_server_event(get_active_history_state_id_from_remote) - id = result.get('history_state_id', None) - return id - - # for apis call - async def async_get_active_history_state_id_from_remote(self): - result = await self.sdppp.sio.call('get_active_history_state_id', data={}, to=self.sid) + if result is None: + return 0 id = result.get('history_state_id', None) return id @@ -65,19 +98,14 @@ class PhotoshopInstance: # === # for api calls and initialize def reset_change_tracker(self): - self.push_data = {} self.get_img_state_id = 0 - self.last_get_img_id = None self.change_tracker = {} self.comfyui_last_value_tracker = {} # for apis calls - async def is_ps_history_changed(self): - push_state_id = await self.async_get_active_history_state_id_from_remote() - if push_state_id is not None: - return self.get_img_state_id < push_state_id - current_id = await self.get_active_history_state_id_from_remote() - return self.get_img_state_id != current_id + def is_ps_history_changed(self): + current_id = self.get_active_history_state_id_from_remote() + return self.get_img_state_id != current_id and self.get_img_state_id < current_id # for nodes calls def check_layer_bounds_combo_changed(self, layer, use_layer_bounds): @@ -85,7 +113,7 @@ class PhotoshopInstance: layer_bounds_history_state_id = self.change_tracker.get(layer_bounds_combo, None) if layer_bounds_history_state_id is None: return True - latest_state_id = self._get_push_history_state_id() or self.get_active_history_state_id_from_remote() + latest_state_id = self.get_active_history_state_id_from_remote() if latest_state_id > layer_bounds_history_state_id: return True, latest_state_id #didn't change, use last value @@ -113,8 +141,4 @@ class PhotoshopInstance: layer_bounds_combo = f"{layer}{use_layer_bounds}" latest_state_id = self.get_active_history_state_id_from_remote() self.change_tracker[layer_bounds_combo] = latest_state_id - return latest_state_id - - # for nodes call - def _get_push_history_state_id(self): - return self.push_data.get('history_state_id', None) \ No newline at end of file + return latest_state_id \ No newline at end of file diff --git a/comfy/sdppp.py b/comfy/sdppp.py index 996a321..a45f55b 100644 --- a/comfy/sdppp.py +++ b/comfy/sdppp.py @@ -3,6 +3,7 @@ import json import asyncio from socketio import exceptions from .photoshop_instance import PhotoshopInstance +empty_queue = [] class SDPPP: def __init__(self, PromptServer): @@ -16,18 +17,25 @@ class SDPPP: self.loop = PromptServer.instance.loop - self.onNextTickQueue = [] + self.onNextTickQueue = {} def has_ps_instance(self): return len(self.photoshop_instances) > 0 - def get_ps_instance(self, sid = None): + def get_ps_instance(self, sid = None) -> PhotoshopInstance: + if len(self.photoshop_instances) == 0: + return None if sid is None: sid = list(self.photoshop_instances.keys())[0] return self.photoshop_instances[sid] - def onNextTick(self, fn, handle): - self.onNextTickQueue.append((fn, handle)) + def onNextTick(self, fn, handle, sid): + if sid not in self.onNextTickQueue: + self.onNextTickQueue[sid] = [] + self.onNextTickQueue[sid].append((fn, handle)) + + def check_state_true(self, sid): + return self.state.get(sid, False) def registerSocketListeners(self): sio = self.sio @@ -56,10 +64,15 @@ class SDPPP: while True: if (self.state[sid] is False): break - while len(self.onNextTickQueue) > 0: - item = self.onNextTickQueue.pop(0) - item[1]['result'] = await item[0](self.sio) - item[1]['done'] = True + sid_queue = self.onNextTickQueue.get(sid, empty_queue) + while len(sid_queue) > 0: + try: + item = sid_queue.pop(0) + item[1]['result'] = await item[0](self.sio) + except Exception as e: + pass + finally: + item[1]['done'] = True await asyncio.sleep(0.5) self.loop.create_task(selfEventLoop()) @@ -67,25 +80,44 @@ class SDPPP: @sio.event def disconnect(sid): self.state[sid] = False + self.onNextTickQueue.pop(sid, None) if sid in self.photoshop_instances: self.photoshop_instances.pop(sid, None) elif sid in self.comfyui_instances: self.comfyui_instances.pop(sid, None) + sio.disconnect(sid) # only emit by photoshop instance @sio.event async def sync_layers(sid, data): instance = self.get_ps_instance(sid) + if instance is None: + return instance.layers = data['layers'] - layer_strs, bounds_strs = instance.get_layers() + layer_strs = instance.get_base_layers() + bounds_strs = instance.get_bounds_layers() + set_layer_strs = instance.get_set_layers() for sid, instance in self.comfyui_instances.items(): await sio.emit('sync_layers', { 'layer_strs': layer_strs, - 'bound_strs': bounds_strs + 'bound_strs': bounds_strs, + 'set_layer_strs': set_layer_strs, }, to=sid) @sio.event - def push_data(sid, data): - instance = self.get_ps_instance(sid) - instance.push_data.update(push_data) \ No newline at end of file + def check_changes(sid): + instance = self.get_ps_instance() + if instance is None: + return + if not instance.is_ps_history_changed(): + return + sio.emit('trigger_graph_change', to=sid) + + @sio.event + def reset_changes(sid): + instance = self.get_ps_instance() + if instance is None: + return + instance.reset_change_tracker() + diff --git a/comfy/static/js/sd-ppp.js b/comfy/static/js/sd-ppp.js index 90df319..a1e6eb9 100644 --- a/comfy/static/js/sd-ppp.js +++ b/comfy/static/js/sd-ppp.js @@ -4,6 +4,8 @@ import socketio from './socket.io.js' let layerStrs = []; let boundsStrs = []; +let setLayerStrs = []; +let socket = null; console.log("[sd-ppp]", "Loading js extension"); app.registerExtension({ @@ -11,10 +13,9 @@ app.registerExtension({ init() { }, async setup() { - await api.fetchApi(`/sd-ppp/resetchanges`); setInterval(checkChanges, 1000); - const socket = socketio(location.origin, { + socket = socketio(location.origin, { transports: ["websocket"], path: '/sd-ppp/', query: { @@ -24,6 +25,7 @@ app.registerExtension({ }); socket.on('connect', () => { + socket.emit('reset_changes'); }); socket.on('disconnect', () => { }); @@ -33,6 +35,10 @@ app.registerExtension({ socket.on('sync_layers', (data) => { layerStrs = data.layer_strs; boundsStrs = data.bound_strs; + setLayerStrs = data.set_layer_strs; + }); + socket.on('trigger_graph_change', () => { + api.dispatchEvent(new CustomEvent("graphChanged")); }); }, async beforeRegisterNodeDef(nodeType, nodeData, app) { @@ -51,6 +57,21 @@ app.registerExtension({ if(onMouseEnter) await onMouseEnter.call(this, ...args); this_handler.call(this); } + } else if (nodeType.comfyClass === 'Send Images To Photoshop') { + const onSelected = nodeType.prototype.onSelected; + const onMouseEnter = nodeType.prototype.onMouseEnter; + let this_handler = function() { + this.widgets[0].options.values = setLayerStrs; + } + nodeType.prototype.onSelected = async function(...args) { + if(onSelected) await onSelected.call(this, ...args); + this_handler.call(this); + } + nodeType.prototype.onMouseEnter = async function(...args) { + if(onMouseEnter) await onMouseEnter.call(this, ...args); + this_handler.call(this); + } + } } }); @@ -58,7 +79,6 @@ app.registerExtension({ const SDPPPNodes = [ 'Get Image From Photoshop Layer', 'Send Images To Photoshop', - 'Send Images To Photoshop Set Layer', ] async function checkChanges() { await checkHistoryChanges(); @@ -70,10 +90,7 @@ async function checkHistoryChanges() { const mode0NodeTypes = currentState.nodes.filter(node => node.mode == 0).map(node => node.type); const containsSDPPPNodes = mode0NodeTypes.some(nodeType => SDPPPNodes.includes(nodeType)); if (!containsSDPPPNodes) return; - const res = await api.fetchApi(`/sd-ppp/checkchanges`); - const json = await res.json() - if (!json.is_changed) return; - api.dispatchEvent(new CustomEvent("graphChanged")); + socket.emit('check_changes') } catch (e) { console.error("[sd-ppp]", "Failed to check changes", e); } diff --git a/photoshop/src/panels/Main.jsx b/photoshop/src/panels/Main.jsx index d4c5ed7..c521bcb 100644 --- a/photoshop/src/panels/Main.jsx +++ b/photoshop/src/panels/Main.jsx @@ -1,6 +1,5 @@ import React from "react"; import ComfyConnection from "../system/ComfyConnection"; -import HistoryChecker from "../system/HistoryChecker"; import { storage } from "uxp"; export default class Main extends React.Component { @@ -17,14 +16,6 @@ export default class Main extends React.Component { isConnected: instance?.isConnected, comfyURL: instance ? instance.comfyURL : '' }) - if (instance?.isConnected) { - const hc = HistoryChecker.createInstance(); - hc.setChangeCallback((historyId) => { - instance.pushData({history_state_id: historyId}) - }); - } else { - HistoryChecker.instance?.destroy(); - } }); storage.secureStorage.getItem('comfyURL').then((value) => { if (!value) return diff --git a/photoshop/src/system/ComfyConnection.js b/photoshop/src/system/ComfyConnection.js index ee7bda8..81152d8 100644 --- a/photoshop/src/system/ComfyConnection.js +++ b/photoshop/src/system/ComfyConnection.js @@ -40,6 +40,7 @@ class ComfyConnection { this.connect(); } connect() { + console.log('connect') if (!this.socket) { this._createSocket(); } @@ -52,21 +53,10 @@ class ComfyConnection { } } - pushData(data) { - if (!this.isConnected) { - console.error('Connection not open'); - return; - } - - try { - this.socket.emit('push_data', { - push_data: data, - }); - } catch (e) { console.error(e) } - } - _createSocket() { + console.log('create socket') const socket = this.socket = socketio(this.comfyURL, { + autoConnect: false, transports: ["websocket"], path: '/sd-ppp/', query: { @@ -76,17 +66,22 @@ class ComfyConnection { }); this.interval = setInterval(() => { if (!this.isConnected) return; - const allLayers = getAllSubLayer(app.activeDocument); + const allLayers = getAllSubLayer(app.activeDocument); this.socket.emit('sync_layers', { layers: allLayers } ) }, 3000) socket.on('connect_error', (error) => { - console.error('connect_error', error) + if (socket.active) { + console.error('connect_error reconnecting...') + } else { + console.error('connect_error disconnected') + } ComfyConnection._callConnectStateChange(); }); socket.on('connect', () => { + console.log('connect') storage.secureStorage.setItem('comfyURL', this.comfyURL); ComfyConnection._callConnectStateChange(); }); diff --git a/photoshop/src/system/HistoryChecker.js b/photoshop/src/system/HistoryChecker.js deleted file mode 100644 index 6d53744..0000000 --- a/photoshop/src/system/HistoryChecker.js +++ /dev/null @@ -1,43 +0,0 @@ -import {app, action} from "photoshop"; - -class HistoryChecker { - static instance = null; - static createInstance() { - if (HistoryChecker.instance) { - return HistoryChecker.instance; - } - return new HistoryChecker(); - } - constructor() { - HistoryChecker.instance = this; - this.lastCheckId = -1; - this.changeCallback = null; - action.addNotificationListener(["historyStateChanged"], () => { - this.checkHistoryState(); - }); - } - - destroy() { - clearInterval(this.timer); - this.timer = null; - this.changeCallback = null; - HistoryChecker.instance = null; - } - - setChangeCallback(callback) { - this.changeCallback = callback; - } - - checkHistoryState() { - const historyStates = app.activeDocument?.historyStates; - if (!historyStates || historyStates.length == 0) return; - const historyState = historyStates[historyStates.length - 1]; - const historyId = historyState.id; - if (this.lastCheckId == historyId) return; - this.lastCheckId = historyId; - if (this.changeCallback) - this.changeCallback(historyId); - } -} - -export default HistoryChecker; \ No newline at end of file diff --git a/photoshop/src/system/events/send_images.js b/photoshop/src/system/events/send_images.js index c3bd99c..ad865bb 100644 --- a/photoshop/src/system/events/send_images.js +++ b/photoshop/src/system/events/send_images.js @@ -2,6 +2,17 @@ import { app, imaging } from "photoshop"; import { executeAsModalUntilSuccess} from '../util.js'; import Jimp from "../library/jimp.min"; +const SPECIAL_LAYER_USE_CANVAS = '### Use Canvas ###' +const SPECIAL_LAYER_USE_SELECTION = '### Use Selection ###' +const SPECIAL_LAYER_NEW_LAYER = '### New Layer ###' +const SPECIAL_LAYER_SAME_AS_LAYER = '### Same as Layer ###' +const SPECIAL_LAYER_NAME_TO_ID = { + SPECIAL_LAYER_USE_CANVAS: 0, + SPECIAL_LAYER_USE_SELECTION: -1, + SPECIAL_LAYER_NEW_LAYER: -2, + SPECIAL_LAYER_SAME_AS_LAYER: -3 +} + function autocrop(jimp) { let minX = jimp.bitmap.width - 1; let minY = jimp.bitmap.height - 1; @@ -25,9 +36,8 @@ function autocrop(jimp) { } export default async function sendImages(comfyURL, params) { - const imageIds = params.image_ids - const layerName = params.layer_name + const layerId = params.layer_id await Promise.all( imageIds.map(async imageId => { let layer; @@ -35,58 +45,72 @@ export default async function sendImages(comfyURL, params) { let newLayerName; await executeAsModalUntilSuccess(async () => { try { - if (layerName && layerName != "### New Layer ###") { + if (layerId && layerId != SPECIAL_LAYER_NAME_TO_ID[SPECIAL_LAYER_NEW_LAYER]) { + layer = await app.activeDocument.layers.find(l => l.id == layerId) + // deal with multiple images let imageIndexSuffix = "" + console.log("imageIds.length: ", imageIds.length) if (imageIds.length > 1){ - imageIndexSuffix = ` ${imageIds.indexOf(imageId)}` + index = imageIds.indexOf(imageId) + console.log("imageIds.index: ", index) + if (index > 0) + imageIndexSuffix = ` ${index}` + } + if (imageIndexSuffix != "" && layer != null){ + const layerName = layer?.name; + existingLayerName = layerName + imageIndexSuffix + console.log("existingLayerName: ", existingLayerName) + layer = await app.activeDocument.layers.find(l => l.name == existingLayerName) } - existingLayerName = layerName + imageIndexSuffix - layer = await app.activeDocument.layers.find(l => l.name == existingLayerName) } + // deal with new layer or id/name not found layer if (!layer) { newLayerName = existingLayerName ?? 'Comfy Images ' + imageId + console.log("newLayerName: ", newLayerName) layer = await app.activeDocument.createLayer("pixel", { name: newLayerName }) } + const jimp = (await Jimp.read(comfyURL + '/finished_images?id=' + imageId)) + autocrop(jimp) + console.log("layer name ", layer.name) + let putPixelsOptions = { + layerID: layer.id, + imageData: await imaging.createImageDataFromBuffer( + jimp.bitmap.data, + { + width: jimp.bitmap.width, + height: jimp.bitmap.height, + components: 4, + colorSpace: "RGB" + } + ), + replace: true, + } + if (!newLayerName) { + let bounds = layer.bounds + if (bounds.width != jimp.bitmap.width || bounds.height != jimp.bitmap.height) { + if (bounds.width <= 1 && bounds.height <= 1) { + bounds.left = jimp.bitmap.width / 2 + bounds.top = jimp.bitmap.height / 2 + } + let centerBounds = {} + centerBounds.left = bounds.left + (bounds.width - jimp.bitmap.width) / 2 + centerBounds.top = bounds.top + (bounds.height - jimp.bitmap.height) / 2 + centerBounds.right = bounds.left + jimp.bitmap.width + centerBounds.bottom = bounds.top + jimp.bitmap.height + centerBounds.width = jimp.bitmap.width + centerBounds.height = jimp.bitmap.height + bounds = centerBounds + } + putPixelsOptions.targetBounds = bounds + } + await imaging.putPixels(putPixelsOptions) } catch(e) { console.error(e) throw e } }) - - const jimp = (await Jimp.read(comfyURL + '/finished_images?id=' + imageId)) - autocrop(jimp) - let putPixelsOptions = { - layerID: layer.id, - imageData: await imaging.createImageDataFromBuffer( - jimp.bitmap.data, - { - width: jimp.bitmap.width, - height: jimp.bitmap.height, - components: 4, - colorSpace: "RGB" - } - ), - replace: true, - } - if (!newLayerName) { - let bounds = layer.bounds - if (bounds.width != jimp.bitmap.width || bounds.height != jimp.bitmap.height) { - let centerBounds = {} - centerBounds.left = bounds.left + (bounds.width - jimp.bitmap.width) / 2 - centerBounds.top = bounds.top + (bounds.height - jimp.bitmap.height) / 2 - centerBounds.right = bounds.left + jimp.bitmap.width - centerBounds.bottom = bounds.top + jimp.bitmap.height - centerBounds.width = jimp.bitmap.width - centerBounds.height = jimp.bitmap.height - bounds = centerBounds - } - putPixelsOptions.targetBounds = bounds - } - await executeAsModalUntilSuccess(async () => { - await imaging.putPixels(putPixelsOptions) - }) }) ) return {} diff --git a/photoshop/src/system/util.js b/photoshop/src/system/util.js index 4f1775d..7851850 100644 --- a/photoshop/src/system/util.js +++ b/photoshop/src/system/util.js @@ -57,7 +57,7 @@ export function unTrimImageData( } export function getAllSubLayer(layer, level = 0) { - if (!layer.layers) return []; + if (!layer?.layers) return []; return layer.layers.reduce((ret, layer) => { ret.push({ name: '-'.repeat(level) + layer.name,