File indexing completed on 2024-06-16 04:17:40
0001 # SPDX-License-Identifier: CC0-1.0 0002 0003 from . import exportlayersdialog 0004 from PyQt5.QtCore import (Qt, QRect) 0005 from PyQt5.QtWidgets import (QFormLayout, QListWidget, QHBoxLayout, 0006 QDialogButtonBox, QVBoxLayout, QFrame, 0007 QPushButton, QAbstractScrollArea, QLineEdit, 0008 QMessageBox, QFileDialog, QCheckBox, QSpinBox, 0009 QComboBox) 0010 import os 0011 import krita 0012 0013 0014 class UIExportLayers(object): 0015 0016 def __init__(self): 0017 self.mainDialog = exportlayersdialog.ExportLayersDialog() 0018 self.mainLayout = QVBoxLayout(self.mainDialog) 0019 self.formLayout = QFormLayout() 0020 self.resSpinBoxLayout = QFormLayout() 0021 self.documentLayout = QVBoxLayout() 0022 self.directorySelectorLayout = QHBoxLayout() 0023 self.optionsLayout = QVBoxLayout() 0024 self.rectSizeLayout = QHBoxLayout() 0025 0026 self.refreshButton = QPushButton(i18n("Refresh")) 0027 self.widgetDocuments = QListWidget() 0028 self.directoryTextField = QLineEdit() 0029 self.directoryDialogButton = QPushButton(i18n("...")) 0030 self.exportFilterLayersCheckBox = QCheckBox( 0031 i18n("Export filter layers")) 0032 self.batchmodeCheckBox = QCheckBox(i18n("Export in batchmode")) 0033 self.groupAsLayer = QCheckBox(i18n("Group as layer")) 0034 self.ignoreInvisibleLayersCheckBox = QCheckBox( 0035 i18n("Ignore invisible layers")) 0036 self.cropToImageBounds = QCheckBox( 0037 i18n("Adjust export size to layer content")) 0038 0039 self.rectWidthSpinBox = QSpinBox() 0040 self.rectHeightSpinBox = QSpinBox() 0041 self.formatsComboBox = QComboBox() 0042 self.resSpinBox = QSpinBox() 0043 0044 self.buttonBox = QDialogButtonBox( 0045 QDialogButtonBox.Ok | QDialogButtonBox.Cancel) 0046 0047 self.kritaInstance = krita.Krita.instance() 0048 self.documentsList = [] 0049 0050 self.directoryTextField.setReadOnly(True) 0051 self.batchmodeCheckBox.setChecked(True) 0052 self.directoryDialogButton.clicked.connect(self._selectDir) 0053 self.widgetDocuments.currentRowChanged.connect(self._setResolution) 0054 self.refreshButton.clicked.connect(self.refreshButtonClicked) 0055 self.buttonBox.accepted.connect(self.confirmButton) 0056 self.buttonBox.rejected.connect(self.mainDialog.close) 0057 self.cropToImageBounds.stateChanged.connect(self._toggleCropSize) 0058 0059 self.mainDialog.setWindowModality(Qt.NonModal) 0060 self.widgetDocuments.setSizeAdjustPolicy( 0061 QAbstractScrollArea.AdjustToContents) 0062 0063 def initialize(self): 0064 self.loadDocuments() 0065 0066 self.rectWidthSpinBox.setRange(1, 10000) 0067 self.rectHeightSpinBox.setRange(1, 10000) 0068 self.resSpinBox.setRange(20, 1200) 0069 0070 self.formatsComboBox.addItem(i18n("JPEG")) 0071 self.formatsComboBox.addItem(i18n("PNG")) 0072 0073 self.documentLayout.addWidget(self.widgetDocuments) 0074 self.documentLayout.addWidget(self.refreshButton) 0075 0076 self.directorySelectorLayout.addWidget(self.directoryTextField) 0077 self.directorySelectorLayout.addWidget(self.directoryDialogButton) 0078 0079 self.optionsLayout.addWidget(self.exportFilterLayersCheckBox) 0080 self.optionsLayout.addWidget(self.batchmodeCheckBox) 0081 self.optionsLayout.addWidget(self.groupAsLayer) 0082 self.optionsLayout.addWidget(self.ignoreInvisibleLayersCheckBox) 0083 self.optionsLayout.addWidget(self.cropToImageBounds) 0084 0085 self.resSpinBoxLayout.addRow(i18n("dpi:"), self.resSpinBox) 0086 0087 self.rectSizeLayout.addWidget(self.rectWidthSpinBox) 0088 self.rectSizeLayout.addWidget(self.rectHeightSpinBox) 0089 self.rectSizeLayout.addLayout(self.resSpinBoxLayout) 0090 0091 self.formLayout.addRow(i18n("Documents:"), self.documentLayout) 0092 self.formLayout.addRow( 0093 i18n("Initial directory:"), self.directorySelectorLayout) 0094 self.formLayout.addRow(i18n("Export options:"), self.optionsLayout) 0095 self.formLayout.addRow(i18n("Export size:"), self.rectSizeLayout) 0096 self.formLayout.addRow( 0097 i18n("Images extensions:"), self.formatsComboBox) 0098 0099 self.line = QFrame() 0100 self.line.setFrameShape(QFrame.HLine) 0101 self.line.setFrameShadow(QFrame.Sunken) 0102 0103 self.mainLayout.addLayout(self.formLayout) 0104 self.mainLayout.addWidget(self.line) 0105 self.mainLayout.addWidget(self.buttonBox) 0106 0107 self.mainDialog.resize(500, 300) 0108 self.mainDialog.setWindowTitle(i18n("Export Layers")) 0109 self.mainDialog.setSizeGripEnabled(True) 0110 self.mainDialog.show() 0111 self.mainDialog.activateWindow() 0112 0113 def loadDocuments(self): 0114 self.widgetDocuments.clear() 0115 0116 self.documentsList = [ 0117 document for document in self.kritaInstance.documents() 0118 if document.fileName() 0119 ] 0120 0121 for document in self.documentsList: 0122 self.widgetDocuments.addItem(document.fileName()) 0123 0124 def refreshButtonClicked(self): 0125 self.loadDocuments() 0126 0127 def confirmButton(self): 0128 selectedPaths = [ 0129 item.text() for item in self.widgetDocuments.selectedItems()] 0130 selectedDocuments = [ 0131 document for document in self.documentsList 0132 for path in selectedPaths if path == document.fileName() 0133 ] 0134 0135 self.msgBox = QMessageBox(self.mainDialog) 0136 if not selectedDocuments: 0137 self.msgBox.setText(i18n("Select one document.")) 0138 elif not self.directoryTextField.text(): 0139 self.msgBox.setText(i18n("Select the initial directory.")) 0140 else: 0141 self.export(selectedDocuments[0]) 0142 self.msgBox.setText(i18n("All layers have been exported.")) 0143 self.msgBox.exec_() 0144 0145 def mkdir(self, directory): 0146 target_directory = self.directoryTextField.text() + directory 0147 if (os.path.exists(target_directory) 0148 and os.path.isdir(target_directory)): 0149 return 0150 0151 try: 0152 os.makedirs(target_directory) 0153 except OSError as e: 0154 raise e 0155 0156 def export(self, document): 0157 Application.setBatchmode(self.batchmodeCheckBox.isChecked()) 0158 0159 documentName = document.fileName() if document.fileName() else 'Untitled' # noqa: E501 0160 fileName, extension = os.path.splitext(os.path.basename(documentName)) 0161 self.mkdir('/' + fileName) 0162 0163 self._exportLayers( 0164 document.rootNode(), 0165 self.formatsComboBox.currentText(), 0166 '/' + fileName) 0167 Application.setBatchmode(True) 0168 0169 def _exportLayers(self, parentNode, fileFormat, parentDir): 0170 """ This method get all sub-nodes from the current node and export then in 0171 the defined format.""" 0172 0173 for node in parentNode.childNodes(): 0174 newDir = '' 0175 if node.type() == 'grouplayer' and not self.groupAsLayer.isChecked(): 0176 newDir = os.path.join(parentDir, node.name()) 0177 self.mkdir(newDir) 0178 elif (not self.exportFilterLayersCheckBox.isChecked() 0179 and 'filter' in node.type()): 0180 continue 0181 elif (self.ignoreInvisibleLayersCheckBox.isChecked() 0182 and not node.visible()): 0183 continue 0184 else: 0185 nodeName = node.name() 0186 _fileFormat = self.formatsComboBox.currentText() 0187 if '[jpeg]' in nodeName: 0188 _fileFormat = 'jpeg' 0189 elif '[png]' in nodeName: 0190 _fileFormat = 'png' 0191 0192 if self.cropToImageBounds.isChecked(): 0193 bounds = QRect() 0194 else: 0195 bounds = QRect(0, 0, self.rectWidthSpinBox.value(), self.rectHeightSpinBox.value()) 0196 0197 layerFileName = '{0}{1}/{2}.{3}'.format( 0198 self.directoryTextField.text(), 0199 parentDir, node.name(), _fileFormat) 0200 node.save(layerFileName, self.resSpinBox.value() / 72., 0201 self.resSpinBox.value() / 72., krita.InfoObject(), bounds) 0202 0203 if node.childNodes() and not self.groupAsLayer.isChecked(): 0204 self._exportLayers(node, fileFormat, newDir) 0205 0206 def _selectDir(self): 0207 directory = QFileDialog.getExistingDirectory( 0208 self.mainDialog, 0209 i18n("Select a Folder"), 0210 os.path.expanduser("~"), 0211 QFileDialog.ShowDirsOnly) 0212 self.directoryTextField.setText(directory) 0213 0214 def _setResolution(self, index): 0215 document = self.documentsList[index] 0216 self.rectWidthSpinBox.setValue(document.width()) 0217 self.rectHeightSpinBox.setValue(document.height()) 0218 self.resSpinBox.setValue(document.resolution()) 0219 0220 def _toggleCropSize(self): 0221 cropToLayer = self.cropToImageBounds.isChecked() 0222 self.rectWidthSpinBox.setDisabled(cropToLayer) 0223 self.rectHeightSpinBox.setDisabled(cropToLayer)