欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

工具 - 分解TexturePacker导出的大图

发布时间:2023/12/3 编程问答 40 豆豆
生活随笔 收集整理的这篇文章主要介绍了 工具 - 分解TexturePacker导出的大图 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

 这是一个用于分解TexturePacker导出的大图的工具。

需要包含png图片和.plist文件

使用Python编写的,界面使用的是wxPython库写的。

以下是实现代码:

''' 功能: 分解TexturePacker制作的图集,要求包含plist文件和图片1.制作一个简单的界面来指定要分解的图集(plist文件和图片)1.提供选择plist文件2.提供选择图片文件3.提供保存路径选择 2.根据选择的文件做分解操作1.读取plist文件,并解析2.根据解析出来的数据对图集进行裁剪,并生成新的图片3.将图片保存到指定文件夹中参考: 1.wxpython教程1:https://blog.csdn.net/xufive/article/details/82665460?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166532024216782388061584%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166532024216782388061584&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~top_positive~default-1-82665460-null-null.nonecase&utm_term=wxpython&spm=1018.2226.3001.4450 2.wxpython教程2:https://edu.csdn.net/skill/python/python-3-176?category=9&typeId=17490 3.wxpython教程 - 事件:https://blog.csdn.net/weixin_42161954/article/details/109302843?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-109302843-blog-113688944.pc_relevant_3mothn_strategy_recovery&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-109302843-blog-113688944.pc_relevant_3mothn_strategy_recovery&utm_relevant_index=5 4.Python中的Partial函数(偏函数):https://edu.csdn.net/skill/python/python-3-176?category=9&typeId=17490#41__429 5.wxpython教程Wiki:https://wiki.wxpython.org/Passing%20Arguments%20to%20Callbacks 6.with open() 结构:https://blog.csdn.net/m0_48936146/article/details/124360734 7.plist文件解析plistlib:https://www.osgeo.cn/cpython/library/plistlib.html 8.python打包exe:https://blog.csdn.net/m0_64355682/article/details/125043126 8.python打包exe:https://www.cnblogs.com/strides/p/16422602.html '''from email.mime import image from functools import partial from PIL import Image import wx import os import plistlibAPP_TITLE = "TexturePacker分解工具" APP_ICON = "" SPLITY_TYPE = "COCOS"# 这里是窗口类 class MainFrame(wx.Frame):__plistPath = None__imgPath = None__savePath = None__saveDir = None# 分解类型,根据TexturePacker导出的引擎定义对于的函数, 注意这里的函数名不能加上前面下划线,否则无法调用__splitFuncDict = {'COCOS':'SplitImage_Cocos',}# 初始化窗口显示界面def __init__(self):'''初始化,这里使用默认的样式默认style是下列项的组合:wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN 但是不需要改变窗口的大小,所以加上 ^ wx.RESIZE_BORDER'''wx.Frame.__init__(self, None, style = wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)# 设置标题,背景色,大小,居中显示self.SetTitle(APP_TITLE)self.SetBackgroundColour(wx.Colour(224, 224, 224))self.SetSize((450, 220))self.Center()# 创建一个Panel,存放控件panel = wx.Panel(self)# plist文件获取# 固定文本显示:label:文本内容,pos:在panel内的位置(x, y)wx.StaticText(panel, label = "Plist文件:", pos = (20, 20))# 文本框,size:控件大小(w, h),-1表示默认大小self.plistTxtBox = wx.TextCtrl(panel, pos = (80, 20), size = (250, -1))# 按钮plistBtn = wx.Button(panel, label = "获取", pos = (340, 20))# 绑定点击事件,使用控件的Bind接口(事件类型,回调函数,对象),partial接口用于给回调事件中传入额外的参数,可以用于判断是哪个按钮的回调plistBtn.Bind(wx.EVT_BUTTON, partial(self.OnSelectBtnClick, bPlist = True))# 图片获取wx.StaticText(panel, label = "图片文件:", pos = (20, 60))self.imgTxtBox = wx.TextCtrl(panel, pos = (80, 60), size = (250, -1))imgBtn = wx.Button(panel, label = "获取", pos = (340, 60))imgBtn.Bind(wx.EVT_BUTTON, partial(self.OnSelectBtnClick, bPlist = False))# 分解保存路径wx.StaticText(panel, label = "保存地址:", pos = (20, 100))self.saveTxtBox = wx.TextCtrl(panel, pos = (80, 100), size = (250, -1))saveBtn = wx.Button(panel, label = "保存", pos = (340, 100))saveBtn.Bind(wx.EVT_BUTTON, self.OnSaveBtnClick, saveBtn)# 分解图片splitBtn = wx.Button(panel, label = "分解", pos = (50, 140))splitBtn.Bind(wx.EVT_BUTTON, self.OnSplitBtnClick, splitBtn)# 选择文件路径按钮点击事件,用于获取Plist、png文件路径def OnSelectBtnClick(self, evt, bPlist):fileWildCard = "" # 筛选文件类型:描述|*.后缀|下一组...titleTips = "" # 文件浏览器的标题if bPlist :fileWildCard = "Plist files(*.plist)|*.plist|All files(*.*)|*.*" titleTips = "请选择plist文件"else:fileWildCard = "PNG files(*.png)|*.png|All files(*.*)|*.*" titleTips = "请选择图片文件"# 通过 wx.FileDialog 打开文件浏览器,并选择对应的文件, defaultDir:起始路径fd = wx.FileDialog(self, titleTips, defaultDir = os.getcwd(), wildcard = fileWildCard) # 用户确认后的操作,这一步必须写上,不然弹窗无法正常打开,如果用户取消则该值 = wx.ID_CANCELif fd.ShowModal() == wx.ID_OK :filePath = fd.GetPath()os.chdir(os.path.dirname(filePath))if bPlist :self.__plistPath = filePathself.plistTxtBox.write(self.__plistPath)else:self.__imgPath = filePathself.imgTxtBox.write(self.__imgPath) # 用完就关了fd.Destroy()# 保存路径按钮点击事件def OnSaveBtnClick(self, evt):fd = wx.DirDialog(self, "请选择保存文件夹", defaultPath = os.getcwd())if fd.ShowModal() == wx.ID_OK :self.__savePath = fd.GetPath()self.saveTxtBox.write(self.__savePath)fd.Destroy()# 分解按钮点击事件def OnSplitBtnClick(self, evt):if self.__plistPath == None or not os.path.exists(self.__plistPath) :wx.MessageBox("请指定有效的Plist文件!", "警告", style = wx.OK)returnif self.__imgPath == None or not os.path.exists(self.__imgPath) :wx.MessageBox("请指定有效的图片文件!", "警告", style = wx.OK)returnif self.__savePath == None or not os.path.exists(self.__savePath) :wx.MessageBox("请指定有效的保存路径!", "警告", style = wx.OK)return'''1.读取plist文件内容,并转换为python数据结构2.遍历碎图数据,对大图进行裁剪3.将小图生成到指定的路径'''self.__InitPlistData()# 初始化Plist文件数据def __InitPlistData(self):funcStr = self.__splitFuncDict.get(SPLITY_TYPE, 'Defuault')if funcStr == 'Defuault' :wx.MessageBox(f"没有{SPLITY_TYPE}对应的分解处理接口", "警告", style = wx.OK)return'''with open(文件路径,打开方式:r只读/w只写/a追加) as 文件对象r: 以只读方式打开文件。文件的指针将会放在文件的开头。这是**默认模式**。rb: 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。r+: 打开一个文件用于读写。文件指针将会放在文件的开头。rb+:以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。w: 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb: 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。w+: 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。wb+:以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。a: 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。ab: 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。a+: 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。ab+:以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。'''with open(self.__plistPath, "rb") as fp:# 解析Plist文件plistDict = plistlib.load(fp)if plistDict == None :wx.MessageBox("Plist解析失败", "错误", style = wx.OK)return# 获取图片名称,并根据图片名称创建文件夹存储小图imgName = plistDict['metadata']['realTextureFileName']self.__saveDir = os.path.join(self.__savePath, imgName.replace(".png", "")) # 把后缀去掉,然后组合一下碎图的保存路径if not os.path.isdir(self.__saveDir) : # 判断有没有该目录,没有就创建os.mkdir(self.__saveDir) # 创建目录# 打开图片对象srcImage = Image.open(self.__imgPath)# 开始分解,getattr(self, xxx):相当于 self.xxxfunc = getattr(self, funcStr)func(plistDict['frames'], srcImage)# Cocos版本的分解接口def SplitImage_Cocos(self, imgsDic, srcImage):'''大图中的原点是在左上角,右为x正轴,下为y正轴frame:小图在大图中的位置大小(这里是经过Trim去掉空白之后的):{x,y},{w,h}offset:小图经过Trim之后的中心点与原小图的中心点的偏移值,注意这里的坐标系是:右为x正轴,上为y正轴rotated:是否旋转了90°sourceColorRect:原小图经过Trim之后在原图中的位置大小:{x,y},{w,h}sourceSize:原图大小'''# 将json格式的数据转换成数组json2List = lambda x : x.replace('{', '').replace('}', '').split(',')for key, value in imgsDic.items() :# 获取裁剪的位置大小:[x,y,w,h]cutRect = []valueFrame = json2List(value['frame'])frameList = [int(valueFrame[0]), int(valueFrame[1]), int(valueFrame[2]), int(valueFrame[3])]if value['rotated'] == True :cutRect = [frameList[0], frameList[1], frameList[0] + frameList[3], frameList[1] + frameList[2],]else:cutRect = [frameList[0], frameList[1], frameList[0] + frameList[2], frameList[1] + frameList[3],]# 原始的图片大小[w,h]valueSourceSize = json2List(value['sourceSize'])sourceSizeList = [int(valueSourceSize[0]), int(valueSourceSize[1])]# 获取偏移值: [x,y]'''首先大图里的小图是有可能对原图裁剪后的,所以如果要放回原图中的话,需要用(原图的大小 - 裁剪后的图的大小)/ 2,得到一个偏移值小图在原图的位置应该从原点(0,0),即左上角做一个偏移再加上中心点的偏移值就是最终的位置,注意这里因为坐标系问题,y轴应该是减法宽高 = 位置 + 大小'''valueOffset = json2List(value['offset'])offsetList = [int(valueOffset[0]), int(valueOffset[1])]adjust_x = int((sourceSizeList[0] - frameList[2]) / 2)adjust_y = int((sourceSizeList[1] - frameList[3]) / 2)order_x = adjust_x + offsetList[0]order_y = adjust_y - offsetList[1]orderRect = [order_x, order_y, order_x + frameList[2], order_y + frameList[3],]# 存储位置subImgPath = ""if key.endswith('.png') :subImgPath = os.path.join(self.__saveDir, key)else:subImgPath = os.path.join(self.__saveDir, key + ".png")self.GenerateImage(srcImage, cutRect, orderRect, subImgPath)# 创建小图并保存def GenerateImage(self, srcImage, cutRect, orderRect, orderPath):subImage = srcImage.crop(cutRect)orderImage = Image.new("RGBA", [orderRect[2], orderRect[3]])orderImage.paste(subImage, orderRect)orderImage.save(orderPath)# 这里是程序类 class MainApp(wx.App):def OnInit(self):self.SetAppName(APP_TITLE)self.frame = MainFrame()self.frame.Show()return True# 启动应用程序 if __name__ == "__main__":app = MainApp()app.MainLoop()

本人新学Python,有什么不对的地方,欢迎各位大佬指正~~ 

总结

以上是生活随笔为你收集整理的工具 - 分解TexturePacker导出的大图的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。