Krita Source Code Documentation
Loading...
Searching...
No Matches
uiexportlayers.py
Go to the documentation of this file.
1# SPDX-License-Identifier: CC0-1.0
2
3from . import exportlayersdialog
4try:
5 from PyQt6.QtCore import (Qt, QRect)
6 from PyQt6.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout,
7 QDialogButtonBox, QVBoxLayout, QFrame,
8 QPushButton, QAbstractScrollArea, QLineEdit,
9 QMessageBox, QCheckBox, QSpinBox,
10 QComboBox, QListWidgetItem)
11except:
12 from PyQt5.QtCore import (Qt, QRect)
13 from PyQt5.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout,
14 QDialogButtonBox, QVBoxLayout, QFrame,
15 QPushButton, QAbstractScrollArea, QLineEdit,
16 QMessageBox, QCheckBox, QSpinBox,
17 QComboBox, QListWidgetItem)
18import os
19from krita import Krita, InfoObject, FileDialog
20from builtins import i18n, Application
21
22
23class UIExportLayers(object):
24
25 def __init__(self):
27 self.mainLayout = QVBoxLayout(self.mainDialog)
28 self.formLayout = QFormLayout()
29 self.resSpinBoxLayout = QFormLayout()
30 self.documentLayout = QVBoxLayout()
31 self.directorySelectorLayout = QHBoxLayout()
32 self.optionsLayout = QVBoxLayout()
33 self.rectSizeLayout = QHBoxLayout()
34
35 self.refreshButton = QPushButton(i18n("Refresh"))
36 self.widgetDocuments = QListWidget()
37 self.directoryTextField = QLineEdit()
38 self.directoryDialogButton = QPushButton(i18n("..."))
40 i18n("Export filter layers"))
41 self.batchmodeCheckBox = QCheckBox(i18n("Export in batchmode"))
42 self.groupAsLayer = QCheckBox(i18n("Group as layer"))
44 i18n("Ignore invisible layers"))
45 self.cropToImageBounds = QCheckBox(
46 i18n("Adjust export size to layer content"))
48 i18n("Add incrementing prefix"))
49
50 self.rectWidthSpinBox = QSpinBox()
51 self.rectHeightSpinBox = QSpinBox()
52 self.formatsComboBox = QComboBox()
53 self.resSpinBox = QSpinBox()
54
55 self.buttonBox = QDialogButtonBox(
56 QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
57
59 self.documentsList = []
60
61 self.directoryTextField.setReadOnly(True)
62 self.batchmodeCheckBox.setChecked(True)
64 self.widgetDocuments.currentRowChanged.connect(self._setResolution_setResolution)
65 self.widgetDocuments.setSelectionMode(QListWidget.SelectionMode.MultiSelection)
66 self.widgetDocuments.setMouseTracking(True) #enable ToolTips to show the paths
68 self.buttonBox.accepted.connect(self.confirmButtonconfirmButton)
69 self.buttonBox.rejected.connect(self.mainDialog.close)
70 self.cropToImageBounds.stateChanged.connect(self._toggleCropSize_toggleCropSize)
71
72 self.mainDialog.setWindowModality(Qt.WindowModality.NonModal)
73 self.widgetDocuments.setSizeAdjustPolicy(
74 QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
75
76 def initialize(self):
77 self.loadDocuments()
78
79 self.rectWidthSpinBox.setRange(1, 10000)
80 self.rectHeightSpinBox.setRange(1, 10000)
81 self.resSpinBox.setRange(20, 1200)
82
83 self.formatsComboBox.addItem(i18n("JPEG"))
84 self.formatsComboBox.addItem(i18n("PNG"))
85
86 self.documentLayout.addWidget(self.widgetDocuments)
87 self.documentLayout.addWidget(self.refreshButton)
88
91
92 self.optionsLayout.addWidget(self.exportFilterLayersCheckBox)
93 self.optionsLayout.addWidget(self.batchmodeCheckBox)
94 self.optionsLayout.addWidget(self.groupAsLayer)
96 self.optionsLayout.addWidget(self.cropToImageBounds)
97 self.optionsLayout.addWidget(self.addIncrementPrefixCheckBox)
98
99 self.resSpinBoxLayout.addRow(i18n("dpi:"), self.resSpinBox)
100
101 self.rectSizeLayout.addWidget(self.rectWidthSpinBox)
102 self.rectSizeLayout.addWidget(self.rectHeightSpinBox)
103 self.rectSizeLayout.addLayout(self.resSpinBoxLayout)
104
105 self.formLayout.addRow(i18n("Documents:"), self.documentLayout)
106 self.formLayout.addRow(
107 i18n("Initial directory:"), self.directorySelectorLayout)
108 self.formLayout.addRow(i18n("Export options:"), self.optionsLayout)
109 self.formLayout.addRow(i18n("Export size:"), self.rectSizeLayout)
110 self.formLayout.addRow(
111 i18n("Images extensions:"), self.formatsComboBox)
112
113 self.line = QFrame()
114 self.line.setFrameShape(QFrame.Shape.HLine)
115 self.line.setFrameShadow(QFrame.Shadow.Sunken)
116
117 self.mainLayout.addLayout(self.formLayout)
118 self.mainLayout.addWidget(self.line)
119 self.mainLayout.addWidget(self.buttonBox)
120
121 self.mainDialog.resize(500, 300)
122 self.mainDialog.setWindowTitle(i18n("Export Layers"))
123 self.mainDialog.setSizeGripEnabled(True)
124 self.mainDialog.show()
125 self.mainDialog.activateWindow()
126
127 def loadDocuments(self):
128 self.widgetDocuments.clear()
129
130 self.documentsList = [
131 document for document in self.kritaInstance.documents()
132 ]
133
134 currentDoc = None
135 if self.kritaInstance.activeDocument():
136 currentDoc = self.kritaInstance.activeDocument().fileName()
137
138 activeDoc = 0
139 docCount = 0
140 for document in self.documentsList:
141 fullName = document.fileName()
142 if document.name(): #if you open a file that isn't a .kra file it won't have a name property...
143 shortName = document.name()
144 else:
145 shortName = os.path.basename(document.fileName()) #... so just get the name from the file using os.path.basename()
146 newListItem= QListWidgetItem(shortName)
147 newListItem.setToolTip(fullName) # ... show the full path as a ToolTip, rather than in the list, better UX
148 if fullName == currentDoc:
149 activeDoc = docCount
150 self.widgetDocuments.addItem(newListItem)
151 docCount += 1
152 if self.widgetDocuments.count():
153 self.widgetDocuments.setCurrentItem(self.widgetDocuments.item(activeDoc))
154
156 self.loadDocuments()
157
158 def confirmButton(self):
159 selectedPaths = [
160 item.toolTip() for item in self.widgetDocuments.selectedItems()]
161 selectedDocuments = [
162 document for document in self.documentsList
163 for path in selectedPaths if path == document.fileName()
164 ]
165 self.msgBox = QMessageBox(self.mainDialog)
166
167 if not selectedDocuments:
168 self.msgBox.setText(i18n("Select one document."))
169 elif not self.directoryTextField.text():
170 self.msgBox.setText(i18n("Select the initial directory."))
171 else:
172 for doc in selectedDocuments:
173 self.export(doc)
174 self.msgBox.setText(i18n("All layers have been exported."))
175 self.msgBox.exec()
176
177 def mkdir(self, directory):
178 target_directory = self.directoryTextField.text() + directory
179 if (os.path.exists(target_directory)
180 and os.path.isdir(target_directory)):
181 return
182
183 try:
184 os.makedirs(target_directory)
185 except OSError as e:
186 raise e
187
188 def export(self, document):
189 Application.setBatchmode(self.batchmodeCheckBox.isChecked())
190
191 documentName = document.fileName() if document.fileName() else 'Untitled' # noqa: E501
192 fileName, extension = os.path.splitext(os.path.basename(documentName))
193 self.mkdir('/' + fileName)
194
195 self._exportLayers(
196 document.rootNode(),
197 self.formatsComboBox.currentText(),
198 '/' + fileName)
199 Application.setBatchmode(True)
200
201 def _exportLayers(self, parentNode, fileFormat, parentDir):
202 """ This method get all sub-nodes from the current node and export then in
203 the defined format."""
204 prefixNum = 0
205 for node in parentNode.childNodes():
206 newDir = ''
207 nodeName = node.name()
208 if self.addIncrementPrefixCheckBox.isChecked():
209 nodeName = str(prefixNum) + "-" + nodeName
210
211 if node.type() == 'grouplayer' and not self.groupAsLayer.isChecked():
212 newDir = os.path.join(parentDir, nodeName)
213 self.mkdir(newDir)
214 elif (not self.exportFilterLayersCheckBox.isChecked()
215 and 'filter' in node.type()):
216 continue
217 elif (self.ignoreInvisibleLayersCheckBox.isChecked()
218 and not node.visible()):
219 continue
220 else:
221 _fileFormat = self.formatsComboBox.currentText()
222 if '[jpeg]' in nodeName:
223 _fileFormat = 'jpeg'
224 elif '[png]' in nodeName:
225 _fileFormat = 'png'
226
227 if self.cropToImageBounds.isChecked():
228 bounds = QRect()
229 else:
230 bounds = QRect(0, 0, self.rectWidthSpinBox.value(), self.rectHeightSpinBox.value())
231
232 layerFileName = '{0}{1}/{2}.{3}'.format(
233 self.directoryTextField.text(),
234 parentDir, nodeName, _fileFormat)
235 node.save(layerFileName, self.resSpinBox.value() / 72.,
236 self.resSpinBox.value() / 72., InfoObject(), bounds)
237 prefixNum += 1
238 if node.childNodes() and not self.groupAsLayer.isChecked():
239 self._exportLayers(node, fileFormat, newDir)
240
241 def _selectDir(self):
243 self.mainDialog,
244 i18n("Select a Folder"),
245 os.path.expanduser("~"))
246 if directory:
247 self.directoryTextField.setText(directory)
248
249 def _setResolution(self, index):
250 document = self.documentsList[index]
251 self.rectWidthSpinBox.setValue(document.width())
252 self.rectHeightSpinBox.setValue(document.height())
253 self.resSpinBox.setValue(document.resolution())
254
256 cropToLayer = self.cropToImageBounds.isChecked()
257 self.rectWidthSpinBox.setDisabled(cropToLayer)
258 self.rectHeightSpinBox.setDisabled(cropToLayer)
float value(const T *src, size_t ch)
static QString getExistingDirectory(QWidget *parent=nullptr, const QString &caption=QString(), const QString &directory=QString(), const QString &dialogName=QString())
Create and show a file dialog and return the name of an existing directory selected by the user.
static Krita * instance()
instance retrieve the singleton instance of the Application object.
Definition Krita.cpp:390
_exportLayers(self, parentNode, fileFormat, parentDir)