提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、为什么需要图集打包?
  • 二、使用python批量拆解plist格式文件
    • 1.引入库
    • 2.具体实现代码
  • 三、使用python批量拆解laya引擎图集文件
  • 四、使用python批量拆解Egret引擎图集文件
  • 附Gitee传送地址
  • Creator拆图工具
  • 总结

前言

因为学习需要制作游戏,经常会在网上寻找一些资源进行学习,而一般资源分积分下载源资源或者线上扒取别人的图集资源。所以很多时候需要对一张合集图进行拆分,今天主要讲解有描述文件的图集拆分。
我常接触的图集格式一般是
CocosCreator TexturePacker .plst 格式的图集
LayaBox .json ,atlas引擎自带贴图合集格式
Egret 引擎的.json图集格式


一、为什么需要图集打包?

做过游戏开发的童靴都知道纹理打包,用于下载节约流量减少io操作。也能让渲染合批提升性能。市面上常用打包工具TexturePacker,还有一些引擎自带图集打包的工具。

二、使用python批量拆解plist格式文件

1.引入库

代码如下(示例):
Python库主要依赖PIL下Image模板对图片的操作

import os,sys
from xml.etree import ElementTree
from PIL import Image
reload(sys)
sys.setdefaultencoding('utf8')

2.具体实现代码

代码如下(示例):

#!python
# coding: utf-8
import os,sys
from xml.etree import ElementTree
from PIL import Image
reload(sys)
sys.setdefaultencoding('utf8')def tree_to_dict(tree):d = {}for index, item in enumerate(tree):if item.tag == 'key':if tree[index+1].tag == 'string':d[item.text] = tree[index + 1].textelif tree[index + 1].tag == 'true':d[item.text] = Trueelif tree[index + 1].tag == 'false':d[item.text] = Falseelif tree[index + 1].tag == 'integer':d[item.text] = int(tree[index + 1].text) elif tree[index+1].tag == 'dict':d[item.text] = tree_to_dict(tree[index+1])return d def read_rect(dict):return [dict['x'],dict['y'],dict['width'],dict['height']];def gen_png_from_plist(filename, outPath):plist_filename = filename + '.plist'png_filename = filename + '.png' if checkPath(plist_filename) == False or checkPath(png_filename) ==False:print("don't find %s png  or plist"%filename)return#获取大图big_image = Image.open(png_filename)#读取plistroot = ElementTree.fromstring(open(plist_filename, 'r').read())plist_dict = tree_to_dict(root[0])to_list = lambda x: x.replace('{','').replace('}','').split(',')to_int = lambda x:int(x)for k,v in plist_dict['frames'].items():if v.has_key('textureRect'):textureRect = to_list(v['textureRect'])elif v.has_key('frame'):textureRect = to_list(v['frame'])else:textureRect = read_rect(v)#获得图像尺寸if v.has_key('spriteSize'):spriteSize = v['spriteSize']elif v.has_key('sourceSize'):spriteSize = v['sourceSize']elif v.has_key('spriteSourceSize'):spriteSize = v['spriteSourceSize']elif v.has_key("width"):spriteSize = str(v['width']) + ',' +  str(v['height'])spriteSize = to_list(spriteSize)spriteSize = map(to_int, spriteSize) result_box = textureRect#防止宽高小于0导致错误if spriteSize[0] <= 0 or spriteSize[1]<0 :print "< 0"continueresult_image = Image.new('RGBA', spriteSize, (0,0,0,0))if (v.has_key('textureRotated') and v['textureRotated']) or (v.has_key('rotated') and v['rotated']): result_box[0] = int(textureRect[0])result_box[1] = int(textureRect[1])result_box[2] = int(textureRect[0] + spriteSize[1])result_box[3] = int(textureRect[1] + spriteSize[0])else:result_box[0] = int(textureRect[0])result_box[1] = int(textureRect[1])result_box[2] = int(textureRect[0] + spriteSize[0])result_box[3] = int(textureRect[1] + spriteSize[1])#获得小图rect_on_big = big_image.crop(result_box)# 有旋转if (v.has_key('textureRotated') and v['textureRotated']) or (v.has_key('rotated') and v['rotated']):rect_on_big = rect_on_big.transpose(Image.ROTATE_90)result_image.paste(rect_on_big) if not os.path.isdir(outPath):os.mkdir(outPath)k = k.replace('/', '_')outfile = (outPath+'/' + k).replace('gift_', '')#print kif outfile.find('.png') == -1:outfile = outfile + '.png'print outfile, "generated"result_image.save(outfile)def read_dir( path, outPath):for name in os.listdir( path ): if os.path.isdir( os.path.join(path, name) ): find_file(os.path.join(path, name),outPath )else:portion = os.path.splitext(name)if portion[1] == '.plist':fileName = os.path.join(path, portion[0])outDir = os.path.join(outPath, portion[0]); gen_png_from_plist(fileName , outDir)def checkPath(path):if not os.path.exists( path ):print "not find 1 %s"%pathreturn Falsereturn Trueif __name__ == '__main__': if len( sys.argv ) < 2:dirName = raw_input("Enter your DirName: ")else:dirName = sys.argv[1]if len( sys.argv ) < 3:outPath = raw_input("Enter your outPath: ")else:outPath = sys.argv[2]outPath = os.path.join( os.getcwd(), outPath )if not os.path.isdir( outPath ):os.mkdir( outPath )path =  os.path.join(os.getcwd(),dirName)if checkPath(path): read_dir(path,outPath)

