Add support for sending folder layer

Photoshop plugin will first clone and merge the selected folder layer, send, then delete the cloned and merged layer, all in one modal execution.
This commit is contained in:
CMonk
2024-05-13 12:46:19 +08:00
committed by zombieyang
parent 7b65676ab7
commit a402d02b00
3 changed files with 96 additions and 28 deletions
+14 -13
View File
@@ -127,19 +127,20 @@ class PhotoshopInstance:
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 = self.get_push_history_state_id() or await self.get_active_history_state_id()
latest_state_id = await self.get_active_history_state_id()
self.change_tracker[layer_bounds_combo] = latest_state_id
return latest_state_id
async def update_history_state_id_after_send(self):
old_history_state_id = self.get_img_state_id
history_state_id = await self.get_active_history_state_id() # need to get new id after operation, it causes history change
self.get_img_state_id = history_state_id # it gets into a loop if get img state is not updated
if old_history_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 == old_history_state_id}
async def get_layers(self):
result = await self.wsCallsManager.call('get_layers', {})
@@ -151,10 +152,10 @@ class PhotoshopInstance:
if not is_changed and self.last_get_img_id is not None:
return self.last_get_img_id
result = await self.wsCallsManager.call('get_image', {'layer_id': layer_id, 'use_layer_bounds': bounds_id}, timeout=60)
id = result['upload_name']
layer_opacity = result['layer_opacity']
history_state_id = await self.update_layer_bounds_history_state_id(layer_id, bounds_id)
self.get_img_state_id = history_state_id
await self.update_history_state_id_after_internal_change(history_state_id)
layer_opacity = result['layer_opacity']
id = result['upload_name']
self.last_get_img_id = id
return id, layer_opacity
@@ -167,7 +168,7 @@ class PhotoshopInstance:
async def send_images(self, image_ids, layer_name=""):
result = await self.wsCallsManager.call('send_images', {'image_ids': image_ids, 'layer_name': layer_name})
await self.update_history_state_id_after_send()
await self.update_history_state_id_after_internal_change()
return result
def get_push_history_state_id(self):
+41 -8
View File
@@ -267,7 +267,7 @@ async function getPixelsData(layer, desireBounds) {
return await getPixelsDataHelper(null, desireBounds);
}
// normal layer
return getPixelsDataHelper(layer, desireBounds);
return await getPixelsDataHelper(layer, desireBounds);
}
// ps returns trimmed data so need padding
@@ -286,6 +286,22 @@ function padAndTrimLayerDataToDesireBounds(layer, pixelDataFromAPI, desireBounds
(0,_util__WEBPACK_IMPORTED_MODULE_2__.unTrimImageData)(pixelDataFromAPI, pixelDataForReturn, bounds, desireBounds);
return pixelDataForReturn;
}
function isLayerFolder(layer) {
return layer.layers && layer.layers.length > 0;
}
async function findLayer(layerID) {
let layer;
let isFolder = false;
if (layerID <= 0) return [layer, isFolder];
layer = (0,_util__WEBPACK_IMPORTED_MODULE_2__.findInAllSubLayer)(photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument, layerID);
if (!layer) throw new Error(`Layer(id: ${layerID}) not found`);
if (!isLayerFolder(layer)) return [layer, isFolder];
// layer is folder
const dupLayer = await layer.duplicate();
const mergedLayer = await dupLayer.merge();
isFolder = true;
return [mergedLayer, isFolder];
}
class ComfyConnection {
static instance = null;
static _connectStateCallbacks = [];
@@ -423,15 +439,23 @@ class ComfyConnection {
} else if (payload.action == 'get_image') {
const layerID = payload.params.layer_id;
const boundsLayerID = payload.params.use_layer_bounds;
await executeAsModalUntilSuccess(async () => {
await executeAsModalUntilSuccess(async executionContext => {
let hostControl;
let suspensionID;
const startTime = Date.now();
let uploadName = 0;
let layer;
let layerOpacity = 100;
let isFolder = false;
const activeLayers = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.activeLayers;
try {
let layer;
if (layerID > 0) {
layer = (0,_util__WEBPACK_IMPORTED_MODULE_2__.findInAllSubLayer)(photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument, layerID);
if (!layer) throw new Error(`Layer(id: ${layerID}) not found`);
}
hostControl = executionContext.hostControl;
suspensionID = await hostControl.suspendHistory({
"documentID": photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.id,
"name": "Image To ComfyUI"
});
[layer, isFolder] = await findLayer(layerID);
layerOpacity = layer?.opacity ?? 100;
const desireBounds = getDesiredBounds(boundsLayerID);
const pixelDataFromAPI = await getPixelsData(layer, desireBounds);
const pixelDataForReturn = padAndTrimLayerDataToDesireBounds(layer, pixelDataFromAPI, desireBounds);
@@ -476,11 +500,20 @@ class ComfyConnection {
error: e.message
}));
throw e;
} finally {
if (layer && isFolder) layer.delete();
if (activeLayers && activeLayers.length > 0) {
for (let i = 0; i < activeLayers.length; i++) {
activeLayers[i].selected = true;
}
}
if (hostControl && suspensionID) await hostControl.resumeHistory(suspensionID);
}
this.socket.send(JSON.stringify({
call_id: payload.call_id,
result: {
upload_name: uploadName
upload_name: uploadName,
layer_opacity: layerOpacity
}
}));
}, {
+41 -7
View File
@@ -93,7 +93,7 @@ async function getPixelsData(layer, desireBounds) {
return await getPixelsDataHelper(null, desireBounds);
}
// normal layer
return getPixelsDataHelper(layer, desireBounds);
return await getPixelsDataHelper(layer, desireBounds);
}
// ps returns trimmed data so need padding
@@ -118,6 +118,24 @@ function padAndTrimLayerDataToDesireBounds(layer, pixelDataFromAPI, desireBounds
return pixelDataForReturn;
}
function isLayerFolder(layer){
return layer.layers && layer.layers.length > 0;
}
async function findLayer(layerID) {
let layer;
let isFolder = false;
if (layerID <= 0) return [layer, isFolder];
layer = findInAllSubLayer(app.activeDocument, layerID)
if (!layer) throw new Error(`Layer(id: ${layerID}) not found`);
if (!isLayerFolder(layer)) return [layer, isFolder];
// layer is folder
const dupLayer = await layer.duplicate();
const mergedLayer = await dupLayer.merge()
isFolder = true;
return [mergedLayer, isFolder];
}
class ComfyConnection {
static instance = null;
@@ -272,15 +290,23 @@ class ComfyConnection {
const layerID = payload.params.layer_id
const boundsLayerID = payload.params.use_layer_bounds
await executeAsModalUntilSuccess(async () => {
await executeAsModalUntilSuccess(async (executionContext) => {
let hostControl;
let suspensionID;
const startTime = Date.now();
let uploadName = 0;
let layer;
let layerOpacity = 100;
let isFolder = false;
const activeLayers = app.activeDocument.activeLayers;
try {
if (layerID > 0) {
layer = findInAllSubLayer(app.activeDocument, layerID)
if (!layer) throw new Error(`Layer(id: ${layerID}) not found`);
}
hostControl = executionContext.hostControl;
suspensionID = await hostControl.suspendHistory({
"documentID": app.activeDocument.id,
"name": "Image To ComfyUI"
});
[layer, isFolder] = await findLayer(layerID);
layerOpacity = layer?.opacity ?? 100;
const desireBounds = getDesiredBounds(boundsLayerID);
const pixelDataFromAPI = await getPixelsData(layer, desireBounds)
const pixelDataForReturn = padAndTrimLayerDataToDesireBounds(layer, pixelDataFromAPI, desireBounds)
@@ -329,6 +355,14 @@ class ComfyConnection {
})
)
throw e
} finally {
if (layer && isFolder) layer.delete();
if (activeLayers && activeLayers.length > 0) {
for (let i = 0; i < activeLayers.length; i++) {
activeLayers[i].selected = true;
}
}
if (hostControl && suspensionID) await hostControl.resumeHistory(suspensionID);
}
this.socket.send(
@@ -336,7 +370,7 @@ class ComfyConnection {
call_id: payload.call_id,
result: {
upload_name: uploadName,
layer_opacity: layer?.opacity ?? 100
layer_opacity: layerOpacity,
}
})
)