#!/usr/bin/env python # coding:utf-8 import os import sys curr_dir = os.path.split(os.path.abspath(__file__))[0] sys.path.append(os.path.join(curr_dir, '../')) sys.path.append(os.path.join(curr_dir, '../config_convert')) import utils as utils import config as config import json import re import numpy as np from psd_tools import PSDImage from PIL import Image from config_convert.game_play_type import MainPlayType levels_root_path = os.path.join(curr_dir, "../../Assets/AssetRaw/UIRaw/Raw/Level/") thumbnail_root_path = os.path.join(curr_dir, "../../Assets/AssetRaw/UIRaw/Raw/Thum/") version_path = os.path.join(curr_dir, "../../../../../unity_ap_bundle_resource/psd_version.json") # 游戏玩法的设计分辨率 design_width = 1040 design_height = 1280 thumbnail_size = (1500,1000) crop_rect = (250,0,1250,1000) crop_size = (1000,1000) #psd需要用到的一些命名规则 titem_group = 'titem' nouse_group = 'nouse' tfull_layer = 'tfull' base_layer = 'base' mask_layer = 'tmask' tlight_name = 'tlight' tshadow_name = 'tshadow' group_name = 'group_' json_level_id = 'levelId' json_list = 'JsonPiecesDataList' json_x_pos = 'XPos' json_y_pos = 'YPos' json_name = 'Name' scale = 0 version = {} def run(psd_path, levels_output_dir, thumbnail_output_dir): """ 解析PSD文件 :param path: psd文件路径 :param levels_output_dir: 关卡资源输出文件夹路径, :param thumbnail_output_dir: 缩略图资源输出文件夹路径 :return: 无 """ print(f'开始解析:{psd_path}') psd_name = os.path.split(psd_path)[1].replace('.psd','') psd_type = psd_name.split('_')[0] # export_dir = os.path.join(levels_root_path,psd_type) if not os.path.exists(levels_output_dir): os.mkdir(levels_output_dir) if not os.path.exists(thumbnail_output_dir): os.mkdir(thumbnail_output_dir) psd = PSDImage.open(psd_path) level_info_json_data = {} level_info_json_data[json_level_id] = psd_name piece_list = [] titem_out_path = os.path.join(levels_output_dir, 'titem') if not os.path.exists(titem_out_path): os.mkdir(titem_out_path) for layer in psd: layer.visible = True if layer.name == nouse_group and layer.is_group(): # layer.visible = False continue if layer.name == titem_group and layer.is_group(): for item_layer in layer: piece_data = {} item_layer.visible = True # lt_x, lt_y = layer.offset # c_w, c_h = layer.size # c_x, c_y = lt_x + c_w / 2, lt_y + c_h / 2 # piece_data[json_x_pos] = c_x # piece_data[json_y_pos] = c_y piece_data[json_name] = f'{psd_name}_{item_layer.name}' piece_list.append(piece_data) img_cur_item_layer = item_layer.composite() img_cur_item_layer.save(f"{titem_out_path}/{psd_name}_{item_layer.name}.png") if layer.is_group() and group_name in layer.name: for child_layer in layer: piece_data = {} lt_x, lt_y = child_layer.offset c_w, c_h = child_layer.size c_x, c_y = lt_x + c_w / 2, lt_y + c_h / 2 piece_data[json_x_pos] = c_x piece_data[json_y_pos] = c_y piece_data[json_name] = f'{psd_name}_{child_layer.name}' img_cur_layer = child_layer.composite() img_cur_layer.save(f"{levels_output_dir}/{psd_name}_{child_layer.name}.png") piece_list.append(piece_data) if not layer.is_group(): piece_data = {} lt_x, lt_y = layer.offset c_w, c_h = layer.size c_x, c_y = lt_x + c_w / 2, lt_y + c_h / 2 piece_data[json_x_pos] = c_x piece_data[json_y_pos] = c_y piece_data[json_name] = f'{psd_name}_{layer.name}' img_cur_layer = layer.composite() img_cur_layer.save(f"{levels_output_dir}/{psd_name}_{layer.name}.png") piece_list.append(piece_data) level_info_json_data[json_list] = piece_list json_path = os.path.join(levels_output_dir, f'{psd_name}.json') with open(json_path, "w") as f: f.write(json.dumps(level_info_json_data)) # print(level_info_json_data) thumbnail_path = os.path.join(thumbnail_output_dir, f'{psd_name}_thum.png') psd_image = psd.composite(layer_filter=lambda mix_layer : mask_layer in (mix_layer.name) or tfull_layer in (mix_layer.name) or base_layer in (mix_layer.name)) # psd_image = psd.composite() psd_image.thumbnail(thumbnail_size) crop_image = psd_image.crop(crop_rect) crop_image.save(thumbnail_path) print(f'解析完毕:{psd_path}') pass def make_version_file(remake): """ 生成version文件 :param remake: 重新生成 :return: """ version_file = os.path.join(curr_dir, version_path) 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) version_file = os.path.join(curr_dir, version_path) with open(version_file, "r") as f: try: versions = json.load(f) except Exception as e: print(e) # 删除版本文件并重新生成 make_version_file(True) def write_version(): version_file = os.path.join(curr_dir, version_path) with open(version_file, "w") as f: json.dump(versions, f, sort_keys=True, indent=4) def parse_psd(path, output_root, specific_files, platform): """ 解析psd文件 :param path: psd文件路径 :param output_root: 资源输出路径 :param specific_files: 需要解析文件列表, 如果为[]则解析所有文件,否则只解析列表中的文件 :return: 所有解析psd name """ print("解析指定文件", specific_files) mainPlayType = MainPlayType() global levels_root_path, thumbnail_root_path, version_path # 重置保存路径 levels_root_path = os.path.join(output_root, "Raw/Level") thumbnail_root_path = os.path.join(output_root, "Raw/Thum") utils.mkdirs(levels_root_path) utils.mkdirs(thumbnail_root_path) version_path = os.path.join(output_root, f"../psd_version.json") # load_version() all_parse_asset_names = [] for root, dirs, files in os.walk(path): for name in files: if name.endswith(".zip"): src_filename = os.path.join(root, name) file_name = os.path.split(src_filename)[1] asset_id = file_name.split(".")[0] if asset_id not in specific_files: continue hash_old = "" # if asset_id in versions: # hash_old = versions[asset_id] hash_now = utils.calc_hash(src_filename) print("文件:" + src_filename + " => old = " + hash_old + " now = " + hash_now) if hash_old != hash_now: print("文件更改:" + src_filename + " => old = " + hash_old + " now = " + hash_now) levels_output_dir = None thumbnail_output_dir = None for gameplay in mainPlayType.all_main_play_type_list: if gameplay in asset_id: gameplay_dir = os.path.join(levels_root_path, gameplay) if not os.path.exists(gameplay_dir): os.mkdir(gameplay_dir) levels_output_dir = os.path.join(gameplay_dir, asset_id) thumbnail_output_dir = os.path.join(thumbnail_root_path, gameplay) utils.clear_dirs(levels_output_dir) break if levels_output_dir is None or thumbnail_output_dir is None: print(asset_id + "资源命名异常,找不到对应玩法gameplay") continue psd_zip_filename = os.path.join(root, name) utils.unzip_file(psd_zip_filename) psd_filename = "{}.psd".format(os.path.splitext(os.path.join(root, name))[0]) run(psd_filename, levels_output_dir, thumbnail_output_dir) all_parse_asset_names.append(asset_id) # versions[asset_id] = hash_now # write_version() os.remove(psd_filename) return all_parse_asset_names if __name__ == "__main__": # pass # PSD测试方法 # parse_psd(sys.argv[1], sys.argv[2], []) # print(os.getcwd()) # print(os.path.curdir) # psd_path = "./CheckPsd/main_30point_ws20250422_1.psd" psd_dir = "./CheckPsd" psd_files = {} for filename in os.listdir(psd_dir): filepath = os.path.join(psd_dir, filename) if os.path.isfile(filepath) and filename.lower().endswith('.psd'): file_name = filename.replace('.psd', '') psd_files[file_name] = filepath print(psd_files) for k,v in psd_files.items(): run(v,f'./{k}',f'./{k}/thu')