正常免费的使用TexturePack和UnPack的功能
前言:去官网下载个TexturePack下来,可发现要使用需要付费才可,如果不想付费点击使用免费版本,但是呢免费版本打出来的图片带有水印,plist倒是正常的,所以我们要做的就是在plist的基础上使用Python脚本读取plist的信息重新生成图片,这样就可以免费使用TexturePack的功能了!
当然有人可能使用的是破解版,可是破解版基本是拷贝一份TexturePackerGUI去覆盖原exe,涉及到用命令打包的你会发现网上大部分破解版并没有破解TexturePacker.exe也就不能使用了,所以这个时候最简单的方式就是去官网下载正版使用free模式,这样即便是终端命名TexturePacker.exe也能使用了,只是打出来的有红色的水印,不过plist信息确实和付费的一样,我们的操作就在这里
TextureRePk 即基于plist的RePack
# -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import os
from xml.etree import ElementTree
from PIL import Image
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].text
elif tree[index + 1].tag == 'true':
d[item.text] = True
elif tree[index + 1].tag == 'false':
d[item.text] = False
elif tree[index + 1].tag == 'dict':
d[item.text] = tree_to_dict(tree[index+1])
return d
def gen_png_from_plist(plist_filename, png_dir):
# 第一步 读取plist的信息 解析
to_list = lambda x: x.replace('{','').replace('}','').split(',')
# 解析plist为字典
root = ElementTree.fromstring(open(plist_filename, 'r').read())
plist_dict = tree_to_dict(root[0])
# 根据plist画一张大图作为底图
get_size = plist_dict["metadata"]["size"]
sizelist = [ int(x) for x in to_list(get_size) ]
result_image = Image.new('RGBA', sizelist, (0,0,0,0))
# 判断plist类型 有的plist的用 frame 有的用 aliases 关键有的frame还不一样 这里我先做我面对的几种不一样的情况
# food14.png {'frame': '{{107,214},{28,28}}', 'rotated': False, 'sourceColorRect': '{{0,0},{28,28}}', 'sourceSize': '{28,28}', 'offset': '{0,0}'}
# res/shuihuzhuan/loading/logo.png {'spriteSize': '{280,296}', 'textureRect': '{{2,346},{280,296}}', 'textureRotated': True, 'spriteOffset': '{0,0}', 'spriteSourceSize': '{280,296}'}
for k, v in plist_dict['frames'].items():
full_path = os.path.join(png_dir, k)
if not os.path.exists(full_path):
print u"图片不存在:" + full_path
continue
# 打开子图片
part_png = Image.open(full_path)
spriteSourceSize = v["spriteSourceSize"] if v.has_key("spriteSourceSize") else v["sourceSize"]
spriteSourceSize = [ int(x) for x in to_list(spriteSourceSize) ]
# pack后剩下的有效区域
textureRect = v["textureRect"] if v.has_key("textureRect") else v["frame"]
textureRect = [ int(x) for x in to_list(textureRect) ]
# 是否旋转
isRotate = v["textureRotated"] if v.has_key("textureRotated") else v["rotated"]
# 小图在大图上的区域
spriteOffset = v["spriteOffset"] if v.has_key("spriteOffset") else v["offset"]
spriteOffset = [ int(x) for x in to_list(spriteOffset) ]
# 获得长宽
width = int( textureRect[3] if isRotate else textureRect[2] )
height = int( textureRect[2] if isRotate else textureRect[3] )
if (part_png.size[0] != spriteSourceSize[0]) or (part_png.size[1] != spriteSourceSize[1]):
print "图片和所描述尺寸不一致:目标替换尺寸->" + str(spriteSourceSize) + " 图片尺寸->" + str(part_png.size)
continue
if isRotate:
rect_box=(
( spriteSourceSize[0] - height)/2 + spriteOffset[0],
( spriteSourceSize[1] - width)/2 - spriteOffset[1],
( spriteSourceSize[0] + height)/2 + spriteOffset[0],
( spriteSourceSize[1] + width)/2 - spriteOffset[1]
)
else:
rect_box=(
( spriteSourceSize[0] - width)/2 + spriteOffset[0],
( spriteSourceSize[1] - height)/2 - spriteOffset[1],
( spriteSourceSize[0] + width)/2 + spriteOffset[0],
( spriteSourceSize[1] + height)/2 - spriteOffset[1]
)
rect_png = part_png.crop(rect_box)
# 这里有个 spriteOffset 是干嘛的?先不管了
result_box = ( textureRect[0], textureRect[1], textureRect[0] + width, textureRect[1] + height )
if isRotate:
result_image.paste(part_png.rotate(-90), result_box, mask = 0)
else:
result_image.paste(rect_png, result_box, mask = 0)
print "paste", k
# 保存图片
save_name = os.path.join( os.path.dirname(plist_filename), plist_dict["metadata"]["realTextureFileName"] )
result_image.save(save_name)
def main():
# plist 所在路径
plist_filename = r'D:\xampp\htdocs\Aproject\mGit\mSnack\res\game\snakePack2.plist'
# 图片所在文件夹
png_dir = r'D:\xampp\htdocs\Aproject\mGit\mSnack\res\game\snakePack2'
# 根据plist生成图片
if (os.path.exists(plist_filename) and os.path.exists(png_dir)):
gen_png_from_plist( plist_filename, png_dir )
else:
print "make sure you have both plist and pngDir in directory"
if __name__ == '__main__':
main()
这个脚本目前是以Python2.7版本所写,只需要拖动到SublimeText,修改好plist所在位置和素材图片文件夹就可以了,按Ctrl+B键即可快速运行
TextureUnPk即解压plist和大图为小图片
有时候我们有了大图和plist想要把它拆分成小图片,但是手上有没有趁手的工具,不妨用Python再写一个脚本用于功能TextureUnPacker
# -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import os
from xml.etree import ElementTree
from PIL import Image
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].text
elif tree[index + 1].tag == 'true':
d[item.text] = True
elif tree[index + 1].tag == 'false':
d[item.text] = False
elif tree[index+1].tag == 'dict':
d[item.text] = tree_to_dict(tree[index+1])
return d
def gen_png_from_plist(filename):
plist_filename = filename + '.plist'
png_filename = filename + '.png'
# 判断两个文件是否存在
if (not os.path.exists(plist_filename)) or (not os.path.exists(png_filename)):
print "make sure you have both plist and png files in the directory"
return True
to_list = lambda x: x.replace('{','').replace('}','').split(',')
# 打开大图
big_image = Image.open(png_filename)
# 解析plist
root = ElementTree.fromstring(open(plist_filename, 'r').read())
plist_dict = tree_to_dict(root[0])
# 通常遇到的两种plist类型 格式
# food14.png {'frame': '{{107,214},{28,28}}', 'rotated': False, 'sourceColorRect': '{{0,0},{28,28}}', 'sourceSize': '{28,28}', 'offset': '{0,0}'}
# res/shuihuzhuan/loading/logo.png {'spriteSize': '{280,296}', 'textureRect': '{{2,346},{280,296}}', 'textureRotated': True, 'spriteOffset': '{0,0}', 'spriteSourceSize': '{280,296}'}
for k, v in plist_dict['frames'].items():
spriteSourceSize = v["spriteSourceSize"] if v.has_key("spriteSourceSize") else v["sourceSize"]
spriteSourceSize = [ int(x) for x in to_list(spriteSourceSize) ]
# pack后剩下的有效区域
textureRect = v["textureRect"] if v.has_key("textureRect") else v["frame"]
textureRect = [ int(x) for x in to_list(textureRect) ]
# 是否旋转
isRotate = v["textureRotated"] if v.has_key("textureRotated") else v["rotated"]
# 小图在大图上的区域
spriteOffset = v["spriteOffset"] if v.has_key("spriteOffset") else v["offset"]
spriteOffset = [ int(x) for x in to_list(spriteOffset) ]
# 获得长宽
width = int( textureRect[3] if isRotate else textureRect[2] )
height = int( textureRect[2] if isRotate else textureRect[3] )
box = [ textureRect[0], textureRect[1], textureRect[0] + width, textureRect[1] + height ]
rect_on_big = big_image.crop(box)
if isRotate:
rect_on_big = rect_on_big.rotate(90)
result_image = Image.new('RGBA', spriteSourceSize, (0,0,0,0))
if isRotate:
result_box=(
( spriteSourceSize[0] - height)/2 + spriteOffset[0],
( spriteSourceSize[1] - width)/2 - spriteOffset[1],
( spriteSourceSize[0] + height)/2 + spriteOffset[0],
( spriteSourceSize[1] + width)/2 - spriteOffset[1]
)
else:
result_box=(
( spriteSourceSize[0] - width)/2 + spriteOffset[0],
( spriteSourceSize[1] - height)/2 - spriteOffset[1],
( spriteSourceSize[0] + width)/2 + spriteOffset[0],
( spriteSourceSize[1] + height)/2 - spriteOffset[1]
)
result_image.paste(rect_on_big, result_box, mask = 0)
outfile = filename + '/' + k
print outfile, "generated"
if not os.path.exists(os.path.dirname(outfile)):
os.makedirs(os.path.dirname(outfile))
result_image.save(outfile)
if isRotate:
print("isRotate", isRotate, k)
def main():
# 这里输入要解压的plist文件路径 不需要带.plist 同样的图片一样的名字
# filename = r'C:\Users\Administrator\Desktop\mibao\xxx'
filename = r"D:\xampp\htdocs\Aproject\mGit\mSnack\res\game\snakePack2"
gen_png_from_plist(filename)
if __name__ == '__main__':
main()
比如我要解压exit的图片,这里只需要填入filename = r’G:\quick\reName\exit’即可,前面带r的意思是正则表达式,也就是你输入什么字符串就是什么路径,不会像\n被解析为回车键。
好了到了这里我们就讲解完毕了