这篇文章介绍手杀的拆包方法。都是批量完成的。确保某一步完成之后再继续下一步。消耗的时间可能会相当长。
下载三国杀移动版
点击这里下载三国杀移动版
下载必需软件
对于ArchLinux用户,直接yay -S pvr-tex-tool-bin imagemagick
。
对于Windows用户,因为官方下载PVRTexTool要注册,所以只能去软件园下载了,自己百度解决。
ImageMagick可以在官网下载,当然就那破网速我还是建议去软件园下载。
此外Windows还需要额外准备一个解压缩软件,我推荐7zip。
记得安装Python。
解包三国杀移动版
把下载下来的apk文件后缀名改成.zip(其实也不用改),然后把assets文件夹解压缩出来。素材都在这里面。
去解压好的assets文件夹下面,把res文件夹单独拿出来。素材都在这里面。(再放送)
res下面有这些:
- audios文件夹:音频素材,直接可以听。
- font:图片素材的字体
- fonts:ttf字体
- ui:里面是ui素材。
.pvr.ccz@alpha转.pvr.ccz
我们可以注意到里面有许多.pvr.ccz文件。ccz文件就是pvr文件的压缩包形式,所以我们先把ccz文件转为pvr文件。注意到有.pvr.ccz@alpha结尾的,这个其实也是.pvr.ccz文件,只是在文件名后面加了个alpha。所以我们先把所有的<name>.pvr.ccz@alpha改成<name>_alpha.pvr.ccz形式,方便下一步操作。
由于pvr.ccz文件实在是太多了,手动重名极其折磨人,我们需要写个自动化脚本。我只会shell脚本,Windows用户请装个git bash用来跑shell脚本。
假设你在手刹素材目录,也就是res目录下面。现在请新建一个文本文件,然后改名为rename_alpha.sh(txt拓展名也要改掉)。然后用文本编辑器打开它并粘贴以下内容:
for l in `find -name '*@alpha'`
do
mv $l ${l%*.pvr.ccz@alpha}"_alpha.pvr.ccz";
done
保存。在文件夹里面右键,点“Git Bash Here”,然后输入命令bash rename_alpha.sh
,回车。现在重命名工作已经完成了。
.pvr.ccz转.pvr
.pvr.ccz就是一个pvr文件用zlib压缩了加个16字节文件头而已。我们写个python脚本就能把一个.pvr.ccz转成.pvr文件了。
现在新建一个文本文件,重命名为ccz2pvr.py。然后打开并粘贴以下内容:
import zlib
import sys
ccz = sys.argv[1]
pvr = ccz[0:len(ccz) - 4]
ccz = open(ccz, "rb").read()
pvr = open(pvr, "wb")
pvr.write(zlib.decompress(ccz[16:len(ccz)]))
pvr.close()
保存。然后在git bash中输入命令python,回车,如果看到的是这样:
Python 3.10.1 (main, Dec 18 2021, 23:53:45) [GCC 11.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
反正不是啥报错之类的,说明python正常安装,按Ctrl+D重新回到bash里面。如果是报错信息,请确认python是否正常安装。
然后我们创建ccz2pvr.sh,输入以下内容:
for l in `find -name '*.ccz'`
do
python ccz2pvr.py $l
rm $l
done
保存,运行它。现在ccz文件都被转为pvr了。
pvr转png
现在该我们PVRTexTool上场了。新建文件pvr2png.sh,输入:
for l in `find -name '*.pvr'`
do
pvr-tex-tool -ics sRGB -i $l -d ${l%.pvr}.png
rm $l
rm ${l%.pvr}.Out.pvr
done
如果你是Windows用户,情况又稍微不同。需要输入的命令改为
for l in `find -name '*.pvr'`
do
C:/PowerVR/GraphicsSDK/PVRTexTool/CLI/Windows_x86_64/PVRTexToolCLI.exe -ics sRGB -i $l -d ${l%.pvr}.png
rm $l
rm ${l%.pvr}.Out.pvr
done
那一长串自然是你的PVRTexToolCLI.exe文件的路径了。注意了,路径里面的反斜杠“\”记得改成斜杠"/"。
保存,运行命令。现在pvr文件都变成png了。
合并RGB通道和alpha通道
我们可以注意到拿出来的png文件有些是纯黑底的,有些是黑白的。那些黑白的是alpha通道信息。现在我们把这两个合并起来,得到真正可用的透明底的png图片。
这里要用到ImageMagick。
新建alpha_png.sh,输入以下内容:
for l in `find -name '*_alpha.png'`
do
n=${l%*_alpha.png}.png
convert $n $l -compose copy-opacity -composite $n
rm $l
done
对于Windows用户,输入这些:
for l in `find -name '*_alpha.png'`
do
n=${l%*_alpha.png}.png
<你的ImageMagick安装目录>/convert.exe $n $l -compose copy-opacity -composite $n
rm $l
done
注意目录里面的反斜杠要改成斜杠哦。保存,运行。
plist拆图
可以看到有些图是很多小图拼成的大图。有些大图有同名.plist文件,另一些有同名.atlas文件。我们先来把plist图拆开成小图。
这里也是找了个plist拆图的python脚本。我们创建一个plist_split.py的文件,输入下面的内容:
import plistlib
import os
import sys
from PIL import Image
def export_image(img, pathname, item):
# 去透明后的子图矩形
x, y, w, h = tuple(map(int, item['frame']))
# 子图原始大小
size = tuple(map(int, item['sourceSize']))
# 子图在原始图片中的偏移
ox, oy, _, _ = tuple(map(int, item['sourceColorRect']))
# 获取子图左上角,右下角
if item['rotated']:
box = (x, y, x + h, y + w)
else:
box = (x, y, x + w, y + h)
# 使用原始大小创建图像,全透明
image = Image.new('RGBA', size, (0, 0, 0, 0))
# 从图集中裁剪出子图
sprite = img.crop(box)
# rotated纹理旋转90度
if item['rotated']:
sprite = sprite.transpose(Image.ROTATE_90)
# 粘贴子图,设置偏移
image.paste(sprite, (ox, oy))
# 保存到文件
print('保存文件:%s' % pathname)
image.save(pathname, 'png')
# 获取 frame 参数
def get_frame(frame):
result = {}
if frame['frame']:
result['frame'] = frame['frame'].replace('}', '').replace('{', '').split(',')
result['sourceSize'] = frame['sourceSize'].replace('}', '').replace('{', '').split(',')
result['sourceColorRect'] = frame['sourceColorRect'].replace('}', '').replace('{', '').split(',')
result['rotated'] = frame['rotated']
return result
# 生成图片
def gen_image(file_name, export_path):
# 检查文件是否存在
plist = file_name + '.plist'
if not os.path.exists(plist):
print('plist文件【%s】不存在!请检查' % plist)
return
png = file_name + '.png'
if not os.path.exists(png):
print('png文件【%s】不存在!请检查' % plist)
return
# 检查导出目录
if not os.path.exists(export_path):
try:
os.mkdir(export_path)
except Exception as e:
print(e)
return
# 使用plistlib库加载 plist 文件
lp = plistlib.load(open(plist, 'rb'))
# 加载 png 图片文件
img = Image.open(file_name + '.png')
# 读取所有小图数据
frames = lp['frames']
for key in frames:
item = get_frame(frames[key])
export_image(img, os.path.join(export_path, key), item)
if __name__ == '__main__':
if len(sys.argv) == 3:
filename = sys.argv[1]
exportPath = sys.argv[2]
gen_image(filename, exportPath)
然后新建plist_split.sh,输入:
for l in `find -name '*.plist'`; do
pic=${l%%.plist}
python plist_split.py $pic $pic'_plist'
rm $pic'.png'
rm $pic'.plist'
done
atlas拆图
新建atlas_split.py,输入
import os
import sys
import re
from PIL import Image
xymatcher = re.compile("\s*xy: (\d+),\s*(\d+)")
sizematcher = re.compile("\s*size: (\d+),\s*(\d+)")
indexmatcher = re.compile("\s*index: ([\-\d]+)")
origmatcher = re.compile("\s*orig: (\d+),\s*(\d+)")
offsetmatcher = re.compile("\s*offset: (\d+),\s*(\d+)")
def write_image(name, sprites, atlas_file, out_dir):
"""Get next texture info from the atlas and write it to the
directory"""
rotate = atlas_file.readline() #ignore rotate
if ("true" in rotate):
rotate = True
xy = xymatcher.match(atlas_file.readline())
x = int(xy.group(1))
y = int(xy.group(2))
sizes = sizematcher.match(atlas_file.readline())
width = int(sizes.group(1))
height = int(sizes.group(2))
#split = atlas_file.readline()
#if "split" in split:
# atlas_file.readline() #ignore origin
#atlas_file.readline() #ignore offset
orig = origmatcher.match(atlas_file.readline())
origw = int(orig.group(1))
origh = int(orig.group(2))
offset = offsetmatcher.match(atlas_file.readline())
offsetx = int(offset.group(1))
offsety = int(offset.group(2))
index_match = indexmatcher.match(atlas_file.readline())
index = index_match.group(1)
box = x, y, x + width, y + height
if rotate == True:
box = x, y, x + height, y + width
tile = sprites.crop(box)
if rotate == True:
tile = tile.transpose(Image.ROTATE_270)
target = Image.new("RGBA", (origw, origh))
target.paste(tile, (offsetx, offsety))
name = name if index == "-1" else name + "_" + index
#return
out_path = os.path.join(out_dir, name + ".png")
os.system("mkdir -p " + out_path)
os.system("rm -r " + out_path)
print ("Writing sprite: ", name, " to: ", out_path, " sizes: ", width, height, x, y)
target.save(out_path, "PNG")
def split(atlas, out_dir):
"""Open's the sheet, reads each atlas item and writes it into
the out directory"""
#sprites = Image.open(sheet).convert("RGBA")
atlas_file = open(atlas)
#read first few lines
atlas_file.readline() #blank line
sheet = os.path.join(os.path.dirname(atlas), atlas_file.readline().rstrip("\n"))
sprites = Image.open(sheet).convert("RGBA") #use rgba for now
while True:
line = atlas_file.readline()
if line.startswith("repeat"):
break
while True:
name = atlas_file.readline()
if name:
write_image(name.rstrip("\n"), sprites, atlas_file, out_dir)
else:
break
def print_usage():
print ("Usage : python atlas_splitter.py atlas out_dir")
if len(sys.argv) < 3:
print_usage()
elif sys.argv[1] == "--help":
print_usage()
else:
split(sys.argv[1], sys.argv[2])
再新建atlas_split.sh,输入
for l in `find -name "*.atlas"`
do
mkdir ${l}_out
python atlas_split.py $l ${l}_out
done
保存运行。