944 def openDialogOptions(self):
945 """Open dialog box to let user define channel extraction options"""
948 previewBaSrc = QByteArray()
949 lblPreview = [QLabel(), QLabel(), QLabel(), QLabel()]
950 lblPreviewLbl = [QLabel(), QLabel(), QLabel(), QLabel()]
953 # ----------------------------------------------------------------------
954 # Define signal and slots for UI widgets
956 def ledLayerGroupName_Changed(value):
957 self.__outputOptions['layerGroupName'] = value
960 def ledLayerColorName_Changed(value):
961 self.__outputOptions['layerColorName'] = value
964 def cmbOutputMode_Changed(value):
965 self.__outputOptions['outputMode'] = value
969 def cmbOriginalLayerAction_Changed(value):
970 self.__outputOptions['originalLayerAction'] = value
973 pbProgress.setVisible(True)
975 backupValue = self.__outputOptions['layerColorName']
976 self.__outputOptions['layerColorName'] = '{color:long}'
978 # create a temporary document to work
979 tmpDocument = Application.createDocument(imgThumbSrc.width(), imgThumbSrc.height(), "tmp", "RGBA", "U8", "", 120.0)
981 # create a layer used as original layer
982 originalLayer = tmpDocument.createNode("Original", "paintlayer")
983 tmpDocument.rootNode().addChildNode(originalLayer, None)
984 # and set original image content
985 originalLayer.setPixelData(previewBaSrc, 0, 0, tmpDocument.width(), tmpDocument.height())
988 groupLayer = self.process(tmpDocument, originalLayer, pbProgress)
990 self.__outputOptions['layerColorName'] = backupValue
992 originalLayer.setVisible(False)
993 groupLayer.setVisible(True)
995 for layer in groupLayer.childNodes():
996 layer.setBlendingMode('normal')
997 layer.setVisible(False)
998 tmpDocument.refreshProjection()
1001 for layer in groupLayer.childNodes():
1002 layer.setVisible(True)
1003 tmpDocument.refreshProjection()
1005 lblPreview[index].setPixmap(QPixmap.fromImage(tmpDocument.projection(0, 0, tmpDocument.width(), tmpDocument.height())))
1006 lblPreviewLbl[index].setText("<i>{0}</i>".format(layer.name()))
1007 layer.setVisible(False)
1012 lblPreview[3].setVisible(True)
1013 lblPreviewLbl[3].setVisible(True)
1015 lblPreview[3].setVisible(False)
1016 lblPreviewLbl[3].setVisible(False)
1021 pbProgress.setVisible(False)
1024 # ----------------------------------------------------------------------
1026 dlgMain = QDialog(Application.activeWindow().qwindow())
1027 dlgMain.setWindowTitle(PLUGIN_DIALOG_TITLE)
1028 # resizeable with minimum size
1029 dlgMain.setSizeGripEnabled(True)
1030 dlgMain.setMinimumSize(DOPT_MIN_WIDTH, DOPT_MIN_HEIGHT)
1031 dlgMain.setModal(True)
1033 # ......................................................................
1034 # main dialog box, container
1035 vbxMainContainer = QVBoxLayout(dlgMain)
1037 # main dialog box, current layer name
1038 lblLayerName = QLabel("{0} <b><i>{1}</i></b>".format(i18n("Processing layer"), self.__sourceLayer.name()))
1039 lblLayerName.setFixedHeight(30)
1040 vbxMainContainer.addWidget(lblLayerName)
1042 # main dialog box, groupbox for layers options
1043 gbxLayersMgt = QGroupBox("Layers management")
1044 vbxMainContainer.addWidget(gbxLayersMgt)
1046 # main dialog box, groupbox for output options
1047 gbxOutputResults = QGroupBox("Output results")
1048 vbxMainContainer.addWidget(gbxOutputResults)
1050 vbxMainContainer.addStretch()
1052 # main dialog box, OK/Cancel buttons
1053 dbbxOkCancel = QDialogButtonBox(dlgMain)
1054 dbbxOkCancel.setOrientation(Qt.Orientation.Horizontal)
1055 dbbxOkCancel.setStandardButtons(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
1056 dbbxOkCancel.accepted.connect(dlgMain.accept)
1057 dbbxOkCancel.rejected.connect(dlgMain.reject)
1058 vbxMainContainer.addWidget(dbbxOkCancel)
1060 # ......................................................................
1061 # create layout for groupbox "Layers management"
1062 flLayersMgt = QFormLayout()
1063 gbxLayersMgt.setLayout(flLayersMgt)
1065 ledLayerGroupName = QLineEdit()
1066 ledLayerGroupName.setText(self.__outputOptions['layerGroupName'])
1067 ledLayerGroupName.textChanged.connect(ledLayerGroupName_Changed)
1068 flLayersMgt.addRow(i18nc('The name for a new group layer; the generated layers will be placed in this group.', 'New layer group name'), ledLayerGroupName)
1070 ledLayerColorName = QLineEdit()
1071 ledLayerColorName.setText(self.__outputOptions['layerColorName'])
1072 ledLayerColorName.textChanged.connect(ledLayerColorName_Changed)
1073 flLayersMgt.addRow(i18nc('Defines how the name for each layer created from the channel is generated.', 'New layers color name'), ledLayerColorName)
1075 cmbOriginalLayerAction = QComboBox()
1076 cmbOriginalLayerAction.addItems([
1077 ORIGINAL_LAYER_KEEPUNCHANGED,
1078 ORIGINAL_LAYER_KEEPVISIBLE,
1079 ORIGINAL_LAYER_KEEPHIDDEN,
1080 ORIGINAL_LAYER_REMOVE
1082 cmbOriginalLayerAction.setCurrentText(self.__outputOptions['originalLayerAction'])
1083 cmbOriginalLayerAction.currentTextChanged.connect(cmbOriginalLayerAction_Changed)
1084 flLayersMgt.addRow(i18n("Original layer"), cmbOriginalLayerAction)
1086 # ......................................................................
1087 # create layout for groupbox "Output results"
1088 flOutputResults = QFormLayout()
1089 gbxOutputResults.setLayout(flOutputResults)
1091 cmbOutputMode = QComboBox()
1092 cmbOutputMode.addItems([
1100 cmbOutputMode.setCurrentText(self.__outputOptions['outputMode'])
1101 cmbOutputMode.currentTextChanged.connect(cmbOutputMode_Changed)
1102 flOutputResults.addRow(i18n("Mode"), cmbOutputMode)
1104 vbxPreviewLblContainer = QHBoxLayout()
1105 flOutputResults.addRow('', vbxPreviewLblContainer)
1106 vbxPreviewContainer = QHBoxLayout()
1107 flOutputResults.addRow('', vbxPreviewContainer)
1109 # add preview progressbar
1110 pbProgress = QProgressBar()
1111 pbProgress.setFixedHeight(8)
1112 pbProgress.setTextVisible(False)
1113 pbProgress.setVisible(False)
1114 pbProgress.setRange(0, 107)
1115 flOutputResults.addRow('', pbProgress)
1118 imageRatio = self.__sourceDocument.width() / self.__sourceDocument.height()
1119 rect = QRect(0, 0, OUTPUT_PREVIEW_MAXSIZE, OUTPUT_PREVIEW_MAXSIZE)
1121 # always ensure that final preview width and/or height is lower or equal than OUTPUT_PREVIEW_MAXSIZE
1124 rect.setWidth(int(imageRatio * OUTPUT_PREVIEW_MAXSIZE))
1127 rect.setHeight(int(OUTPUT_PREVIEW_MAXSIZE / imageRatio))
1129 imgThumbSrc = self.toQImage(self.__sourceLayer, rect)
1131 previewBaSrc.resize(imgThumbSrc.sizeInBytes())
1132 ptr = imgThumbSrc.bits()
1133 ptr.setsize(imgThumbSrc.sizeInBytes())
1134 previewBaSrc = QByteArray(ptr.asstring())
1137 lblPreviewSrc = QLabel()
1138 lblPreviewSrc.setPixmap(QPixmap.fromImage(imgThumbSrc))
1139 lblPreviewSrc.setFixedHeight(imgThumbSrc.height() + 4)
1140 lblPreviewSrc.setFixedWidth(imgThumbSrc.width() + 4)
1141 vbxPreviewContainer.addWidget(lblPreviewSrc)
1143 lblPreviewLblSrc = QLabel(i18nc("the original layer", "Original"))
1144 lblPreviewLblSrc.setFixedWidth(imgThumbSrc.width() + 4)
1145 vbxPreviewLblContainer.addWidget(lblPreviewLblSrc)
1148 vbxPreviewLblContainer.addWidget(QLabel(" "))
1149 vbxPreviewContainer.addWidget(QLabel(">"))
1151 lblPreview[3].setPixmap(QPixmap.fromImage(imgThumbSrc))
1152 lblPreview[3].setFixedHeight(imgThumbSrc.height() + 4)
1153 lblPreview[3].setFixedWidth(imgThumbSrc.width() + 4)
1154 vbxPreviewContainer.addWidget(lblPreview[3])
1156 lblPreviewLbl[3] = QLabel(i18n("<i>Cyan</i>"))
1157 lblPreviewLbl[3].setIndent(10)
1158 lblPreviewLbl[3].setFixedWidth(imgThumbSrc.width() + 4)
1159 vbxPreviewLblContainer.addWidget(lblPreviewLbl[3])
1162 lblPreview[2] = QLabel()
1163 lblPreview[2].setPixmap(QPixmap.fromImage(imgThumbSrc))
1164 lblPreview[2].setFixedHeight(imgThumbSrc.height() + 4)
1165 lblPreview[2].setFixedWidth(imgThumbSrc.width() + 4)
1166 vbxPreviewContainer.addWidget(lblPreview[2])
1168 lblPreviewLbl[2] = QLabel(i18n("<i>Magenta</i>"))
1169 lblPreviewLbl[2].setIndent(10)
1170 lblPreviewLbl[2].setFixedWidth(imgThumbSrc.width() + 4)
1171 vbxPreviewLblContainer.addWidget(lblPreviewLbl[2])
1174 lblPreview[1] = QLabel()
1175 lblPreview[1].setPixmap(QPixmap.fromImage(imgThumbSrc))
1176 lblPreview[1].setFixedHeight(imgThumbSrc.height() + 4)
1177 lblPreview[1].setFixedWidth(imgThumbSrc.width() + 4)
1178 vbxPreviewContainer.addWidget(lblPreview[1])
1180 lblPreviewLbl[1] = QLabel(i18n("<i>Yellow</i>"))
1181 lblPreviewLbl[1].setIndent(10)
1182 lblPreviewLbl[1].setFixedWidth(imgThumbSrc.width() + 4)
1183 vbxPreviewLblContainer.addWidget(lblPreviewLbl[1])
1186 lblPreview[0] = QLabel()
1187 lblPreview[0].setPixmap(QPixmap.fromImage(imgThumbSrc))
1188 lblPreview[0].setFixedHeight(imgThumbSrc.height() + 4)
1189 lblPreview[0].setFixedWidth(imgThumbSrc.width() + 4)
1190 vbxPreviewContainer.addWidget(lblPreview[0])
1192 lblPreviewLbl[0] = QLabel(i18n("<i>Black</i>"))
1193 lblPreviewLbl[0].setIndent(10)
1194 lblPreviewLbl[0].setFixedWidth(imgThumbSrc.width() + 4)
1195 vbxPreviewLblContainer.addWidget(lblPreviewLbl[0])
1198 vbxPreviewLblContainer.addStretch()
1199 vbxPreviewContainer.addStretch()
1203 returned = dlgMain.exec()
1232 def process(self, pDocument, pOriginalLayer, pProgress):
1233 """Process given layer with current options"""
1236 document = pDocument
1237 originalLayer = pOriginalLayer
1238 parentGroupLayer = None
1239 currentProcessedLayer = None
1240 originalLayerIsVisible = originalLayer.visible()
1243 def getLayerByName(parent, value):
1244 """search and return a layer by name, within given parent group"""
1246 return document.nodeByName(value)
1248 for layer in parent.childNodes():
1249 if layer.name() == value:
1255 def duplicateLayer(currentProcessedLayer, value):
1256 """Duplicate layer from given name
1257 New layer become active layer
1262 srcName = re.match("^@(.*)", value)
1264 if not srcName is None:
1265 # reference to a specific layer
1266 if srcName[1] == 'original':
1267 # original layer currently processed
1268 srcLayer = originalLayer
1270 # a color layer previously built (and finished)
1271 srcLayer = getLayerByName(parentGroupLayer, parseLayerName(self.__outputOptions['layerColorName'], srcName[1]))
1273 # a layer with a fixed name
1274 srcLayer = document.nodeByName(parseLayerName(value, ''))
1277 if not srcLayer is None:
1278 newLayer = srcLayer.duplicate()
1281 newLayer.setName("c2l-w{0}".format(self.layerNum))
1283 parentGroupLayer.addChildNode(newLayer, currentProcessedLayer)
1289 def newLayer(currentProcessedLayer, value):
1290 """Create a new layer of given type
1291 New layer become active layer
1296 if value is None or not value['type'] in ['filllayer']:
1297 # given type for new layer is not valid
1298 # currently only one layer type is implemented
1301 if value['type'] == 'filllayer':
1302 infoObject = InfoObject();
1303 infoObject.setProperty("color", value['color'])
1304 selection = Selection();
1305 selection.select(0, 0, document.width(), document.height(), 255)
1307 newLayer = document.createFillLayer(value['color'].name(), "color", infoObject, selection)
1312 newLayer.setName("c2l-w{0}".format(self.layerNum))
1314 parentGroupLayer.addChildNode(newLayer, currentProcessedLayer)
1316 # Need to force generator otherwise, information provided when creating layer seems to not be taken in
1318 newLayer.setGenerator("color", infoObject)
1325 def mergeDown(currentProcessedLayer, value):
1326 """Merge current layer with layer below"""
1327 if currentProcessedLayer is None:
1330 newLayer = currentProcessedLayer.mergeDown()
1332 # when layer is merged down:
1333 # - a new layer seems to be created (reference to 'down' layer does not match anymore layer in group)
1334 # - retrieved 'newLayer' reference does not match to new layer resulting from merge
1335 # - activeNode() in document doesn't match to new layer resulting from merge
1336 # maybe it's norpmal, maybe not...
1337 # but the only solution to be able to work on merged layer (with current script) is to consider that from
1338 # parent node, last child match to last added layer and then, to our merged layer
1339 currentProcessedLayer = parentGroupLayer.childNodes()[-1]
1340 # for an unknown reason, merged layer bounds are not corrects... :'-(
1341 currentProcessedLayer.cropNode(0, 0, document.width(), document.height())
1342 return currentProcessedLayer
1345 def applyBlendingMode(currentProcessedLayer, value):
1346 """Set blending mode for current laye
r"""
1347 if currentProcessedLayer is None or value is None or value == '':
1350 currentProcessedLayer.setBlendingMode(value)
1354 def applyFilter(currentProcessedLayer, value):
1355 """Apply filter to laye
r"""
1356 if currentProcessedLayer is None or value is None or value == '':
1359 filterName = re.match("name=([^;]+)", value)
1361 if filterName is None:
1364 filter = Application.filter(filterName.group(1))
1365 filterConfiguration = filter.configuration()
1367 for parameter in value.split(';'):
1368 parameterName = re.match("^([^=]+)=(.*)", parameter)
1370 if not parameterName is None and parameterName != 'name':
1371 filterConfiguration.setProperty(parameterName.group(1), parameterName.group(2))
1373 filter.setConfiguration(filterConfiguration)
1374 filter.apply(currentProcessedLayer, 0, 0, document.width(), document.height())
1376 return currentProcessedLayer
1379 def parseLayerName(value, color):
1380 """Parse layer name"""
1384 returned = returned.replace("{source:name}", originalLayer.name())
1385 returned = returned.replace("{mode}", OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['groupLayerName'])
1386 returned = returned.replace("{color:short}", color)
1388 returned = returned.replace("{color:long}", i18n("Cyan"))
1390 returned = returned.replace("{color:long}", i18n("Magenta"))
1392 returned = returned.replace("{color:long}", i18n("Yellow"))
1394 returned = returned.replace("{color:long}", i18n("Black"))
1396 returned = returned.replace("{color:long}", i18n("Red"))
1398 returned = returned.replace("{color:long}", i18n("Green"))
1400 returned = returned.replace("{color:long}", i18n("Blue"))
1402 returned = returned.replace("{color:long}", "")
1407 if document is None or originalLayer is None:
1408 # should not occurs, but...
1411 if not pProgress is None:
1413 for layer in OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['layers']:
1414 stepTotal+=len(layer['process'])
1416 pProgress.setRange(0, stepTotal)
1419 if originalLayerIsVisible == False:
1420 originalLayer.setVisible(True)
1422 # ----------------------------------------------------------------------
1423 # Create new group layer
1424 parentGroupLayer = document.createGroupLayer(parseLayerName(self.__outputOptions['layerGroupName'], ''))
1426 self.progressNext(pProgress)
1428 currentProcessedLayer = None
1430 for layer in OUTPUT_MODE_NFO[self.__outputOptions['outputMode']]['layers']:
1431 for process in layer['process']:
1432 if process['action'] == 'duplicate':
1433 currentProcessedLayer = duplicateLayer(currentProcessedLayer, process['value'])
1434 elif process['action'] == 'new':
1435 currentProcessedLayer = newLayer(currentProcessedLayer, process['value'])
1436 elif process['action'] == 'merge down':
1437 currentProcessedLayer = mergeDown(currentProcessedLayer, process['value'])
1439 elif process['action'] == 'blending mode':
1440 applyBlendingMode(currentProcessedLayer, process['value'])
1441 elif process['action'] == 'filter':
1442 applyFilter(currentProcessedLayer, process['value'])
1444 self.progressNext(pProgress)
1446 if not currentProcessedLayer is None:
1447 # rename currentProcessedLayer
1448 currentProcessedLayer.setName(parseLayerName(self.__outputOptions['layerColorName'], layer['color']))
1450 document.rootNode().addChildNode(parentGroupLayer, originalLayer)
1451 self.progressNext(pProgress)
1453 if self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_KEEPVISIBLE:
1454 originalLayer.setVisible(True)
1455 elif self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_KEEPHIDDEN:
1456 originalLayer.setVisible(False)
1457 elif self.__outputOptions['originalLayerAction'] == ORIGINAL_LAYER_REMOVE:
1458 originalLayer.remove()
1460 # ORIGINAL_LAYER_KEEPUNCHANGED
1461 originalLayer.setVisible(originalLayerIsVisible)
1464 self.progressNext(pProgress)
1466 document.refreshProjection()
1467 self.progressNext(pProgress)
1469 document.setActiveNode(parentGroupLayer)
1471 return parentGroupLayer
1474#ChannelsToLayers(Krita.instance()).process(Application.activeDocument(), Application.activeDocument().activeNode(), None)
1475#ChannelsToLayers(Krita.instance()).action_triggered()