crlf to lf
This commit is contained in:
+176
-176
@@ -1,177 +1,177 @@
|
||||
import numpy as np
|
||||
import time
|
||||
from nodes import LoadImage
|
||||
from PIL import Image
|
||||
from .apis import addImageCache
|
||||
|
||||
def define_comfyui_nodes(sdppp):
|
||||
def validate_sdppp():
|
||||
if not sdppp.has_ps_instance():
|
||||
return 'Photoshop is not connected'
|
||||
return True
|
||||
|
||||
def call_async_func_in_server_thread(coro, dontwait = False):
|
||||
handle = {
|
||||
'done': False,
|
||||
'result': None,
|
||||
'error': None
|
||||
}
|
||||
loop = sdppp.loop
|
||||
async def do_call():
|
||||
try:
|
||||
handle['result'] = await coro
|
||||
except Exception as e:
|
||||
handle['error'] = e
|
||||
finally:
|
||||
handle['done'] = True
|
||||
loop.create_task(do_call())
|
||||
|
||||
if not dontwait:
|
||||
while not handle['done']:
|
||||
pass
|
||||
if handle['error'] is not None:
|
||||
raise handle['error']
|
||||
else:
|
||||
return handle['result']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class GetImageFromPhotoshopLayerNode:
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, layer):
|
||||
return validate_sdppp()
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(self, layer, use_layer_bounds):
|
||||
if not sdppp.has_ps_instance():
|
||||
return np.random.rand()
|
||||
else:
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
id = photoshopInstance.layer_name_to_id(layer)
|
||||
bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id)
|
||||
start = time.time()
|
||||
is_changed, history_state_id = call_async_func_in_server_thread(photoshopInstance.check_layer_bounds_combo_changed(id, bounds_id))
|
||||
if is_changed and history_state_id is None:
|
||||
return np.random.rand()
|
||||
photoshopInstance.update_comfyui_last_value(id, bounds_id, history_state_id)
|
||||
return history_state_id
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
if validate_sdppp() is not True:
|
||||
layer_strs = []
|
||||
bounds_strs = []
|
||||
else:
|
||||
layer_strs = sdppp.get_ps_instance().get_base_layers()
|
||||
bounds_strs = sdppp.get_ps_instance().get_bounds_layers()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}),
|
||||
"use_layer_bounds": (bounds_strs, {"default": bounds_strs[0] if len(bounds_strs) > 0 else None}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "MASK", "FLOAT")
|
||||
RETURN_NAMES = ("image_out", "mask_out", "layer_opacity")
|
||||
FUNCTION = "get_image"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def get_image(self, layer, use_layer_bounds):
|
||||
if validate_sdppp() is not True:
|
||||
raise ValueError('Photoshop is not connected')
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
|
||||
id = photoshopInstance.layer_name_to_id(layer)
|
||||
bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id)
|
||||
|
||||
start = time.time()
|
||||
image_id, layer_opacity = call_async_func_in_server_thread(photoshopInstance.get_image(layer_id=id, bounds_id=bounds_id))
|
||||
|
||||
loadImage = LoadImage()
|
||||
(output_image, output_mask) = loadImage.load_image(image_id)
|
||||
return (output_image, output_mask, layer_opacity / 100)
|
||||
|
||||
|
||||
class SendImageToPhotoshopLayerNode:
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, images):
|
||||
return validate_sdppp()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
if validate_sdppp() is not True:
|
||||
layer_strs = []
|
||||
else:
|
||||
layer_strs = sdppp.get_ps_instance().get_set_layers()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE", ),
|
||||
"layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "send_image"
|
||||
CATEGORY = "Photoshop"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def send_image(self, images, layer):
|
||||
if validate_sdppp() is not True:
|
||||
raise ValueError('Photoshop is not connected')
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
|
||||
image_ids = []
|
||||
for (batch_number, image) in enumerate(images):
|
||||
i = 255. * image.cpu().numpy()
|
||||
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
||||
image_ids.append(addImageCache(img))
|
||||
layer_id = photoshopInstance.layer_name_to_id(layer)
|
||||
call_async_func_in_server_thread(photoshopInstance.send_images(image_ids=image_ids, layer_id=layer_id), True)
|
||||
|
||||
return (None,)
|
||||
|
||||
class ImageTimesOpacity:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE", ),
|
||||
"opacity": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 1.0, "step": 0.01}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_times_opacity"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def image_times_opacity(self, images, opacity):
|
||||
image_out = images * opacity
|
||||
return (image_out,)
|
||||
|
||||
class MaskTimesOpacity:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"masks": ("MASK", ),
|
||||
"opacity": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 1.0, "step": 0.01}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "mask_times_opacity"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def mask_times_opacity(self, masks, opacity):
|
||||
mask_out = masks * opacity
|
||||
return (mask_out,)
|
||||
|
||||
return {
|
||||
'GetImageFromPhotoshopLayerNode': GetImageFromPhotoshopLayerNode,
|
||||
'SendImageToPhotoshopLayerNode': SendImageToPhotoshopLayerNode,
|
||||
'ImageTimesOpacity': ImageTimesOpacity,
|
||||
'MaskTimesOpacity': MaskTimesOpacity,
|
||||
import numpy as np
|
||||
import time
|
||||
from nodes import LoadImage
|
||||
from PIL import Image
|
||||
from .apis import addImageCache
|
||||
|
||||
def define_comfyui_nodes(sdppp):
|
||||
def validate_sdppp():
|
||||
if not sdppp.has_ps_instance():
|
||||
return 'Photoshop is not connected'
|
||||
return True
|
||||
|
||||
def call_async_func_in_server_thread(coro, dontwait = False):
|
||||
handle = {
|
||||
'done': False,
|
||||
'result': None,
|
||||
'error': None
|
||||
}
|
||||
loop = sdppp.loop
|
||||
async def do_call():
|
||||
try:
|
||||
handle['result'] = await coro
|
||||
except Exception as e:
|
||||
handle['error'] = e
|
||||
finally:
|
||||
handle['done'] = True
|
||||
loop.create_task(do_call())
|
||||
|
||||
if not dontwait:
|
||||
while not handle['done']:
|
||||
pass
|
||||
if handle['error'] is not None:
|
||||
raise handle['error']
|
||||
else:
|
||||
return handle['result']
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class GetImageFromPhotoshopLayerNode:
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, layer):
|
||||
return validate_sdppp()
|
||||
|
||||
@classmethod
|
||||
def IS_CHANGED(self, layer, use_layer_bounds):
|
||||
if not sdppp.has_ps_instance():
|
||||
return np.random.rand()
|
||||
else:
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
id = photoshopInstance.layer_name_to_id(layer)
|
||||
bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id)
|
||||
start = time.time()
|
||||
is_changed, history_state_id = call_async_func_in_server_thread(photoshopInstance.check_layer_bounds_combo_changed(id, bounds_id))
|
||||
if is_changed and history_state_id is None:
|
||||
return np.random.rand()
|
||||
photoshopInstance.update_comfyui_last_value(id, bounds_id, history_state_id)
|
||||
return history_state_id
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
if validate_sdppp() is not True:
|
||||
layer_strs = []
|
||||
bounds_strs = []
|
||||
else:
|
||||
layer_strs = sdppp.get_ps_instance().get_base_layers()
|
||||
bounds_strs = sdppp.get_ps_instance().get_bounds_layers()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}),
|
||||
"use_layer_bounds": (bounds_strs, {"default": bounds_strs[0] if len(bounds_strs) > 0 else None}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE", "MASK", "FLOAT")
|
||||
RETURN_NAMES = ("image_out", "mask_out", "layer_opacity")
|
||||
FUNCTION = "get_image"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def get_image(self, layer, use_layer_bounds):
|
||||
if validate_sdppp() is not True:
|
||||
raise ValueError('Photoshop is not connected')
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
|
||||
id = photoshopInstance.layer_name_to_id(layer)
|
||||
bounds_id = photoshopInstance.layer_name_to_id(use_layer_bounds, id)
|
||||
|
||||
start = time.time()
|
||||
image_id, layer_opacity = call_async_func_in_server_thread(photoshopInstance.get_image(layer_id=id, bounds_id=bounds_id))
|
||||
|
||||
loadImage = LoadImage()
|
||||
(output_image, output_mask) = loadImage.load_image(image_id)
|
||||
return (output_image, output_mask, layer_opacity / 100)
|
||||
|
||||
|
||||
class SendImageToPhotoshopLayerNode:
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(s, images):
|
||||
return validate_sdppp()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
if validate_sdppp() is not True:
|
||||
layer_strs = []
|
||||
else:
|
||||
layer_strs = sdppp.get_ps_instance().get_set_layers()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE", ),
|
||||
"layer": (layer_strs, {"default": layer_strs[0] if len(layer_strs) > 0 else None}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ()
|
||||
FUNCTION = "send_image"
|
||||
CATEGORY = "Photoshop"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def send_image(self, images, layer):
|
||||
if validate_sdppp() is not True:
|
||||
raise ValueError('Photoshop is not connected')
|
||||
photoshopInstance = sdppp.get_ps_instance()
|
||||
|
||||
image_ids = []
|
||||
for (batch_number, image) in enumerate(images):
|
||||
i = 255. * image.cpu().numpy()
|
||||
img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
|
||||
image_ids.append(addImageCache(img))
|
||||
layer_id = photoshopInstance.layer_name_to_id(layer)
|
||||
call_async_func_in_server_thread(photoshopInstance.send_images(image_ids=image_ids, layer_id=layer_id), True)
|
||||
|
||||
return (None,)
|
||||
|
||||
class ImageTimesOpacity:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"images": ("IMAGE", ),
|
||||
"opacity": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 1.0, "step": 0.01}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("IMAGE",)
|
||||
FUNCTION = "image_times_opacity"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def image_times_opacity(self, images, opacity):
|
||||
image_out = images * opacity
|
||||
return (image_out,)
|
||||
|
||||
class MaskTimesOpacity:
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"masks": ("MASK", ),
|
||||
"opacity": ("FLOAT", {"default": 1.0, "min": 0.01, "max": 1.0, "step": 0.01}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("MASK",)
|
||||
FUNCTION = "mask_times_opacity"
|
||||
CATEGORY = "Photoshop"
|
||||
|
||||
def mask_times_opacity(self, masks, opacity):
|
||||
mask_out = masks * opacity
|
||||
return (mask_out,)
|
||||
|
||||
return {
|
||||
'GetImageFromPhotoshopLayerNode': GetImageFromPhotoshopLayerNode,
|
||||
'SendImageToPhotoshopLayerNode': SendImageToPhotoshopLayerNode,
|
||||
'ImageTimesOpacity': ImageTimesOpacity,
|
||||
'MaskTimesOpacity': MaskTimesOpacity,
|
||||
}
|
||||
+120
-120
@@ -1,121 +1,121 @@
|
||||
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
|
||||
self.layers = []
|
||||
self.reset_change_tracker()
|
||||
|
||||
def get_layers(self):
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
async def get_image(self, layer_id, bounds_id=False):
|
||||
result = await self.sdppp.sio.call('get_image', data={'layer_id': layer_id, 'use_layer_bounds': bounds_id}, to=self.sid)
|
||||
if not result:
|
||||
return None, None
|
||||
if 'error' in result:
|
||||
raise Exception('sdppp PS side error:' + result['error'])
|
||||
history_state_id = await self._update_layer_bounds_history_state_id(layer_id, bounds_id)
|
||||
await self._update_history_state_id_after_internal_change(history_state_id)
|
||||
|
||||
return result['upload_name'], result['layer_opacity']
|
||||
|
||||
async def send_images(self, image_ids, layer_id=""):
|
||||
result = await self.sdppp.sio.call('send_images', data={'image_ids': image_ids, 'layer_id': layer_id}, to=self.sid)
|
||||
await self._update_history_state_id_after_internal_change()
|
||||
return result
|
||||
|
||||
async def get_active_history_state_id(self):
|
||||
result = await self.sdppp.sio.call('get_active_history_state_id', data={}, to=self.sid)
|
||||
if result is None:
|
||||
return 0
|
||||
if 'error' in result:
|
||||
raise Exception('sdppp get_active_history_state_id PS side error:' + result['error'])
|
||||
id = result.get('history_state_id', 0)
|
||||
return id
|
||||
|
||||
|
||||
# ===
|
||||
def reset_change_tracker(self):
|
||||
self.get_img_state_id = 0
|
||||
self.change_tracker = {}
|
||||
self.comfyui_last_value_tracker = {}
|
||||
|
||||
# for apis calls
|
||||
async def is_ps_history_changed(self):
|
||||
current_id = await self.get_active_history_state_id()
|
||||
return self.get_img_state_id != current_id and self.get_img_state_id < current_id
|
||||
|
||||
async def check_layer_bounds_combo_changed(self, layer, use_layer_bounds):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
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 = await self.get_active_history_state_id()
|
||||
if latest_state_id > layer_bounds_history_state_id:
|
||||
return True, latest_state_id
|
||||
#didn't change, use last value
|
||||
comfyui_last_value = self.comfyui_last_value_tracker.get(layer_bounds_combo, None) or layer_bounds_history_state_id
|
||||
return False, comfyui_last_value
|
||||
|
||||
# have to track this value because comfyui determines if the value is changed by comparing it with the last value.
|
||||
# can't use the real history id because sending images changes the history id, and comfyui will think the value is changed when it's not
|
||||
def update_comfyui_last_value(self, layer, use_layer_bounds, value):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
self.comfyui_last_value_tracker[layer_bounds_combo] = value
|
||||
|
||||
# need to update history id after internal operation otherwise it might cause infinite change loop
|
||||
async def _update_history_state_id_after_internal_change(self, history_state_id=None):
|
||||
if history_state_id is None: # need to get new id after operation, it causes history change
|
||||
history_state_id = await self.get_active_history_state_id()
|
||||
if self.get_img_state_id is not None: # udpate all the change trackers with the new history state id
|
||||
self.change_tracker = {k: history_state_id for k, v in self.change_tracker.items() if v == self.get_img_state_id}
|
||||
self.get_img_state_id = history_state_id # it gets into a loop if get img state is not updated
|
||||
|
||||
async def _update_layer_bounds_history_state_id(self, layer, use_layer_bounds):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
latest_state_id = await self.get_active_history_state_id()
|
||||
self.change_tracker[layer_bounds_combo] = latest_state_id
|
||||
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
|
||||
self.layers = []
|
||||
self.reset_change_tracker()
|
||||
|
||||
def get_layers(self):
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
async def get_image(self, layer_id, bounds_id=False):
|
||||
result = await self.sdppp.sio.call('get_image', data={'layer_id': layer_id, 'use_layer_bounds': bounds_id}, to=self.sid)
|
||||
if not result:
|
||||
return None, None
|
||||
if 'error' in result:
|
||||
raise Exception('sdppp PS side error:' + result['error'])
|
||||
history_state_id = await self._update_layer_bounds_history_state_id(layer_id, bounds_id)
|
||||
await self._update_history_state_id_after_internal_change(history_state_id)
|
||||
|
||||
return result['upload_name'], result['layer_opacity']
|
||||
|
||||
async def send_images(self, image_ids, layer_id=""):
|
||||
result = await self.sdppp.sio.call('send_images', data={'image_ids': image_ids, 'layer_id': layer_id}, to=self.sid)
|
||||
await self._update_history_state_id_after_internal_change()
|
||||
return result
|
||||
|
||||
async def get_active_history_state_id(self):
|
||||
result = await self.sdppp.sio.call('get_active_history_state_id', data={}, to=self.sid)
|
||||
if result is None:
|
||||
return 0
|
||||
if 'error' in result:
|
||||
raise Exception('sdppp get_active_history_state_id PS side error:' + result['error'])
|
||||
id = result.get('history_state_id', 0)
|
||||
return id
|
||||
|
||||
|
||||
# ===
|
||||
def reset_change_tracker(self):
|
||||
self.get_img_state_id = 0
|
||||
self.change_tracker = {}
|
||||
self.comfyui_last_value_tracker = {}
|
||||
|
||||
# for apis calls
|
||||
async def is_ps_history_changed(self):
|
||||
current_id = await self.get_active_history_state_id()
|
||||
return self.get_img_state_id != current_id and self.get_img_state_id < current_id
|
||||
|
||||
async def check_layer_bounds_combo_changed(self, layer, use_layer_bounds):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
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 = await self.get_active_history_state_id()
|
||||
if latest_state_id > layer_bounds_history_state_id:
|
||||
return True, latest_state_id
|
||||
#didn't change, use last value
|
||||
comfyui_last_value = self.comfyui_last_value_tracker.get(layer_bounds_combo, None) or layer_bounds_history_state_id
|
||||
return False, comfyui_last_value
|
||||
|
||||
# have to track this value because comfyui determines if the value is changed by comparing it with the last value.
|
||||
# can't use the real history id because sending images changes the history id, and comfyui will think the value is changed when it's not
|
||||
def update_comfyui_last_value(self, layer, use_layer_bounds, value):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
self.comfyui_last_value_tracker[layer_bounds_combo] = value
|
||||
|
||||
# need to update history id after internal operation otherwise it might cause infinite change loop
|
||||
async def _update_history_state_id_after_internal_change(self, history_state_id=None):
|
||||
if history_state_id is None: # need to get new id after operation, it causes history change
|
||||
history_state_id = await self.get_active_history_state_id()
|
||||
if self.get_img_state_id is not None: # udpate all the change trackers with the new history state id
|
||||
self.change_tracker = {k: history_state_id for k, v in self.change_tracker.items() if v == self.get_img_state_id}
|
||||
self.get_img_state_id = history_state_id # it gets into a loop if get img state is not updated
|
||||
|
||||
async def _update_layer_bounds_history_state_id(self, layer, use_layer_bounds):
|
||||
layer_bounds_combo = f"{layer}{use_layer_bounds}"
|
||||
latest_state_id = await self.get_active_history_state_id()
|
||||
self.change_tracker[layer_bounds_combo] = latest_state_id
|
||||
return latest_state_id
|
||||
Reference in New Issue
Block a user