Maybe it would be better to first collect vector layers to new document and then you would have options on how to edit it before export.
Just for fun plugin that collects layers to new document using name + type + color_label filters.
File tree
%AppData%/krita/pykrita/
collect_layers_plugin/
__init__.py
collect_layers_plugin.desktop
__init__.py
import re
from krita import (
Krita,
Extension)
from PyQt5.QtCore import (
Qt,)
from PyQt5.QtGui import (
QColor,
QStandardItemModel,
QStandardItem)
from PyQt5.QtWidgets import (
QDialog,
QDialogButtonBox,
QVBoxLayout,
QHBoxLayout,
QLabel,
QLineEdit,
QListView)
def walk_nodes(top_nodes):
_memo = set() # just to be sure that each node is walked only once
stack = list()
for n in reversed(top_nodes):
unique_id = n.uniqueId()
if unique_id not in _memo:
_memo.add(unique_id)
stack.append(n)
while stack:
cursor = stack.pop(-1)
yield cursor
_memo.add(cursor.uniqueId())
stack.extend(c for c in reversed(cursor.childNodes()) if c.uniqueId() not in _memo)
class CollectLayersDialog(QDialog):
_type_names = (
('Paint Layers', 'paintlayer'),
# ('Group Layers', grouplayer'),
('File Layers', 'filelayer'),
('Filter Layers', 'filterlayer'),
('Fill Layers', 'filllayer'),
# ('Clone Layers', 'clonelayer'),
('Vector Layers', 'vectorlayer'))
# ('Transparency Masks', 'transparencymask'),
# ('Filter Masks', 'filtermask'),
# ('Transform Masks', 'transformmask'),
# ('Selection Masks', 'selectionmask')
_color_labels = (
Qt.transparent,
QColor(91, 173, 220),
QColor(151, 202, 63),
QColor(247, 229, 61),
QColor(255, 170, 63),
QColor(177, 102, 63),
QColor(238, 50, 51),
QColor(191, 106, 209),
QColor(118, 119, 114))
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._init_models()
self._init_window()
self._init_ui()
self._connect_signals()
def _init_models(self):
self._layer_types_model = QStandardItemModel()
types_root = self._layer_types_model.invisibleRootItem()
for type_label, type_name in self._type_names:
type_item = QStandardItem(type_label)
type_item.setData(type_name)
type_item.setCheckable(True)
type_item.setCheckState(Qt.Unchecked)
types_root.appendRow(type_item)
self._color_labels_model = QStandardItemModel()
colors_root = self._color_labels_model.invisibleRootItem()
for color in self._color_labels:
color_item = QStandardItem('')
color_item.setBackground(color)
color_item.setCheckable(True)
color_item.setCheckState(Qt.Unchecked)
colors_root.appendRow(color_item)
def _init_window(self):
self.resize(800, 400)
self.setWindowTitle('Collect Layers')
def _init_ui(self):
layout = QVBoxLayout()
self.setLayout(layout)
self._banner = QLabel('<br /><h1>Collect Layers</h1><br />')
layout.addWidget(self._banner)
self._name_filter_edit = QLineEdit(placeholderText='layer name filter (regex) ...')
layout.addWidget(self._name_filter_edit, stretch=50)
type_and_color_layout = QHBoxLayout()
layout.addLayout(type_and_color_layout, stretch=100)
self._layer_types_view = QListView(toolTip='Filter layers based on layer type (Nothing = Include All)')
self._layer_types_view.setModel(self._layer_types_model)
type_and_color_layout.addWidget(self._layer_types_view, stretch=50)
self._layer_colors_view = QListView(toolTip='Filter layers based on color label (Nothing = Include All)')
self._layer_colors_view.setModel(self._color_labels_model)
type_and_color_layout.addWidget(self._layer_colors_view, stretch=50)
self._buttons = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
layout.addWidget(self._buttons)
def _connect_signals(self):
self._buttons.accepted.connect(self.accept)
self._buttons.rejected.connect(self.reject)
def name_filter(self):
return self._name_filter_edit.text().strip()
def layer_types_filter(self):
result = set()
model = self._layer_types_model
for row in range(model.rowCount()):
type_item = model.item(row)
if type_item.checkState() == Qt.Checked:
result.add(type_item.data())
return result
def layer_colors_filter(self):
result = set()
model = self._color_labels_model
for row in range(model.rowCount()):
color_item = model.item(row)
if color_item.checkState() == Qt.Checked:
result.add(row)
return result
class CollectLayersExtension(Extension):
def setup(self):
pass
def createActions(self, window):
show_collect_layers_dialog = window.createAction(
'show_collect_layers_dialog',
'Show Collect layers dialog',
'tools/show_collect_layers_dialog')
show_collect_layers_dialog.triggered.connect(self._on_show_collect_layers_dialog_triggered)
def _on_show_collect_layers_dialog_triggered(self, checked=None):
dialog = CollectLayersDialog()
if dialog.exec_() == QDialog.Accepted:
self.collect_layers(
dialog.name_filter(),
dialog.layer_types_filter(),
dialog.layer_colors_filter())
def collect_layers(self, name_filter, layer_types_filter, layer_colors_filter):
app = Krita.instance()
doc = app.activeDocument()
if not doc:
return # nothing to do
name_filter_re = re.compile(name_filter or '.*')
result_document = None
for node in walk_nodes(doc.topLevelNodes()):
if not name_filter_re.search(node.name()):
continue # exclude
if layer_types_filter and (node.type() not in layer_types_filter):
continue # exclude
if layer_colors_filter and (node.colorLabel() not in layer_colors_filter):
continue # exclude
# include layer (passed all filters)
if result_document is None:
result_document = app.createDocument(
doc.width(),
doc.height(),
f'{doc.name()}_collected',
doc.colorModel(),
doc.colorDepth(),
doc.colorProfile(),
doc.resolution())
for initial_node in result_document.topLevelNodes():
initial_node.remove() # ToDo: not sure if this is also removed from memory?
root = result_document.rootNode()
cloned_layer = node.clone()
root.addChildNode(cloned_layer, None)
# finally show result
if result_document:
win = app.activeWindow()
if not win:
return # no window, no show
win.addView(result_document)
app = Krita.instance()
app.addExtension(CollectLayersExtension(app))
collect_layers_plugin.desktop
[Desktop Entry]
Type=Service
ServiceTypes=Krita/PythonPlugin
X-KDE-Library=collect_layers_plugin
X-Python-2-Compatible=false
X-Krita-Manual=readme.md
Name=Collect layers Plugin
Comment=Collets layers to new duplicated document
collect_layers_plugin.action is missing, but it should be really normal except maybe show_collect_layers_dialog action should have flag that activates it only when there is active document.
/AkiR