三、使用python批量拆解laya引擎图集文件


# coding: utf-8
import os
import sys
import json
import time
from PIL import Imagedef checkPath(path):if not os.path.exists( path ):print "not find 1 %s"%pathreturn Falsereturn Truedef splitImage(path, fileName, outPath ):# 检查JSON文件 jsonPath = os.path.join(path, "%s.json"%fileName  )if not os.path.exists( jsonPath ):jsonPath = os.path.join( path, "%s.atlas"%(fileName ))if not os.path.exists( jsonPath ):print "not find 0 {}".format(jsonPath)return# 检查PNG文件 pngPath = os.path.join( path, "%s.png"%fileName )if checkPath(pngPath) == False:return# 检查输出目录outPath = os.path.join( path, outPath )if not os.path.isdir( outPath ):os.mkdir( outPath )# 取JSON文件f = open( jsonPath, 'r' )fileStr = f.read()f.close()jsonData = json.loads( fileStr ) #检查image集合meta = jsonData.get( "meta" )imageStr = meta.get( "image" )#拆分文件名images = imageStr.split(",") #拆分文件名images = imageStr.split(",") imgList = []#打开多个文件准备切割for img in images: pngPath = os.path.join( path, img ) pngPath = pngPath.replace("~","-")if not os.path.exists( pngPath ):print "not find 2 %s"%pngPath break;imgList.append(Image.open( pngPath, 'r' ))# 开始切图lastIdx = 0frames = jsonData.get( "frames" )for fn in frames.keys():data = frames.get( fn )frame = data.get( "frame" )idx = frame.get( "idx" ) x = frame.get("x")y = frame.get("y")w = frame.get("w")h = frame.get("h")box = ( x, y, x+w, y+h )outFile = os.path.join( outPath, fn )imgData = imgList[idx].crop( box )imgData.save( outFile, 'png' )#读取指定目录
def find_file( path, outPath):for name in os.listdir( path ): if os.path.isdir( os.path.join(path, name) ): find_file(os.path.join(path, name),outPath )else:portion = os.path.splitext(name)if portion[1] == '.atlas' or portion[1] == '.json': fileName = os.path.join(path, portion[0])outDir = os.path.join(outPath, portion[0]); splitImage(path,fileName , outDir)if __name__=='__main__':# 取得参数if len( sys.argv ) < 2:target = raw_input("Enter your DirName: ")else:target = sys.argv[1]if len( sys.argv ) < 3:outPath = raw_input("Enter your outPath: ")else:outPath = sys.argv[2]outPath = os.path.join( os.getcwd(), outPath )if not os.path.isdir( outPath ):os.mkdir( outPath )path =  os.path.join(os.getcwd(),target)if checkPath(path): find_file(path,outPath)

