# -*- coding: utf-8 -*-
import os
import os.path
from PIL import Image
import tkinter as tk
from tkinter import filedialog
from tqdm import tqdm
def premultiply_alpha(image):
    '''
    若输出的贴图文件应用了预乘alpha
    :param image:
    :return:
    '''
    if image.mode != "RGBA":
        image = image.convert("RGBA")
    for i in range(image.width):
        for j in range(image.height):
            red, green, blue, alpha = image.getpixel((i,j))
            if alpha > 0:
                image.putpixel((i,j),tuple([min(max(int(p / alpha * 255),0), 255) for p in (red, green, blue)]+[alpha]))
    return image

def split_atlas(fileName, output_path:str=None, atlas_path:str=None):
    '''
    :param fileName: 文件名
    :param output_path: 输出目录
    :param atlas_path: 图集.atlas文件
    :return:
    '''
    if output_path is None:
        output_path = os.path.join(os.getcwd(), fileName)
    if atlas_path is None:
        atlas_path = fileName + '.atlas'
    with open(atlas_path, 'r',encoding='utf-8-sig') as atlas:
        os.makedirs(output_path, exist_ok=True)
        for i in range(6):
            if i==1:
                png_name = atlas.readline().strip("\n")
                png_path = os.path.join(os.path.split(atlas_path)[0],png_name)
                ori_image = Image.open(png_path)
            elif i==2:
                big_image_size = atlas.readline()
                big_image_width, big_image_height = list(map(int, big_image_size.split(":")[1].split(",")))
                big_image = ori_image.resize((big_image_width, big_image_height))
            else:
                _line = atlas.readline()
        while True:
            line1 = atlas.readline()  # name
            if len(line1) == 0:
                break
            elif len(line1.strip("\n")) == 0:
                continue
            elif line1.strip("\n").endswith('.png'):
                png_name = line1.strip("\n")
                png_path = os.path.join(os.path.split(atlas_path)[0], png_name)
                ori_image = Image.open(png_path)
                for i in range(4):
                    if i == 0:
                        big_image_size = atlas.readline()
                        big_image_width, big_image_height = list(map(int, big_image_size.split(":")[1].split(",")))
                        big_image = ori_image.resize((big_image_width, big_image_height))
                    else:
                        _line = atlas.readline()
            else:
                line1 = line1.strip("\n")
                rotate = atlas.readline().split(":")[1].strip("\n")
                xy = atlas.readline()  # xy
                size = atlas.readline()  # size
                orig = atlas.readline()  # orig
                offset = atlas.readline().strip("\n")  # offset
                index = atlas.readline()  # index
                rotate = rotate.strip(" ")
                if rotate == "true":
                    rotate_angle = 90
                elif rotate == "false":
                    rotate_angle = 0
                else:
                    rotate_angle = int(rotate)
                rotate = rotate_angle > 0
                name = line1.replace("\n", "") + ".png"
                if '/' in name:
                    os.makedirs(os.path.join(output_path, '/'.join(name.split('/')[:-1])), exist_ok=True)
                width,height = list(map(int,size.split(":")[1].split(",")))
                ltx,lty = list(map(int,xy.split(":")[1].split(",")))
                origx, origy = list(map(int, orig.split(":")[1].split(",")))
                offset_x,offset_y = list(map(int,offset.split(":")[1].split(",")))
                if rotate_angle==0 or rotate_angle==180:
                    rbx = ltx + width
                    rby = lty + height
                elif rotate_angle==90 :
                    rbx = ltx + height
                    rby = lty + width
                elif rotate_angle==270:
                    rbx = ltx + height
                    rby = lty + width
                #print(name, width, height, ltx, lty, rbx, rby)
                result_image = Image.new("RGBA", (origx, origy))
                rect_on_big = big_image.crop((ltx, lty, rbx, rby))
                if rotate:
                    rect_on_big = rect_on_big.rotate(-rotate_angle,expand=True)
                if premultiply:
                    rect_on_big = premultiply_alpha(rect_on_big)
                result_image.paste(rect_on_big, (offset_x, origy-height-offset_y))
                result_image.save(output_path + '/' + name)

if __name__ == '__main__':
    input_path = filedialog.askdirectory(title="选择需要批量解包的目录")
    pbar = tqdm(os.listdir(input_path))
    for file in pbar:
        pbar.set_description(f"Solving {file} ...")
        if os.path.isdir(os.path.join(input_path,file)):
            unitName = os.path.split(file)[1]
            outputPath = os.path.join(input_path,file)
            split_atlas(unitName,output_path=outputPath,atlas_path=os.path.join(outputPath,unitName+'.atlas'))

 部分素材.png实际尺寸与.atlas内描述的尺寸不一致,直接拉伸即可(代码已包含该操作)

 

抠抠qun:622095682,欢迎游戏开发爱好者加入交流

参考资料:

python切割图片,读取spine的atlas转json配置(python2)https://blog.csdn.net/wclwonder/article/details/90543862

Spine的纹理压缩和半透显示(什么是预乘Alpha)https://zhuanlan.zhihu.com/p/76077345

正确的spine导出/导入参数匹配http://zh.esotericsoftware.com/spine-unity#Advanced

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