def _export_layer(self, node, export_layer_path, active_doc): krita_app = Krita.instance() active_doc_bounds = active_doc.rootNode().bounds() # old versions of Krita had a different signature for this function # unfortunately since this function is not a python one we cannot # inspect it, so we do have to check the Krita version to know # how to approach this export if is_version_older(krita_app.version(), "4.2.0"): node.save(export_layer_path, active_doc.width(), active_doc.height()) else: node.save( export_layer_path, active_doc.width(), active_doc.height(), InfoObject(), active_doc_bounds, )
def export(self, exportDir, animName): doc = Krita.instance().activeDocument() if doc is not None: # record all frames with a keyframe frameCount = doc.animationLength() framesToExport = set([]) root = doc.rootNode() for node in root.childNodes(): if(node.animated() and node.visible()): for i in range(frameCount-1): if(node.hasKeyframeAtTime(i)): framesToExport.add(i) # export keyframes doc.setBatchmode(True) for frame in framesToExport: doc.setCurrentTime(frame) fileNum = "_" + str(frame).zfill(3) exportPath = Path(exportDir) exportPath = exportPath.joinpath(animName + fileNum + ".png") doc.exportImage(str(exportPath), InfoObject()) doc.setBatchmode(False)
def options(self, asInfoObject=False): """Return current options If `asInfoObject` is True, return a InfoObject otherwise a dictionary """ if asInfoObject: color=self.pbBgColor.color() returned=InfoObject() returned.setProperty('compression', self.hsCompressionLevel.value()) returned.setProperty('indexed', self.cbIndexed.isChecked()) returned.setProperty('interlaced', self.cbInterlacing.isChecked()) returned.setProperty('saveSRGBProfile', self.cbSaveICCProfile.isChecked()) returned.setProperty('forceSRGB', self.cbForceConvertsRGB.isChecked()) returned.setProperty('alpha', self.rbStoreAlpha.isChecked()) returned.setProperty('transparencyFillcolor', [color.red(), color.green(), color.blue()]) else: returned={ 'compression': self.hsCompressionLevel.value(), 'indexed': self.cbIndexed.isChecked(), 'interlaced': self.cbInterlacing.isChecked(), 'saveSRGBProfile': self.cbSaveICCProfile.isChecked(), 'forceSRGB': self.cbForceConvertsRGB.isChecked(), 'alpha': self.rbStoreAlpha.isChecked(), 'transparencyFillcolor': self.pbBgColor.color() } return returned
def options(self, asInfoObject=False): """Return current options If `asInfoObject` is True, return a InfoObject otherwise a dictionary """ if asInfoObject: color=self.pbBgColor.color() returned=InfoObject() returned.setProperty('quality', self.hsQuality.value()) returned.setProperty('smoothing', self.hsSmoothing.value()) returned.setProperty('subsampling', self.cbxSubsampling.currentIndex()) returned.setProperty('progressive', self.cbProgressive.isChecked()) returned.setProperty('optimize', self.cbOptimize.isChecked()) returned.setProperty('saveProfile', self.cbSaveICCProfile.isChecked()) returned.setProperty('transparencyFillcolor', [color.red(), color.green(), color.blue()]) else: returned={ 'quality': self.hsQuality.value(), 'smoothing': self.hsSmoothing.value(), 'subsampling': self.cbxSubsampling.currentIndex(), 'progressive': self.cbProgressive.isChecked(), 'optimize': self.cbOptimize.isChecked(), 'saveProfile': self.cbSaveICCProfile.isChecked(), 'transparencyFillcolor': self.pbBgColor.color() } return returned
from krita import (krita, InfoObject) import time myTime = time.strftime('%y%m%d_%H%M%S', time.localtime(time.time())) imagePath = str("G:/Projects/Python/2dgp/leegame/전기이태륜/" + myTime + ".png") doc = Krita.instance().activeDocument() doc.exportImage(imagePath, InfoObject())
def _export(self, node, directory, bone="root", xOffset=0, yOffset=0, slot=None): for child in node.childNodes(): if "selectionmask" in child.type(): continue if not child.visible(): continue if '(ignore)' in child.name(): continue if child.childNodes(): if not self.mergePattern.search(child.name()): newBone = bone newSlot = slot newX = xOffset newY = yOffset if self.bonePattern.search(child.name()): newBone = self.bonePattern.sub('', child.name()).strip() rect = child.bounds() newX = rect.left() + rect.width() / 2 - xOffset newY = (- rect.bottom() + rect.height() / 2) - yOffset self.spineBones.append({ 'name': newBone, 'parent': bone, 'x': newX, 'y': newY }) newX = xOffset + newX newY = yOffset + newY if self.slotPattern.search(child.name()): newSlotName = self.slotPattern.sub('', child.name()).strip() newSlot = { 'name': newSlotName, 'bone': bone, 'attachment': None, } self.spineSlots.append(newSlot) self._export(child, directory, newBone, newX, newY, newSlot) continue name = self.mergePattern.sub('', child.name()).strip() layerFileName = '{0}/{1}.{2}'.format(directory, name, self.fileFormat) child.save(layerFileName, 96, 96, InfoObject()) newSlot = slot if not newSlot: newSlot = { 'name': name, 'bone': bone, 'attachment': name, } self.spineSlots.append(newSlot) else: if not newSlot['attachment']: newSlot['attachment'] = name rect = child.bounds() slotName = newSlot['name'] if slotName not in self.spineDefaultSkin: self.spineDefaultSkin[slotName] = {} self.spineDefaultSkin[slotName][name] = { 'x': rect.left() + rect.width() / 2 - xOffset, 'y': (- rect.bottom() + rect.height() / 2) - yOffset, 'rotation': 0, 'width': rect.width(), 'height': rect.height(), }
def export(self, debugging=False): def debugPrint(message, usingTerminal=True): if usingTerminal: print(message) else: QMessageBox.information(QWidget(), i18n("Debug info: "), i18n(message)) def sheetExportPath(suffix=""): return self.exportDir.joinpath(self.exportName + suffix) def spritesExportPath(suffix=""): return self.spritesExportDir.joinpath(self.exportName + suffix) def fileNum(num): return "_" + str(num).zfill(3) if debugging: print("") debugPrint("Export spritesheet start.") addedFolder = False # create a temporary export directory for the individual sprites # if the user didn't set any if self.spritesExportDir == self.defaultPath: self.spritesExportDir = sheetExportPath("_sprites") if self.forceNew and self.spritesExportDir.exists(): exportNum = 0 parentPath = self.spritesExportDir.parent folder = str(self.spritesExportDir.parts[-1]) def exportCandidate(): return parentPath.joinpath(folder + str(exportNum)) # in case the user has a folder with the exact same name # as my temporary one while exportCandidate().exists(): exportNum += 1 self.spritesExportDir = exportCandidate() # if forceNew, spritesExportDir's value is taken # from the user-set choices in the dialog # this will always be called if not forceNew # because it will always create a new export folder if not (self.spritesExportDir).exists(): addedFolder = True (self.spritesExportDir).mkdir() # render animation in the sprites export folder doc = Krita.instance().activeDocument() # check self.end and self.start values # and if needed input default value if (self.end == 0 or self.start == 0): self.setStartEndFrames() # give default value to step if (self.step == 0): self.step = 1 doc.setCurrentTime(self.start) if (debugging): debugPrint("animation Length: " + str(doc.animationLength()) + "; full clip self.start: " + str(doc.fullClipRangeStartTime()) + "; full clip self.end: " + str(doc.fullClipRangeEndTime()) + "; export start: " + str(self.start) + "; export end: " + str(self.end) + "; export length: " + str(self.end - self.start)) framesNum = ((self.end + 1) - self.start) / self.step doc.setBatchmode(True) # so it won't show the export dialog window tmpNum = self.start while (doc.currentTime() <= self.end): doc.waitForDone() imagePath = str(spritesExportPath(fileNum(tmpNum) + ".png")) doc.exportImage(imagePath, InfoObject()) doc.setCurrentTime(doc.currentTime() + self.step) tmpNum += self.step # getting current document info # so we can copy it over to the new document width = doc.width() height = doc.height() col = doc.colorModel() depth = doc.colorDepth() profile = doc.colorProfile() res = doc.resolution() # debugPrint(dir(doc)) # getting a default value for rows and columns if (self.rows == 0) and (self.columns == 0): # square fit self.columns = ceil(sqrt(framesNum)) self.rows = ceil(float(framesNum) / self.columns) # or one row? # self.rows = 1 # self.columns = framesNum if (debugging): debugPrint("self.rows: " + str(self.rows) + "; self.columns: " + str(self.columns)) # if only one is specified, guess the other elif (self.rows == 0): self.rows = ceil(float(framesNum) / self.columns) # Though if I have to guess the number of columns, # it may also change the (user-set) number of rows. # For example, if you want ten rows from twelve sprites # instead of two rows of two and eight of one, # you'll have six rows of two elif (self.columns == 0): self.columns = ceil(float(framesNum) / self.rows) self.rows = ceil(float(framesNum) / self.columns) # creating a new document where we'll put our sprites sheet = Krita.instance().createDocument(self.columns * width, self.rows * height, self.exportName, col, depth, profile, res) if (debugging): debugPrint("new doc name: " + sheet.name()) debugPrint("old doc width: " + str(width)) debugPrint("num of frames: " + str(framesNum)) debugPrint("new doc width: " + str(sheet.width())) # for debugging when the result of print() is not available # QMessageBox.information(QWidget(), i18n("Debug 130"), # i18n("step: " + str(self.step) + # "; end: " + str(self.end) + # "; start: " + str(self.start) + # "; rows: " + str(self.rows) + # "; columns: " + str(self.columns) + # "; frames number: " + # str(framesNum))) # adding our sprites to the new document # and moving them to the right position imgNum = self.start root_node = sheet.rootNode() while (imgNum <= self.end): doc.waitForDone() img = str(spritesExportPath(fileNum(imgNum) + ".png")) layer = sheet.createFileLayer(img, img, "ImageToSize") root_node.addChildNode(layer, None) self.positionLayer(layer=layer, imgNum=((imgNum - self.start) / self.step), width=width, height=height) # I need to merge down each layer or they don't show layer.mergeDown() if self.removeTmp: # removing temporary sprites exports Path(img).unlink() if (debugging): debugPrint("adding to spritesheet, image " + str(imgNum - self.start) + " name: " + img + " at pos: " + str(layer.position())) imgNum += self.step # export the document to the export location sheet.setBatchmode(True) # so it won't show the export dialog window if debugging: debugPrint("exporting spritesheet to " + str(sheetExportPath())) sheet.exportImage(str(sheetExportPath(".png")), InfoObject()) # and remove the empty tmp folder when you're done if self.removeTmp: if addedFolder: self.spritesExportDir.rmdir() if debugging: debugPrint("All done!")
def exportFrame(num, doc, debugging=False): doc.waitForDone() imagePath = str(spritesExportPath(fileNum(num) + ".png")) doc.exportImage(imagePath, InfoObject()) if (debugging): debugPrint("exporting frame " + str(num) + " at " + imagePath)
def export(self, debugging=False): def debugPrint(message, usingTerminal=True): if usingTerminal: print(message) else: QMessageBox.information(QWidget(), i18n("Debug info: "), i18n(message)) def sheetExportPath(suffix=""): return self.exportDir.joinpath(self.exportName + suffix) def spritesExportPath(suffix=""): return self.spritesExportDir.joinpath(self.exportName + suffix) def fileNum(num): return "_" + str(num).zfill(3) def exportFrame(num, doc, debugging=False): doc.waitForDone() imagePath = str(spritesExportPath(fileNum(num) + ".png")) doc.exportImage(imagePath, InfoObject()) if (debugging): debugPrint("exporting frame " + str(num) + " at " + imagePath) def getLayerState(layer, debugging=False): if len(layer.childNodes()) != 0: # if it was a group layer # we also check its kids for kid in layer.childNodes(): getLayerState(kid, debugging) else: self.layersStates.append(layer.visible()) self.layersList.append(layer) if (not layer.visible()): self.offLayers += 1 if (debugging): debugPrint("saving state " + str(layer.visible()) + " of layer " + str(layer)) if debugging: print("") debugPrint("Export spritesheet start.") # clearing lists in case the script is used several times # without restarting krita self.layersList.clear() self.layersStates.clear() self.offLayers = 0 addedFolder = False # create a temporary export directory for the individual sprites # if the user didn't set any if self.spritesExportDir == self.defaultPath: self.spritesExportDir = sheetExportPath("_sprites") if self.forceNew and self.spritesExportDir.exists(): exportNum = 0 parentPath = self.spritesExportDir.parent folder = str(self.spritesExportDir.parts[-1]) def exportCandidate(): return parentPath.joinpath(folder + str(exportNum)) # in case the user has a folder with the exact same name # as my temporary one while exportCandidate().exists(): exportNum += 1 self.spritesExportDir = exportCandidate() # if forceNew, spritesExportDir's value is taken # from the user-set choices in the dialog # this will always be called if not forceNew # because it will always create a new export folder if not (self.spritesExportDir).exists(): addedFolder = True (self.spritesExportDir).mkdir() # render animation in the sprites export folder doc = Krita.instance().activeDocument() doc.setBatchmode(True) # so it won't show the export dialog window if (not self.layersAsAnimation): # check self.end and self.start values # and if needed input default value if (self.end == self.defaultTime or self.start == self.defaultTime): self.setStartEndFrames() doc.setCurrentTime(self.start) if (debugging): ver = Application.version() isNewVersion = (int(ver[0]) > 4 or (int(ver[0]) == 4 and int(ver[2]) >= 2)) if (isNewVersion): debugPrint("animation Length: " + str(doc.animationLength()) + "; full clip start: " + str(doc.fullClipRangeStartTime()) + "; full clip end: " + str(doc.fullClipRangeEndTime())) debugPrint("export start: " + str(self.start) + "; export end: " + str(self.end) + "; export length: " + str(self.end - self.start)) framesNum = ((self.end + 1) - self.start) / self.step frameIDNum = self.start # export frames while (doc.currentTime() <= self.end): exportFrame(frameIDNum, doc, debugging) frameIDNum += self.step doc.setCurrentTime(frameIDNum) # reset frameIDNum = self.start else: frameIDNum = 0 # save layers state (visible or not) layers = doc.topLevelNodes() for layer in layers: getLayerState(layer, debugging) framesNum = len(self.layersList) # for compatibility between animated frames as frames # and layers as frames self.start = 0 self.end = len(self.layersList) - 1 # hide all layers for layer in self.layersList: layer.setVisible(False) # export each visible layer while (frameIDNum < len(self.layersStates)): if (self.layersStates[frameIDNum]): self.layersList[frameIDNum].setVisible(True) # refresh the canvas doc.refreshProjection() exportFrame(frameIDNum, doc, debugging) self.layersList[frameIDNum].setVisible(False) frameIDNum += self.step # for layer in self.layersStates: # if (layersStates[layersList.index(layer)]): # layer.setVisible(True) # exportFrame(frameIDNum, doc) # layer.setVisible(False) # frameIDNum += self.step # restore layers state frameIDNum = 0 while (frameIDNum < len(self.layersStates)): self.layersList[frameIDNum].setVisible( self.layersStates[frameIDNum]) frameIDNum += 1 if (debugging): debugPrint("restoring layer " + str(frameIDNum)) frameIDNum = 0 # getting current document info # so we can copy it over to the new document width = doc.width() height = doc.height() col = doc.colorModel() depth = doc.colorDepth() profile = doc.colorProfile() res = doc.resolution() # this is very helpful while programming # if you're not quite sure what can be done: # debugPrint(dir(doc)) # getting a default value for rows and columns if (self.rows == self.defaultSpace) and (self.columns == self.defaultSpace): # square fit self.columns = ceil(sqrt(framesNum - self.offLayers)) self.rows = ceil(float(framesNum - self.offLayers) / self.columns) # or one row? # self.rows = 1 # self.columns = framesNum if (debugging): debugPrint("self.rows: " + str(self.rows) + "; self.columns: " + str(self.columns)) # if only one is specified, guess the other elif (self.rows == self.defaultSpace): self.rows = ceil(float(framesNum - self.offLayers) / self.columns) # Though if I have to guess the number of columns, # it may also change the (user-set) number of rows. # For example, if you want ten rows from twelve sprites # instead of two rows of two and eight of one, # you'll have six rows of two elif (self.columns == self.defaultSpace): self.columns = ceil(float(framesNum - self.offLayers) / self.rows) self.rows = ceil(float(framesNum - self.offLayers) / self.columns) # creating a new document where we'll put our sprites sheet = Krita.instance().createDocument(self.columns * width, self.rows * height, self.exportName, col, depth, profile, res) if (debugging): debugPrint("new doc name: " + sheet.name()) debugPrint("old doc width: " + str(width)) debugPrint("num of frames: " + str(framesNum)) debugPrint("new doc width: " + str(sheet.width())) # for debugging when the result of print() is not available # QMessageBox.information(QWidget(), i18n("Debug 130"), # i18n("step: " + str(self.step) + # "; end: " + str(self.end) + # "; start: " + str(self.start) + # "; rows: " + str(self.rows) + # "; columns: " + str(self.columns) + # "; frames number: " + # str(framesNum))) # adding our sprites to the new document # and moving them to the right position root_node = sheet.rootNode() invisibleLayersNum = 0 while (frameIDNum <= self.end): doc.waitForDone() if (not self.layersAsAnimation or (self.layersAsAnimation and self.layersStates[frameIDNum])): img = str(spritesExportPath(fileNum(frameIDNum) + ".png")) if (debugging): debugPrint("managing file " + str(frameIDNum) + " at " + img) layer = sheet.createFileLayer(img, img, "ImageToSize") root_node.addChildNode(layer, None) self.positionLayer( layer=layer, imgNum=(((frameIDNum - invisibleLayersNum) - self.start) / self.step), width=width, height=height) # refresh canvas so the layers actually do show sheet.refreshProjection() if self.removeTmp: # removing temporary sprites exports Path(img).unlink() if (debugging): debugPrint("adding to spritesheet, image " + str(frameIDNum - self.start) + " name: " + img + " at pos: " + str(layer.position())) else: invisibleLayersNum += 1 frameIDNum += self.step # export the document to the export location sheet.setBatchmode(True) # so it won't show the export dialog window if debugging: debugPrint("exporting spritesheet to " + str(sheetExportPath())) sheet.exportImage(str(sheetExportPath(".png")), InfoObject()) # and remove the empty tmp folder when you're done if self.removeTmp: if addedFolder: self.spritesExportDir.rmdir() if debugging: debugPrint("All done!")
def _export(self, node, directory, bone="root", xOffset=0, yOffset=0, slot=None, skin="default"): for child in node.childNodes(): if "selectionmask" in child.type(): continue if not child.visible(): continue if '(ignore)' in child.name(): continue if child.childNodes(): if not self.mergePattern.search(child.name()): newSkin = skin newBone = bone newSlot = slot newX = xOffset newY = yOffset if self.bonePattern.search(child.name()): newBone = self.bonePattern.sub('', child.name()).strip() rect = child.bounds() newX = rect.left() + rect.width() / 2 - xOffset newY = (- rect.bottom() + rect.height() / 2) - yOffset newBoneDict = { 'name': newBone, 'parent': bone, 'x': newX, 'y': newY } # if newSkin != 'default': # newBoneDict['skin'] = True if self.isBoneExist(newBone) == False: self.spineBones.append(newBoneDict) newX = xOffset + newX newY = yOffset + newY else: c_bone = self.getBone(newBone) newX = xOffset + c_bone['x'] newY = yOffset + c_bone['y'] if self.slotPattern.search(child.name()): newSlotName = self.slotPattern.sub('', child.name()).strip() newSlot = { 'name': newSlotName, 'bone': bone, 'attachment': None, } if self.isSlotExist(newSlotName) == False: self.spineSlots.append(newSlot) if self.skinPattern.search(child.name()): newSkin = self.skinPattern.sub('', child.name()).strip() self.spineSkins.append({ 'name': newSkin, 'attachments':{} }) self.createDirectoy(newSkin) self._export(child, directory, newBone, newX, newY, newSlot, newSkin) continue saveDir = directory if skin != "default": saveDir = directory+"/"+skin name = self.mergePattern.sub('', child.name()).strip() layerFileName = '{0}/{1}.{2}'.format(saveDir, name, self.fileFormat) child.save(layerFileName, 96, 96, InfoObject()) newSlot = slot if not newSlot: newSlot = { 'name': name, 'bone': bone, 'attachment': name, } if self.isSlotExist(name) == False: self.spineSlots.append(newSlot) else: if not newSlot['attachment']: newSlot['attachment'] = name rect = child.bounds() slotName = newSlot['name'] skinDict = self.getSkin(skin) nameDir = "" if skin != "default": nameDir = skin+"/" if slotName not in skinDict['attachments']: skinDict['attachments'][slotName] = {} skinDict['attachments'][slotName][name] = { 'name': nameDir+name, 'x': rect.left() + rect.width() / 2 - xOffset, 'y': (- rect.bottom() + rect.height() / 2) - yOffset, 'rotation': 0, 'width': rect.width(), 'height': rect.height(), }
def setUp(self): self._instance = InfoObject()
class TestInfoObject(unittest.TestCase): def setUp(self): self._instance = InfoObject() def testConstructor(self): self.assertTrue(InfoObject()) def testConstructorWithParent(self): self.assertTrue(InfoObject(QObject())) def testConstructorInvalidParameter(self): with self.assertRaises(TypeError): InfoObject(str('')) def testEqualOperator(self): sameInfoObject = self._instance self.assertTrue(sameInfoObject == self._instance) def testInequalityOperator(self): newInfoObject = InfoObject() self.assertTrue(newInfoObject != self._instance) def testPropertiesAcessorsOneProperty(self): self._instance.setProperties({"test": "test"}) self.assertEqual(self._instance.properties(), {"test": "test"}) def testPropertiesAcessorsSetProperties(self): self._instance.setProperties({"test": "test", "test1": 1}) self.assertEqual(self._instance.properties(), {"test": "test", "test1": 1}) def testPropertySlotsString(self): self._instance.setProperty("key", "value") self.assertEqual(self._instance.property("key"), "value") def testPropertySlotsInvalidKey(self): self._instance.setProperty("key", "value") self.assertEqual(self._instance.property("keys"), None)
def testInequalityOperator(self): newInfoObject = InfoObject() self.assertTrue(newInfoObject != self._instance)
def testConstructorInvalidParameter(self): with self.assertRaises(TypeError): InfoObject(str(''))
def testConstructorWithParent(self): self.assertTrue(InfoObject(QObject()))
def testConstructor(self): self.assertTrue(InfoObject())