四、使用python批量拆解Egret引擎图集文件

# coding: utf-8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import os
import json
import time
from PIL import Imagedef checkPath(path):if not os.path.exists( path ):print "not find 1 %s"%pathreturn Falsereturn Truedef splitImage(path, fileName, outPath ):# 检查JSON文件 jsonPath = os.path.join( path, "%s.json"%fileName  ) if not os.path.exists( jsonPath ):print "not find %s"%jsonPathreturn# 检查PNG文件 pngPath = os.path.join( path,  "%s.png"%fileName ) if not os.path.exists( pngPath ):print "not find %s"%pngPathreturn# 检查输出目录 if not os.path.isdir( outPath ):os.mkdir( outPath )# 取JSON文件f = open( jsonPath, 'r' )fileStr = f.read()f.close()jsonData = json.loads( fileStr ) #检查image集合imgList = []imageStr = jsonData.get( "file" )img = Image.open(os.path.join(path,imageStr),'r')imgList.append(img)# 开始切图frames = jsonData.get( "frames" )for fn in frames.keys():data = frames.get( fn )  x = data.get("x")y = data.get("y")w = data.get("w")h = data.get("h")box = ( x, y, x+w, y+h )outFile = os.path.join( outPath, fn )imgData = imgList[0].crop( box )# if imgData.mode == "P":#   imgData = imgData.convert('RGB')outFile = outFile + ".png"imgData.save( outFile )#读取指定目录
def find_file( path, outPath):for name in os.listdir( path ): if os.path.isdir( os.path.join(path, name) ): find_file(os.path.join(path, name),outPath )else:portion = os.path.splitext(name)if portion[1] == '.json': fileName = portion[0]outDir = os.path.join(outPath, portion[0]);  splitImage( path ,fileName, outDir )if __name__=='__main__':# 取得参数if len( sys.argv ) < 2:dirName = raw_input("Enter your dirName: ")else:dirName = sys.argv[1]if len( sys.argv ) < 3:outPath = raw_input("Enter your outPath: ")else:outPath = sys.argv[2]outPath = os.path.join( os.getcwd(), outPath )if not os.path.isdir( outPath ):os.mkdir( outPath )path =  os.path.join(os.getcwd(),dirName) if checkPath(path): # 开始切图find_file(path, outPath)

附Gitee传送地址

仓库传送门

Creator拆图工具

小弟因为平时使用creator开发比较多,所以在creator扩展商店上架了一个免费的插件工具目前只做了windows系统的,欢迎各位下载使用

总结

希望能帮到有需要的人。谢谢

