#!/usr/bin/python #encoding:utf-8 import os, sys curr = os.path.dirname(sys.argv[0]) if curr != "": os.system("cd " + curr) from psd_tools import PSDImage from PIL import Image import hashlib import utils import export_outline import json def parse_psd(path): global scale global versions file_name = os.path.split(path)[1] log = [] log.append("开始检测:{}".format(file_name)) psd = PSDImage.open(path) try: image = psd.composite() except Exception as e: log.append("文件无法打开" + repr(e)) has_base = False has_finish = False has_thumbnail = False lines = {} patch_stages = {} spatch_stages = {} bad_stages = {} sbad_stages = {} auto_stages = {} patch_names = [] bad_names = [] spatch_parent_name = [] sbad_parent_name = [] #patch的末尾数字 patch_end = [] spatch_end = [] bad_end = [] sbad_end = [] line_end = [] max_width = 0 max_height = 0 is_activity_main_psd = path.find("activity/main_psd/") != -1 or path.find("activity\\main_psd\\") != -1 #活动地图读取整个PSD的宽高 if is_activity_main_psd: max_width = psd.width max_height = psd.height else: #普通资源读取base的宽高 for item in psd.descendants(): if not item.is_group(): nArr = item.name.split('_') if item.name == "base": max_width = item.width max_height = item.height break if is_activity_main_psd: if max_width < 1024: log.append("玩法活动背景过小,宽度不能小于1024") if max_height < 2560: log.append("玩法活动背景过小,高度不能小于2560") for item in psd.descendants(): if not item.is_group(): nArr = item.name.split('_') if item.name.strip() != item.name: log.append("命名中存在空格:{}".format(item.name)) if not is_activity_main_psd and nArr[0] == 'base': if has_base: log.append("存在多个base图层") has_base = True elif nArr[0] == 'finish': if has_finish: log.append("存在多个finish图层") has_finish = True elif nArr[0] == 'line': #以前存在line_1,整图轮廓的情况,这种情况视为无line if len(nArr) > 2: if nArr[1] not in lines: lines[nArr[1]] = [] if nArr[2] in lines[nArr[1]]: log.append("存在重复图层:{}".format(item.name)) lines[nArr[1]].append(nArr[2]) else: pass line_end.append(item.name.replace("line", "")) elif nArr[0] == 'patch' or nArr[0] == 'patchrp': if nArr[1] not in patch_stages: patch_stages[nArr[1]] = [] patch_stages[nArr[1]].append(nArr[2]) if item.name not in patch_names: patch_names.append(item.name) patch_end.append(item.name.replace("patch", "")) elif nArr[0] == 'spatch': if nArr[1] not in spatch_stages: spatch_stages[nArr[1]] = [] spatch_stages[nArr[1]].append(nArr[2]) #检测父节点 #通过正则表达式,筛选出#开头与#结尾的字符串 parr = item.name.split('#') if len(parr) != 3: log.append("spatch图层命名错误,找不到父节点:{}".format(item.name)) else: parent = parr[1] if parent not in spatch_parent_name: spatch_parent_name.append(parent) tarr = parent.split('_') if tarr[0] != "patch": log.append("spatch图层命名错误,父节点不是patch:{}".format(item.name)) spatch_end.append(item.name.replace("spatch", "").replace(f"_#{parent}#", "")) elif nArr[0] == 'bad': if nArr[1] not in bad_stages: bad_stages[nArr[1]] = [] bad_stages[nArr[1]].append(nArr[2]) if item.name not in bad_names: bad_names.append(item.name) bad_end.append(item.name.replace("bad", "")) elif nArr[0] == 'sbad': if nArr[1] not in sbad_stages: sbad_stages[nArr[1]] = [] sbad_stages[nArr[1]].append(nArr[2]) #检测父节点 #通过正则表达式,筛选出#开头与#结尾的字符串 parr = item.name.split('#') if len(parr) != 3: log.append("sbad图层命名错误,找不到父节点:{}".format(item.name)) else: parent = parr[1] if parent not in sbad_parent_name: sbad_parent_name.append(parent) tarr = parent.split('_') if tarr[0] != "bad": log.append("sbad图层命名错误,父节点不是bad:{}".format(item.name)) sbad_end.append(item.name.replace("sbad", "").replace(f"_#{parent}#", "")) elif nArr[0] == 'auto': if nArr[1] not in auto_stages: auto_stages[nArr[1]] = [] auto_stages[nArr[1]].append(nArr[2]) elif nArr[0] == 'thumbnail' or nArr[0] == 'role' or nArr[0] == 'rptmp': if nArr[0] == 'thumbnail': has_thumbnail = True elif is_activity_main_psd and nArr[0] == 'entry': if len(nArr) != 3: log.append("活动子点位,命名错误:{}".format(item.name)) elif is_activity_main_psd and nArr[0] == 'base': if nArr[1] == '1': has_base = True else: log.append("命名错误:{}\n".format(item.name)) #空图层检测 if item.width <= 0 or item.height <= 0: log.append("存在空图层:{}\n".format(item.name)) #横坐标越界检测 if item.offset[0] < 0 or (item.offset[0] + item.width) > max_width: log.append("横坐标越界{}\n".format(item.name)) #纵坐标越界检测 if item.offset[1] < 0 or (item.offset[1] + item.height) > max_height: log.append("纵坐标越界{}\n".format(item.name)) if not has_base: log.append("未检测到base图层\n") if not is_activity_main_psd and not has_finish: log.append("未检测到finish图层\n") if is_activity_main_psd and not has_thumbnail: log.append("未检测到 缩略图 图层\n") for stage in patch_stages: tmp = {} for item in patch_stages[stage]: if item in tmp: log.append("存在重复图层:patch_{}_{}".format(stage, item)) else: tmp[item] = 0 for stage in auto_stages: tmp = {} for item in auto_stages[stage]: if item in tmp: log.append("存在重复图层:auto_{}_{}".format(stage, item)) else: tmp[item] = 0 if not is_activity_main_psd: if len(lines) > 0 and len(patch_stages) != len(lines): log.append("阶段与线稿不对应,线稿:{} 关卡:".format(len(lines), len(patch_stages))) for item in patch_end: if item not in line_end: log.append("patch图层找不到描线:patch{}".format(item)) for item in line_end: if item not in patch_end: log.append("描线找不到patch图层:line{}".format(item)) if is_activity_main_psd: for item in bad_end: if item not in patch_end: log.append("bad图层找不到拼图图层:bad{}".format(item)) for item in patch_end: if item not in bad_end: log.append("拼图图层找不到bad图层:patch{}".format(item)) for item in sbad_end: if item not in spatch_end: log.append("sbad图层找不到拼图图层:sbad{}".format(item)) for item in spatch_end: if item not in sbad_end: log.append("拼图图层找不到sbad图层:spatch{}".format(item)) for stage in spatch_stages: tmp = {} for item in spatch_stages[stage]: if item in tmp: log.append("存在重复图层:spatch_{}_{}".format(stage, item)) else: tmp[item] = 0 for stage in sbad_stages: tmp = {} for item in sbad_stages[stage]: if item in tmp: log.append("存在重复图层:sbad_{}_{}".format(stage, item)) else: tmp[item] = 0 #检测sbad的父节点是否存在 for a_sbad_name in sbad_parent_name: if a_sbad_name not in bad_names: log.append(f"sbad中配置的主节点{a_sbad_name} 实际找不到") #检测spatch的父节点是否存在 for a_spatch_name in spatch_parent_name: if a_spatch_name not in patch_names: log.append(f"spatch中配置的主节点{a_spatch_name} 实际找不到") log.append("检测结束") if len(log) == 2: return True else: for a_log in log: print(a_log) return False def convert_2_zip_file(path, is_activity_psd): file_info_arr = os.path.split(path) file_path = file_info_arr[0] file_name = os.path.split(path)[1] #检测成功,压缩到zip os.chdir(file_path) file_name_without_ex = file_name.split(".")[0] utils.zip_file("{}.psd".format(file_name_without_ex), "{}.zip".format(file_name_without_ex)) os.chdir("../") if is_activity_psd: os.chdir("../") os.remove(path) ###生成version文件 def make_version_file(remake): version_file = 'version.json'; if remake: if os.path.exists(version_file): os.remove(version_file) if not os.path.exists(version_file): with open(version_file, 'w') as f: json.dump({}, f, sort_keys=True, indent=4) ###加载版本文件 def load_version(): global versions make_version_file(False); with open('version.json', 'r') as f: try: versions = json.load(f) except: #删除版本文件并重新生成 make_version_file(True); def write_version(): with open('version.json', 'w') as f: json.dump(versions, f, sort_keys=True, indent=4) if __name__ == '__main__': load_version() deal_psdid = [] is_force = sys.argv[1] if len(sys.argv) > 1 else False for root , dirs, files in os.walk('./'): for name in files: src_file = os.path.join(root, name) if name.endswith('.psd') or name.endswith('.zip'): file_info_arr = os.path.split(src_file) file_path = file_info_arr[0] file_name = file_info_arr[1] key = file_name.split("_")[0] try: i_key = int(key) except Exception as e: print("资源命名错误,请查询是否存在特殊字符:{}".format(name)) continue if key not in deal_psdid: deal_psdid.append(key) else: print("存在重复关卡:{}".format(key)) if name.endswith('.psd') or (name.endswith('.zip') and is_force): file_info_arr = os.path.split(src_file) file_path = file_info_arr[0] file_name = file_info_arr[1] key = file_name.split("_")[0] hash_old = "" if key in versions: hash_old = versions[key] if os.path.exists(src_file): hash_now = "" if name.endswith('.psd'): hash_now = utils.calc_hash(src_file) if hash_now != hash_old or is_force: psd_file = src_file if name.endswith('.zip'): utils.unzip_file(src_file) psd_file = "{}.psd".format(os.path.splitext(psd_file)[0]) hash_now = utils.calc_hash(psd_file) try: ret = parse_psd(psd_file) is_activity_psd = psd_file.find("activity/main_psd/") != -1 or psd_file.find("activity\\main_psd\\") != -1 or psd_file.find("activity/level_psd/") != -1 or psd_file.find("activity\\level_psd\\") != -1 if ret: #检测成功,压缩到zip convert_2_zip_file(psd_file, is_activity_psd) versions[key] = hash_now write_version() except Exception as e: print(name + " 解析失败:" + repr(e) + ",请检查命名规范,比如auto_1_1=>auto_1 或 patch_1_1=>patch_1") elif hash_now == hash_old: is_activity_psd = src_file.find("activity/main_psd/") != -1 or src_file.find("activity\\main_psd\\") != -1 or src_file.find("activity/level_psd/") != -1 or src_file.find("activity\\level_psd\\") != -1 convert_2_zip_file(src_file, is_activity_psd)