File indexing completed on 2024-05-12 05:46:37
0001 """ 0002 GDQuest Batch Exporter 0003 ----------------- 0004 Batch export art assets from Krita using layer metadata. 0005 Updates and reads metadata in Krita's layer names, and uses it to smartly process and export layers. 0006 Export to the Blender Cut-Out Animation tools for modular 2d game animation. 0007 Licensed under the GNU GPL v3.0 terms 0008 """ 0009 0010 from functools import partial 0011 from krita import DockWidget, DockWidgetFactory, DockWidgetFactoryBase, Krita 0012 from PyQt5.QtWidgets import ( 0013 QPushButton, 0014 QStatusBar, 0015 QLabel, 0016 QLineEdit, 0017 QHBoxLayout, 0018 QVBoxLayout, 0019 QGroupBox, 0020 QWidget, 0021 ) 0022 import os 0023 from .Config import CONFIG 0024 from .Infrastructure import WNode 0025 from .COATools import COAToolsFormat 0026 from .Utils import kickstart, flip 0027 from .Utils.Tree import iterPre 0028 0029 KI = Krita.instance() 0030 0031 0032 def ensureRGBAU8(doc): 0033 ensured = doc.colorModel() == "RGBA" and doc.colorDepth() == "U8" 0034 if not ensured: 0035 raise ValueError("only RGBA 8-bit depth supported!") 0036 0037 0038 def exportAllLayers(cfg, statusBar): 0039 msg, timeout = (cfg["done"]["msg"].format("Exported all layers."), cfg["done"]["timeout"]) 0040 try: 0041 doc = KI.activeDocument() 0042 0043 root = doc.rootNode() 0044 root = WNode(cfg, root) 0045 0046 dirName = os.path.dirname(doc.fileName()) 0047 it = filter(lambda n: n.isExportable() and n.isMarked(), iterPre(root)) 0048 it = map(partial(flip(WNode.save), dirName), it) 0049 kickstart(it) 0050 except ValueError as e: 0051 msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"] 0052 statusBar.showMessage(msg, timeout) 0053 0054 0055 def exportSelectedLayers(cfg, statusBar): 0056 msg, timeout = (cfg["done"]["msg"].format("Exported selected layers."), cfg["done"]["timeout"]) 0057 try: 0058 doc = KI.activeDocument() 0059 0060 dirName = os.path.dirname(doc.fileName()) 0061 nodes = KI.activeWindow().activeView().selectedNodes() 0062 it = map(partial(WNode, cfg), nodes) 0063 it = map(partial(flip(WNode.save), dirName), it) 0064 kickstart(it) 0065 except ValueError as e: 0066 msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"] 0067 statusBar.showMessage(msg, timeout) 0068 0069 0070 def exportCOATools(mode, cfg, statusBar): 0071 msg, timeout = ( 0072 cfg["done"]["msg"].format("Exported %s layers to COA Tools format." % (mode)), 0073 cfg["done"]["timeout"], 0074 ) 0075 try: 0076 doc = KI.activeDocument() 0077 ensureRGBAU8(doc) 0078 0079 coat_format = COAToolsFormat(cfg, statusBar) 0080 dirName = os.path.dirname(doc.fileName()) 0081 nodes = KI.activeWindow().activeView().selectedNodes() 0082 0083 # If mode is document or no nodes are selected, use document root 0084 if mode == "document" or len(nodes) == 0: 0085 nodes = [doc.rootNode()] 0086 0087 it = map(partial(WNode, cfg), nodes) 0088 # By convention all selected nodes should be Group Layers 0089 # This is to represent a logical root for each export in COATools format 0090 it = filter(lambda n: n.isGroupLayer(), it) 0091 it = map(coat_format.collect, it) 0092 kickstart(it) 0093 coat_format.save(dirName) 0094 0095 except ValueError as e: 0096 msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"] 0097 statusBar.showMessage(msg, timeout) 0098 0099 0100 def renameLayers(cfg, statusBar, lineEdit): 0101 msg, timeout = (cfg["done"]["msg"].format("Renaming successful!"), cfg["done"]["timeout"]) 0102 try: 0103 nodes = KI.activeWindow().activeView().selectedNodes() 0104 it = map(partial(WNode, cfg), nodes) 0105 it = map(partial(flip(WNode.rename), lineEdit.text()), it) 0106 kickstart(it) 0107 except ValueError as e: 0108 msg, timeout = cfg["error"]["msg"].format(e), cfg["error"]["timeout"] 0109 statusBar.showMessage(msg, timeout) 0110 0111 0112 class GameArtTools(DockWidget): 0113 title = "Batch Exporter" 0114 0115 def __init__(self): 0116 super().__init__() 0117 KI.setBatchmode(True) 0118 self.setWindowTitle(self.title) 0119 self.createInterface() 0120 0121 def createInterface(self): 0122 uiContainer = QWidget(self) 0123 0124 exportLabel = QLabel("Export") 0125 exportAllLayersButton = QPushButton("All Layers") 0126 exportSelectedLayersButton = QPushButton("Selected Layers") 0127 renameLabel = QLabel("Update Name and Metadata") 0128 renameLineEdit = QLineEdit() 0129 renameButton = QPushButton("Update") 0130 statusBar = QStatusBar() 0131 0132 exportLabel.setToolTip("Export individual images") 0133 exportAllLayersButton.setToolTip("Export all layers with metadata") 0134 exportSelectedLayersButton.setToolTip("Export selected layers only") 0135 renameButton.setToolTip("Batch update selected layer names and metadata") 0136 0137 # COA Tools GroupBox 0138 coaToolsGroupBox = QGroupBox("COA Tools") 0139 coaToolsHBoxLayout = QHBoxLayout() 0140 coaToolsExportSelectedLayersButton = QPushButton("Selected Layers") 0141 coaToolsExportDocumentButton = QPushButton("Document") 0142 0143 coaToolsGroupBox.setToolTip("Blender Cut-Out Animation Tools") 0144 coaToolsExportSelectedLayersButton.setToolTip("Export selected layers only") 0145 coaToolsExportDocumentButton.setToolTip("Export all layers with metadata") 0146 0147 coaToolsHBoxLayout.addWidget(coaToolsExportDocumentButton) 0148 coaToolsHBoxLayout.addWidget(coaToolsExportSelectedLayersButton) 0149 coaToolsGroupBox.setLayout(coaToolsHBoxLayout) 0150 0151 vboxlayout = QVBoxLayout() 0152 vboxlayout.addWidget(exportLabel) 0153 vboxlayout.addWidget(exportAllLayersButton) 0154 vboxlayout.addWidget(exportSelectedLayersButton) 0155 0156 vboxlayout.addWidget(coaToolsGroupBox) 0157 vboxlayout.addWidget(renameLabel) 0158 vboxlayout.addWidget(renameLineEdit) 0159 0160 hboxlayout = QHBoxLayout() 0161 hboxlayout.addStretch() 0162 hboxlayout.addWidget(renameButton) 0163 0164 vboxlayout.addLayout(hboxlayout) 0165 vboxlayout.addStretch() 0166 vboxlayout.addWidget(statusBar) 0167 0168 uiContainer.setLayout(vboxlayout) 0169 self.setWidget(uiContainer) 0170 0171 exportSelectedLayersButton.released.connect( 0172 partial(exportSelectedLayers, CONFIG, statusBar) 0173 ) 0174 exportAllLayersButton.released.connect(partial(exportAllLayers, CONFIG, statusBar)) 0175 coaToolsExportSelectedLayersButton.released.connect( 0176 partial(exportCOATools, "selected", CONFIG, statusBar) 0177 ) 0178 coaToolsExportDocumentButton.released.connect( 0179 partial(exportCOATools, "document", CONFIG, statusBar) 0180 ) 0181 renameLineEdit.returnPressed.connect( 0182 partial(renameLayers, CONFIG, statusBar, renameLineEdit) 0183 ) 0184 renameButton.released.connect(partial(renameLayers, CONFIG, statusBar, renameLineEdit)) 0185 0186 def canvasChanged(self, canvas): 0187 pass 0188 0189 0190 def registerDocker(): 0191 docker = DockWidgetFactory( 0192 "pykrita_gdquest_art_tools", DockWidgetFactoryBase.DockRight, GameArtTools 0193 ) 0194 KI.addDockWidgetFactory(docker)