Improve transparency mask handling

- Collapse transparency mask by default
- Add transparency mask: option to add or flatten mask
- Removed Use selection as mask
- Mask adding logic sets top paintlayer as active
- Fixes #91
- FIxes #85
pull/112/head
John-Henry Lim 2023-01-20 15:25:42 +08:00
parent c25c8130a8
commit f35706776a
5 changed files with 60 additions and 17 deletions

View File

@ -1,5 +1,11 @@
# UI Changelog
## 2023-01-20
- Removed "Use selection as mask" option; Using the selection to mask generated images is now default behaviour.
- Added "Add transparency mask" option; Choose to mask generated images by adding transparency mask, or directly flatten/crop image.
- Top paintlayer will now be set as active layer when generation is complete.
## 2022-12-28
- Added "Alt Dock Behaviour" under "SD Plugin Config".

View File

@ -103,6 +103,12 @@ A: Unfortunately no, all plugins so far have different APIs. The official API is
See [CHANGELOG.md](./CHANGELOG.md) for the full changelog.
### 2023-01-20
- Removed "Use selection as mask" option; Using the selection to mask generated images is now default behaviour.
- Added "Add transparency mask" option; Choose to mask generated images by adding transparency mask, or directly flatten/crop image.
- Top paintlayer will now be set as active layer when generation is complete.
### 2022-12-28
- Added "Alt Dock Behaviour" under "SD Plugin Config".

View File

@ -21,8 +21,7 @@ ETA_REFRESH_INTERVAL = 1000 # 1 second between eta refresh
CFG_FOLDER = "krita" # which folder in ~/.config to store config
CFG_NAME = "krita_diff_plugin" # name of config file
EXT_CFG_NAME = "krita_diff_plugin_scripts" # name of config file
# selection mask can only be added after image is added, so timeout is needed
ADD_MASK_TIMEOUT = 200
ADD_MASK_TIMEOUT = 50
THREADED = True
ROUTE_PREFIX = "/sdapi/interpause/"
OFFICIAL_ROUTE_PREFIX = "/sdapi/v1/"

View File

@ -31,7 +31,7 @@ class ConfigPage(QWidget):
script.cfg, "just_use_yaml", "(unrecommended) Ignore settings"
)
self.create_mask_layer = QCheckBox(
script.cfg, "create_mask_layer", "Use selection as mask"
script.cfg, "create_mask_layer", "Add transparency mask"
)
self.save_temp_images = QCheckBox(
script.cfg, "save_temp_images", "Save images for debug"

View File

@ -335,22 +335,54 @@ class Script(QObject):
def transparency_mask_inserter(self):
"""Mask out extra regions due to adjust_selection()."""
orig_selection = self.selection.duplicate() if self.selection else None
create_mask = self.cfg("create_mask_layer", bool)
def add_mask(layers):
self.doc.waitForDone()
cur_selection = self.selection
cur_layer = self.doc.activeNode()
for layer in layers:
self.doc.setActiveNode(layer)
self.doc.setSelection(orig_selection)
self.app.action("add_new_transparency_mask").trigger()
self.doc.setSelection(cur_selection) # reset to current selection
self.doc.setActiveNode(cur_layer) # reset to current layer
add_mask_action = self.app.action("add_new_transparency_mask")
merge_mask_action = self.app.action("flatten_layer")
def trigger_mask_adding(layers):
if self.cfg("create_mask_layer", bool):
# need timeout to ensure layer exists first else crash
QTimer.singleShot(ADD_MASK_TIMEOUT, lambda: add_mask(layers))
# This function is recursive to workaround race conditions when calling Krita's actions
def add_mask(layers: list, cur_selection):
if len(layers) < 1:
self.doc.setSelection(cur_selection) # reset to current selection
return
layer = layers.pop()
orig_visible = layer.visible()
orig_name = layer.name()
def restore():
# assume newly flattened layer is active
result = self.doc.activeNode()
result.setVisible(orig_visible)
result.setName(orig_name)
add_mask(layers, cur_selection)
layer.setVisible(True)
self.doc.setActiveNode(layer)
self.doc.setSelection(orig_selection)
add_mask_action.trigger()
if create_mask:
# collapse transparency mask by default
layer.setCollapsed(True)
layer.setVisible(orig_visible)
QTimer.singleShot(
ADD_MASK_TIMEOUT, lambda: add_mask(layers, cur_selection)
)
else:
# flatten transparency mask into layer
merge_mask_action.trigger()
QTimer.singleShot(ADD_MASK_TIMEOUT, lambda: restore())
def trigger_mask_adding(layers: list):
layers = layers[::-1] # causes final active layer to be the top one
def handle_mask():
cur_selection = self.selection.duplicate() if self.selection else None
add_mask(layers, cur_selection)
QTimer.singleShot(ADD_MASK_TIMEOUT, lambda: handle_mask())
return trigger_mask_adding