Plist图集批量拆解工具大全相关推荐

  1. 添加文字 生成pdf_PDF 文件编辑方法和工具大全

    PDF 文件编辑方法和工具大全 我在平时的工作生活中经常用到pdf的编辑. 我用过的方法有如下几个. 对于图片文件格式的pdf文件. 一种方式是用photoshop倒入pdf, 然后在photosho ...

  2. 网页导出pdf不完整_PDF 文件编辑方法和工具大全

    PDF 文件编辑方法和工具大全 我在平时的工作生活中经常用到pdf的编辑. 我用过的方法有如下几个. 对于图片文件格式的pdf文件. 一种方式是用photoshop倒入pdf, 然后在photosho ...

  3. 黄聪:基于Linq to edmx的实体数据模型(EDM)类名批量修改工具

    C#实体数据模型(EDM)类名批量修改工具 最近打算用EF来开发一下新的系统,但是数据库中的表名被直接映射为了实体类名,但是我的表名为Base_XXX(XXX为表名)的格式,这导致我在操作数据的时候不 ...

  4. python批量改名_Python写个批量改名工具

    批量改名工具 ✕ 小伙伴说要给文件名前面批量添加点内容,于是就写一个简单的程序! 说起思路... 获取文件夹下的所有文件名, 修改成需要的文件名. 完了! 哈哈哈哈!!!! 主要用到的是 os 模块中 ...

  5. 批量探测工具fpingping常用命令集合大学霸IT达人

    批量探测工具fpingping常用命令集合大学霸IT达人 批量探测工具fpingping是各个系统自带的基于ICMP协议的主机探测工具.但该工具一次只能检测一个主机,不满足渗透测试批量探测的需要.fp ...

  6. 批量ping工具fping

    批量ping工具fping ping是各个系统自带的基于ICMP协议的主机探测工具.但该工具一次只能检测一个主机,不满足渗透测试批量探测的需要.Kali Linux提供一款批量探测工具fping.用户 ...

  7. SNMP OID批量枚举工具

    SNMP OID批量枚举工具 SNMP信息包含大量的系统.设备信息.这些信息均使用OID方式表示.由于OID编号规则复杂,不便于记忆.为了快速通过OID批量获取指定信息,Kali Linux新增了一个 ...

  8. 信息批量提取工具bulk-extractor

    信息批量提取工具bulk-extractor 在数字取证中,通常需要面对海量的数据,如几百GB甚至TB级别的数据.从这些海量数据中,提取有价值的数据是一个漫长.枯燥.繁琐的过程.Kali Linux提 ...

  9. Python简单主机批量管理工具

    Python简单主机批量管理工具 一.程序介绍 需求: 简单主机批量管理工具需求:1.主机分组2.主机信息使用配置文件3.可批量执行命令.发送文件,结果实时返回4.主机用户名密码.端口可以不同5.执行 ...

  10. 大规模的服务器如何管理--批量管理工具

    作为服务器运维人员都知道,日常检查和处理服务器问题几乎占据了所有时间,检查服务器的繁琐也只有他们自己能体会,这时候,要是能有个工具能帮助他们,就如雪中送炭啊.刚刚好,市面上确实出来了这么几款管理工具, ...

最新文章

  1. 使用雪花id或uuid作为Mysql主键,被老板怼了一顿!
  2. 两个组件连线_如何正确的使用日志组件 Log4j、SLF4J、Logback
  3. sony service tel
  4. 结构体重定义冲突_有意减脂、调整饮食,体重却增加了?
  5. UA OPTI512R 傅立叶光学导论3 用复变函数表示物理量
  6. 使用代码获得ABAP software component的version
  7. php time 循环不变,PHP为系统调用的脚本设置超时,set_time_limit不起作用
  8. ThinkPHP讲解(十二)——文本编辑器和ajax传址
  9. MySQL入门之触发器
  10. mysql客户端报错1366_mysql一些异常
  11. 微信支付JAVA DEMO 微信支付爬过的坑
  12. ios笔试题算法_【2018年最新】iOS面试题之常见算法
  13. 如何设置.net控件SplitContainer平均分配
  14. 使用百度识图 完成图片识别和文字识别
  15. 面试自我介绍和简历上的内容能不能相同?
  16. MySQL 表空间碎片
  17. 利用计算机解决鸡兔同笼问题,用计算机解决“鸡兔同笼”
  18. 计算机所有以太网适配的ip,以太网没有有效的ip配置怎么办
  19. 成都拓嘉启远:拼多多直通车推广怎么做才能有开好
  20. QT:模仿腾讯会议(低配版)

热门文章

  1. 购物车一个Adaper,可以删除,全选反选,数量加减
  2. ul li文字不对齐
  3. 基本函数发生器函数须知
  4. Java组合模式(Composite)
  5. L-ScanPort2.0beta版+完整源代码
  6. 明尼苏达大学双城分校计算机科学,明尼苏达大学双城分校计算机专业研究生需要满足哪些条件?...
  7. BSC智能链主网节点搭建-2022最新详细版文档
  8. 计算机睡眠和休眠哪个更好,电脑睡眠和休眠哪个好?电脑休眠和睡眠的区别介绍...
  9. LeetCode 592
  10. 三角形的内切圆和外接圆半径公式