Changeset View
Changeset View
Standalone View
Standalone View
plugins/python/exportlayers/uiexportlayers.py
1 | ''' | 1 | # This script is licensed CC 0 1.0, so that you can learn from it. | ||
---|---|---|---|---|---|
2 | This script is licensed CC 0 1.0, so that you can learn from it. | | |||
3 | 2 | | |||
4 | ------ CC 0 1.0 --------------- | 3 | # ------ CC 0 1.0 --------------- | ||
5 | 4 | | |||
6 | The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. | 5 | # The person who associated a work with this deed has dedicated the | ||
6 | # work to the public domain by waiving all of his or her rights to the | ||||
7 | # work worldwide under copyright law, including all related and | ||||
8 | # neighboring rights, to the extent allowed by law. | ||||
7 | 9 | | |||
8 | You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. | 10 | # You can copy, modify, distribute and perform the work, even for | ||
11 | # commercial purposes, all without asking permission. | ||||
12 | | ||||
13 | # https://creativecommons.org/publicdomain/zero/1.0/legalcode | ||||
9 | 14 | | |||
10 | https://creativecommons.org/publicdomain/zero/1.0/legalcode | | |||
11 | ''' | | |||
12 | from . import exportlayersdialog | 15 | from . import exportlayersdialog | ||
13 | from PyQt5.QtCore import Qt | 16 | from PyQt5.QtCore import Qt | ||
14 | from PyQt5.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout, | 17 | from PyQt5.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout, | ||
15 | QDialogButtonBox, QVBoxLayout, QFrame, | 18 | QDialogButtonBox, QVBoxLayout, QFrame, | ||
16 | QPushButton, QAbstractScrollArea, QLineEdit, | 19 | QPushButton, QAbstractScrollArea, QLineEdit, | ||
17 | QMessageBox, QFileDialog, QCheckBox, QSpinBox, | 20 | QMessageBox, QFileDialog, QCheckBox, QSpinBox, | ||
18 | QComboBox) | 21 | QComboBox) | ||
19 | import os | 22 | import os | ||
20 | import errno | | |||
21 | import krita | 23 | import krita | ||
22 | 24 | | |||
23 | 25 | | |||
24 | class UIExportLayers(object): | 26 | class UIExportLayers(object): | ||
25 | 27 | | |||
26 | def __init__(self): | 28 | def __init__(self): | ||
27 | self.mainDialog = exportlayersdialog.ExportLayersDialog() | 29 | self.mainDialog = exportlayersdialog.ExportLayersDialog() | ||
28 | self.mainLayout = QVBoxLayout(self.mainDialog) | 30 | self.mainLayout = QVBoxLayout(self.mainDialog) | ||
29 | self.formLayout = QFormLayout() | 31 | self.formLayout = QFormLayout() | ||
30 | self.documentLayout = QVBoxLayout() | 32 | self.documentLayout = QVBoxLayout() | ||
31 | self.directorySelectorLayout = QHBoxLayout() | 33 | self.directorySelectorLayout = QHBoxLayout() | ||
32 | self.optionsLayout = QVBoxLayout() | 34 | self.optionsLayout = QVBoxLayout() | ||
33 | self.resolutionLayout = QHBoxLayout() | 35 | self.resolutionLayout = QHBoxLayout() | ||
34 | 36 | | |||
35 | self.refreshButton = QPushButton(i18n("Refresh")) | 37 | self.refreshButton = QPushButton(i18n("Refresh")) | ||
36 | self.widgetDocuments = QListWidget() | 38 | self.widgetDocuments = QListWidget() | ||
37 | self.directoryTextField = QLineEdit() | 39 | self.directoryTextField = QLineEdit() | ||
38 | self.directoryDialogButton = QPushButton(i18n("...")) | 40 | self.directoryDialogButton = QPushButton(i18n("...")) | ||
39 | self.exportFilterLayersCheckBox = QCheckBox(i18n("Export filter layers")) | 41 | self.exportFilterLayersCheckBox = QCheckBox( | ||
42 | i18n("Export filter layers")) | ||||
40 | self.batchmodeCheckBox = QCheckBox(i18n("Export in batchmode")) | 43 | self.batchmodeCheckBox = QCheckBox(i18n("Export in batchmode")) | ||
41 | self.ignoreInvisibleLayersCheckBox = QCheckBox(i18n("Ignore invisible layers")) | 44 | self.ignoreInvisibleLayersCheckBox = QCheckBox( | ||
45 | i18n("Ignore invisible layers")) | ||||
42 | self.xResSpinBox = QSpinBox() | 46 | self.xResSpinBox = QSpinBox() | ||
43 | self.yResSpinBox = QSpinBox() | 47 | self.yResSpinBox = QSpinBox() | ||
44 | self.formatsComboBox = QComboBox() | 48 | self.formatsComboBox = QComboBox() | ||
45 | 49 | | |||
46 | self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) | 50 | self.buttonBox = QDialogButtonBox( | ||
51 | QDialogButtonBox.Ok | QDialogButtonBox.Cancel) | ||||
47 | 52 | | |||
48 | self.kritaInstance = krita.Krita.instance() | 53 | self.kritaInstance = krita.Krita.instance() | ||
49 | self.documentsList = [] | 54 | self.documentsList = [] | ||
50 | 55 | | |||
51 | self.directoryTextField.setReadOnly(True) | 56 | self.directoryTextField.setReadOnly(True) | ||
52 | self.batchmodeCheckBox.setChecked(True) | 57 | self.batchmodeCheckBox.setChecked(True) | ||
53 | self.directoryDialogButton.clicked.connect(self._selectDir) | 58 | self.directoryDialogButton.clicked.connect(self._selectDir) | ||
54 | self.widgetDocuments.currentRowChanged.connect(self._setResolution) | 59 | self.widgetDocuments.currentRowChanged.connect(self._setResolution) | ||
55 | self.refreshButton.clicked.connect(self.refreshButtonClicked) | 60 | self.refreshButton.clicked.connect(self.refreshButtonClicked) | ||
56 | self.buttonBox.accepted.connect(self.confirmButton) | 61 | self.buttonBox.accepted.connect(self.confirmButton) | ||
57 | self.buttonBox.rejected.connect(self.mainDialog.close) | 62 | self.buttonBox.rejected.connect(self.mainDialog.close) | ||
58 | 63 | | |||
59 | self.mainDialog.setWindowModality(Qt.NonModal) | 64 | self.mainDialog.setWindowModality(Qt.NonModal) | ||
60 | self.widgetDocuments.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents) | 65 | self.widgetDocuments.setSizeAdjustPolicy( | ||
66 | QAbstractScrollArea.AdjustToContents) | ||||
61 | 67 | | |||
62 | def initialize(self): | 68 | def initialize(self): | ||
63 | self.loadDocuments() | 69 | self.loadDocuments() | ||
64 | 70 | | |||
65 | self.xResSpinBox.setRange(1, 10000) | 71 | self.xResSpinBox.setRange(1, 10000) | ||
66 | self.yResSpinBox.setRange(1, 10000) | 72 | self.yResSpinBox.setRange(1, 10000) | ||
67 | 73 | | |||
68 | self.formatsComboBox.addItem(i18n("JPEG")) | 74 | self.formatsComboBox.addItem(i18n("JPEG")) | ||
69 | self.formatsComboBox.addItem(i18n("PNG")) | 75 | self.formatsComboBox.addItem(i18n("PNG")) | ||
70 | 76 | | |||
71 | self.documentLayout.addWidget(self.widgetDocuments) | 77 | self.documentLayout.addWidget(self.widgetDocuments) | ||
72 | self.documentLayout.addWidget(self.refreshButton) | 78 | self.documentLayout.addWidget(self.refreshButton) | ||
73 | 79 | | |||
74 | self.directorySelectorLayout.addWidget(self.directoryTextField) | 80 | self.directorySelectorLayout.addWidget(self.directoryTextField) | ||
75 | self.directorySelectorLayout.addWidget(self.directoryDialogButton) | 81 | self.directorySelectorLayout.addWidget(self.directoryDialogButton) | ||
76 | 82 | | |||
77 | self.optionsLayout.addWidget(self.exportFilterLayersCheckBox) | 83 | self.optionsLayout.addWidget(self.exportFilterLayersCheckBox) | ||
78 | self.optionsLayout.addWidget(self.batchmodeCheckBox) | 84 | self.optionsLayout.addWidget(self.batchmodeCheckBox) | ||
79 | self.optionsLayout.addWidget(self.ignoreInvisibleLayersCheckBox) | 85 | self.optionsLayout.addWidget(self.ignoreInvisibleLayersCheckBox) | ||
80 | 86 | | |||
81 | self.resolutionLayout.addWidget(self.xResSpinBox) | 87 | self.resolutionLayout.addWidget(self.xResSpinBox) | ||
82 | self.resolutionLayout.addWidget(self.yResSpinBox) | 88 | self.resolutionLayout.addWidget(self.yResSpinBox) | ||
83 | 89 | | |||
84 | self.formLayout.addRow(i18n("Documents:"), self.documentLayout) | 90 | self.formLayout.addRow(i18n("Documents:"), self.documentLayout) | ||
85 | self.formLayout.addRow(i18n("Initial directory:"), self.directorySelectorLayout) | 91 | self.formLayout.addRow( | ||
92 | i18n("Initial directory:"), self.directorySelectorLayout) | ||||
86 | self.formLayout.addRow(i18n("Export options:"), self.optionsLayout) | 93 | self.formLayout.addRow(i18n("Export options:"), self.optionsLayout) | ||
87 | self.formLayout.addRow(i18n("Resolution:"), self.resolutionLayout) | 94 | self.formLayout.addRow(i18n("Resolution:"), self.resolutionLayout) | ||
88 | self.formLayout.addRow(i18n("Images extensions:"), self.formatsComboBox) | 95 | self.formLayout.addRow( | ||
96 | i18n("Images extensions:"), self.formatsComboBox) | ||||
89 | 97 | | |||
90 | self.line = QFrame() | 98 | self.line = QFrame() | ||
91 | self.line.setFrameShape(QFrame.HLine) | 99 | self.line.setFrameShape(QFrame.HLine) | ||
92 | self.line.setFrameShadow(QFrame.Sunken) | 100 | self.line.setFrameShadow(QFrame.Sunken) | ||
93 | 101 | | |||
94 | self.mainLayout.addLayout(self.formLayout) | 102 | self.mainLayout.addLayout(self.formLayout) | ||
95 | self.mainLayout.addWidget(self.line) | 103 | self.mainLayout.addWidget(self.line) | ||
96 | self.mainLayout.addWidget(self.buttonBox) | 104 | self.mainLayout.addWidget(self.buttonBox) | ||
97 | 105 | | |||
98 | self.mainDialog.resize(500, 300) | 106 | self.mainDialog.resize(500, 300) | ||
99 | self.mainDialog.setWindowTitle(i18n("Export Layers")) | 107 | self.mainDialog.setWindowTitle(i18n("Export Layers")) | ||
100 | self.mainDialog.setSizeGripEnabled(True) | 108 | self.mainDialog.setSizeGripEnabled(True) | ||
101 | self.mainDialog.show() | 109 | self.mainDialog.show() | ||
102 | self.mainDialog.activateWindow() | 110 | self.mainDialog.activateWindow() | ||
103 | 111 | | |||
104 | def loadDocuments(self): | 112 | def loadDocuments(self): | ||
105 | self.widgetDocuments.clear() | 113 | self.widgetDocuments.clear() | ||
106 | 114 | | |||
107 | self.documentsList = [document for document in self.kritaInstance.documents() if document.fileName()] | 115 | self.documentsList = [ | ||
116 | document for document in self.kritaInstance.documents() | ||||
117 | if document.fileName() | ||||
118 | ] | ||||
108 | 119 | | |||
109 | for document in self.documentsList: | 120 | for document in self.documentsList: | ||
110 | self.widgetDocuments.addItem(document.fileName()) | 121 | self.widgetDocuments.addItem(document.fileName()) | ||
111 | 122 | | |||
112 | def refreshButtonClicked(self): | 123 | def refreshButtonClicked(self): | ||
113 | self.loadDocuments() | 124 | self.loadDocuments() | ||
114 | 125 | | |||
115 | def confirmButton(self): | 126 | def confirmButton(self): | ||
116 | selectedPaths = [item.text() for item in self.widgetDocuments.selectedItems()] | 127 | selectedPaths = [ | ||
117 | selectedDocuments = [document for document in self.documentsList for path in selectedPaths if path == document.fileName()] | 128 | item.text() for item in self.widgetDocuments.selectedItems()] | ||
129 | selectedDocuments = [ | ||||
130 | document for document in self.documentsList | ||||
131 | for path in selectedPaths if path == document.fileName() | ||||
132 | ] | ||||
118 | 133 | | |||
119 | self.msgBox = QMessageBox(self.mainDialog) | 134 | self.msgBox = QMessageBox(self.mainDialog) | ||
120 | if not selectedDocuments: | 135 | if not selectedDocuments: | ||
121 | self.msgBox.setText(i18n("Select one document.")) | 136 | self.msgBox.setText(i18n("Select one document.")) | ||
122 | elif not self.directoryTextField.text(): | 137 | elif not self.directoryTextField.text(): | ||
123 | self.msgBox.setText(i18n("Select the initial directory.")) | 138 | self.msgBox.setText(i18n("Select the initial directory.")) | ||
124 | else: | 139 | else: | ||
125 | self.export(selectedDocuments[0]) | 140 | self.export(selectedDocuments[0]) | ||
126 | self.msgBox.setText(i18n("All layers has been exported.")) | 141 | self.msgBox.setText(i18n("All layers has been exported.")) | ||
127 | self.msgBox.exec_() | 142 | self.msgBox.exec_() | ||
128 | 143 | | |||
129 | def mkdir(self, directory): | 144 | def mkdir(self, directory): | ||
130 | target_directory = self.directoryTextField.text() + directory | 145 | target_directory = self.directoryTextField.text() + directory | ||
131 | if os.path.exists(target_directory) and os.path.isdir(target_directory): | 146 | if (os.path.exists(target_directory) | ||
147 | and os.path.isdir(target_directory)): | ||||
132 | return | 148 | return | ||
133 | 149 | | |||
134 | try: | 150 | try: | ||
135 | os.makedirs(target_directory) | 151 | os.makedirs(target_directory) | ||
136 | except OSError as e: | 152 | except OSError as e: | ||
137 | raise e | 153 | raise e | ||
138 | 154 | | |||
139 | def export(self, document): | 155 | def export(self, document): | ||
140 | Application.setBatchmode(self.batchmodeCheckBox.isChecked()) | 156 | Application.setBatchmode(self.batchmodeCheckBox.isChecked()) | ||
141 | 157 | | |||
142 | documentName = document.fileName() if document.fileName() else 'Untitled' | 158 | documentName = document.fileName() if document.fileName() else 'Untitled' # noqa: E501 | ||
143 | fileName, extension = os.path.splitext(os.path.basename(documentName)) | 159 | fileName, extension = os.path.splitext(os.path.basename(documentName)) | ||
144 | self.mkdir('/' + fileName) | 160 | self.mkdir('/' + fileName) | ||
145 | 161 | | |||
146 | self._exportLayers(document.rootNode(), self.formatsComboBox.currentText(), '/' + fileName) | 162 | self._exportLayers( | ||
163 | document.rootNode(), | ||||
164 | self.formatsComboBox.currentText(), | ||||
165 | '/' + fileName) | ||||
147 | Application.setBatchmode(True) | 166 | Application.setBatchmode(True) | ||
148 | 167 | | |||
149 | def _exportLayers(self, parentNode, fileFormat, parentDir): | 168 | def _exportLayers(self, parentNode, fileFormat, parentDir): | ||
150 | """ This method get all sub-nodes from the current node and export then in | 169 | """ This method get all sub-nodes from the current node and export then in | ||
151 | the defined format.""" | 170 | the defined format.""" | ||
152 | 171 | | |||
153 | for node in parentNode.childNodes(): | 172 | for node in parentNode.childNodes(): | ||
154 | newDir = '' | 173 | newDir = '' | ||
155 | if node.type() == 'grouplayer': | 174 | if node.type() == 'grouplayer': | ||
156 | newDir = os.path.join(parentDir, node.name()) | 175 | newDir = os.path.join(parentDir, node.name()) | ||
157 | self.mkdir(newDir) | 176 | self.mkdir(newDir) | ||
158 | elif not self.exportFilterLayersCheckBox.isChecked() and 'filter' in node.type(): | 177 | elif (not self.exportFilterLayersCheckBox.isChecked() | ||
178 | and 'filter' in node.type()): | ||||
159 | continue | 179 | continue | ||
160 | elif self.ignoreInvisibleLayersCheckBox.isChecked() and not node.visible(): | 180 | elif (self.ignoreInvisibleLayersCheckBox.isChecked() | ||
181 | and not node.visible()): | ||||
161 | continue | 182 | continue | ||
162 | else: | 183 | else: | ||
163 | nodeName = node.name() | 184 | nodeName = node.name() | ||
164 | _fileFormat = self.formatsComboBox.currentText() | 185 | _fileFormat = self.formatsComboBox.currentText() | ||
165 | if '[jpeg]' in nodeName: | 186 | if '[jpeg]' in nodeName: | ||
166 | _fileFormat = 'jpeg' | 187 | _fileFormat = 'jpeg' | ||
167 | elif '[png]' in nodeName: | 188 | elif '[png]' in nodeName: | ||
168 | _fileFormat = 'png' | 189 | _fileFormat = 'png' | ||
169 | 190 | | |||
170 | layerFileName = '{0}{1}/{2}.{3}'.format(self.directoryTextField.text(), | 191 | layerFileName = '{0}{1}/{2}.{3}'.format( | ||
171 | parentDir, node.name(), _fileFormat) | 192 | self.directoryTextField.text(), | ||
193 | parentDir, node.name(), _fileFormat) | ||||
172 | node.save(layerFileName, self.xResSpinBox.value(), | 194 | node.save(layerFileName, self.xResSpinBox.value(), | ||
173 | self.yResSpinBox.value(), krita.InfoObject()) | 195 | self.yResSpinBox.value(), krita.InfoObject()) | ||
174 | 196 | | |||
175 | if node.childNodes(): | 197 | if node.childNodes(): | ||
176 | self._exportLayers(node, fileFormat, newDir) | 198 | self._exportLayers(node, fileFormat, newDir) | ||
177 | 199 | | |||
178 | def _selectDir(self): | 200 | def _selectDir(self): | ||
179 | directory = QFileDialog.getExistingDirectory(self.mainDialog, i18n("Select a Folder"), os.path.expanduser("~"), QFileDialog.ShowDirsOnly) | 201 | directory = QFileDialog.getExistingDirectory( | ||
202 | self.mainDialog, | ||||
203 | i18n("Select a Folder"), | ||||
204 | os.path.expanduser("~"), | ||||
205 | QFileDialog.ShowDirsOnly) | ||||
180 | self.directoryTextField.setText(directory) | 206 | self.directoryTextField.setText(directory) | ||
181 | 207 | | |||
182 | def _setResolution(self, index): | 208 | def _setResolution(self, index): | ||
183 | document = self.documentsList[index] | 209 | document = self.documentsList[index] | ||
184 | self.xResSpinBox.setValue(document.width()) | 210 | self.xResSpinBox.setValue(document.width()) | ||
185 | self.yResSpinBox.setValue(document.height()) | 211 | self.yResSpinBox.setValue(document.height()) |