###-----检测psd是否合格,通过的psd压缩----- import os import time import config from psd_tools import PSDImage from PIL import Image import json import utils import sys curr = os.path.dirname(sys.argv[0]) if curr != "": os.system("cd " + curr) def check_psd(psd_path): psd_name = os.path.split(psd_path)[1] names = psd_name.split('_') log(f'开始检测:{psd_name}') error_log = [] if len(names) != 3 and len(names) != 4 and len(names) != 5 and len(names) != 6: error_log.append(config.error_log.psd_name_error.value) # elif not names[0][0].islower(): # error_log.append(f'{psd_name}:{config.error_log.psd_name_error.value}') # elif not names[1][0].islower(): # error_log.append(f'{psd_name}:{config.error_log.psd_name_error.value}') # elif not names[2][0].isdigit(): # error_log.append(f'{psd_name}:{config.error_log.psd_name_error.value}') try: psd_point_num = int(names[1][:2]) except Exception as e: print(e) error_log.append(config.error_log.psd_name_error.value) return psd = PSDImage.open(psd_path) color_mode = get_psd_color_mode(psd_path) if color_mode == 'CMYK': error_log.append(f'{psd_name}:{config.error_log.psd_cmyk.value}') print("PSD 文件的色彩空间是 CMYK") # elif color_mode == 'RGB': # print("PSD 文件的色彩空间是 RGB") psd_width = psd.width psd_height = psd.height # print(f'{psd.size}') if (psd_width != config.psd_standard_width and psd_width != config.psd_standard_width2) or (psd_height != config.psd_standard_height and psd_height != config.psd_standard_height2): error_log.append(f'{psd_name}:{config.error_log.psd_size_error.value}') titem_name = 'titem' tfull_name = 'tfull' tmask_name = 'tmask' tlight_name = 'tlight' tshadow_name = 'tshadow' group_name = 'group_' all_items = [] all_full = {} all_mask = [] all_tlight = [] all_tshadow = [] all_group = [] all_group_num = [] # all_color_it_full = [] # all_color_it_item = [] all_combination_full = {} all_combination_items = [] all_combination_mask = [] is_exist_base = False is_exist_titem_group = False all_occlusion_degree = [] for layer in psd: if ' ' in layer.name: error_log.append(f'{psd_name}:{layer.name}:{config.error_log.name_contains_spaces.value}') if layer.name == 'nouse' and layer.is_group(): continue if layer.name == titem_name and layer.is_group(): is_exist_titem_group = True for item_layer in layer: if ' ' in item_layer.name: error_log.append(f'{psd_name}:{item_layer.name}:{config.error_log.name_contains_spaces.value}') item_names = item_layer.name.split('_') last_name = item_names[-1] if titem_name in item_layer.name: if item_layer.name in all_items: ##or item_layer.name in all_color_it_item: error_log.append(f'{psd_name}:{item_layer.name}:{config.error_log.exit_repeat_layer.value}') elif int(last_name) >= 1000: all_combination_items.append(item_layer.name) else: # if 'titemcolor' in item_layer.name: # all_color_it_item.append(item_layer.name) # else: all_items.append(item_layer.name) else: error_log.append(f'{psd_name}:{item_layer.name}:{config.error_log.psd_item_name_error.value}') elif group_name in layer.name: try: group_num_str = layer.name.replace(group_name, "") group_num = int(group_num_str) except Exception as e: error_log.append(f'{psd_name}:{layer.name}:{config.error_log.group_name_error.value}') print(e) continue # if group_num <= 0 or group_num > psd_point_num: # error_log.append(f'{psd_name}:{layer.name}:{config.error_log.group_name_error.value}') # continue # else: all_group_num.append(group_num) if not layer.is_group(): error_log.append(f'{psd_name}:{layer.name}:{config.error_log.group_name_error.value}') elif layer.name in all_group: error_log.append(f'{psd_name}:{layer.name}:{config.error_log.exit_repeat_group.value}') else: all_group.append(layer.name) is_exit_full = False layer_names = layer.name.split('_') layer_last_name = layer_names[-1] for child_layer in layer: if group_num_str not in child_layer.name and int(layer_last_name) < 1000: error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.child_layer_not_in_group.value}') if child_layer.is_group(): error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.child_layer_is_group.value}') else: full_names = child_layer.name.split('_') last_name = full_names[-1] if tfull_name in child_layer.name: if child_layer.name in all_full.keys(): error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.exit_repeat_layer.value}') elif int(last_name) >= 1000: all_combination_full[child_layer.name] = (child_layer.left, child_layer.top, child_layer.width, child_layer.height) is_exit_full = True else: all_full[child_layer.name] = (child_layer.left, child_layer.top, child_layer.width, child_layer.height) is_exit_full = True elif tmask_name in child_layer.name: if child_layer.name in all_mask: error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.exit_repeat_layer.value}') elif int(last_name) >= 1000: all_combination_mask.append(child_layer.name) else: all_mask.append(child_layer.name) elif tshadow_name in child_layer.name: if child_layer.name in all_tshadow: error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.exit_repeat_layer.value}') else: all_tshadow.append(child_layer.name) elif tlight_name in child_layer.name: if child_layer.name in all_tlight: error_log.append(f'{psd_name}:{child_layer.name}:{config.error_log.exit_repeat_layer.value}') else: all_tlight.append(child_layer.name) else: error_log.append( f'{psd_name}:{child_layer.name}:{config.error_log.child_layer_unknown.value}') if not is_exit_full: error_log.append(f'{psd_name}:{layer.name}:{config.error_log.group_tfull_not_exit.value}') elif layer.name == 'base': if is_exist_base: error_log.append(f'{psd_name}:{config.error_log.exit_more_base.value}') else: is_exist_base = True else: error_log.append(f'{psd_name}:{layer.name}:{config.error_log.layer_not_need.value}') if not is_exist_base: error_log.append(f'{psd_name}:{config.error_log.psd_not_exit_base.value}') if not is_exist_titem_group: error_log.append(f'{psd_name}:{config.error_log.item_group_not_exit.value}') for i in range(1,psd_point_num + 1): if i not in all_group_num: error_log.append(f'{psd_name}:{i}:{config.error_log.group_lack.value}') all_item_count = len(all_items) if len(all_full) != all_item_count: #or ( len(all_color_it_item) != 0 and len(all_color_it_item) != all_item_count) or ( #len(all_color_it_full) != 0 and len(all_color_it_full) != all_item_count): error_log.append(f'{psd_name}:{config.error_log.item_or_full_num_error.value}') for item in all_items: full_name = item.replace('item', 'full') if full_name not in all_full.keys(): error_log.append(f'{psd_name}:{item}:{config.error_log.psd_not_full.value}') # if len(all_color_it_item) > 0 and len(all_color_it_full) > 0: # for item in all_items: # fullcolor_name = item.replace('item', 'fullcolor') # itemcolor_name = item.replace('item', 'itemcolor') # if fullcolor_name not in all_color_it_full: # error_log.append(f'{psd_name}:{item}:{config.error_log.psd_not_fullcolor.value}') # if itemcolor_name not in all_color_it_item: # error_log.append(f'{psd_name}:{item}:{config.error_log.psd_not_itemcolor.value}') # if not os.path.exists('./test'): # os.mkdir('./test') def find_layer_by_name(layers, target_name): """递归搜索图层中指定名称的图层""" for layer in layers: if layer.name == target_name: return layer if layer.is_group(): # 检查是否为组 found = find_layer_by_name(layer, target_name) if found: return found return None # 计算mask和full的遮罩百分比 for cur_mask in all_mask: # img_mask = psd.composite(layer_filter=lambda mask_layer: mask_layer.name == cur_mask) layer_mask = find_layer_by_name(psd,cur_mask) full_name = cur_mask.replace('mask', 'full') cur_full_rect = None if full_name in all_full.keys(): cur_full_rect = all_full[full_name] # img_full = psd.composite(layer_filter=lambda full_layer: full_layer.name == full_name) layer_full = find_layer_by_name(psd, full_name) if layer_mask is None or layer_full is None: error_log.append(f'{psd_name}:{cur_mask}:{config.error_log.not_find_mask_full.value}') break img_mask = psd.composite(layer_mask) img_full = psd.composite(layer_full) # img_mask.save(f'./test/{cur_mask}.png') # img_full.save(f'./test/{full_name}.png') per = get_item_mask_contact_ratio(img_full, img_mask, cur_full_rect) all_occlusion_degree.append(f'{cur_mask}遮挡{full_name}百分比:{per}\n') # print(f'{cur_mask}遮挡{full_name}百分比:{per}') else: error_log.append(f'{psd_name}:{cur_mask}:{config.error_log.psd_mask_not_full.value}') for cur_mask in all_combination_mask: # img_mask = psd.composite(layer_filter=lambda mask_layer: mask_layer.name == cur_mask) layer_mask = find_layer_by_name(psd, cur_mask) full_name = cur_mask.replace('mask', 'full') cur_full_rect = None if full_name in all_combination_full.keys(): cur_full_rect = all_combination_full[full_name] # img_full = psd.composite(layer_filter=lambda full_layer: full_layer.name == full_name) layer_full = find_layer_by_name(psd, full_name) if layer_mask is None or layer_full is None: error_log.append(f'{psd_name}:{cur_mask}:{config.error_log.not_find_mask_full.value}') break img_mask = psd.composite(layer_mask) img_full = psd.composite(layer_full) # img_mask.save(f'./test/{cur_mask}.png') # img_full.save(f'./test/{full_name}.png') per = get_item_mask_contact_ratio(img_full, img_mask, cur_full_rect) all_occlusion_degree.append(f'{cur_mask}遮挡{full_name}百分比:{per}\n') # print(f'{cur_mask}遮挡{full_name}百分比:{per}') else: error_log.append(f'{psd_name}:{cur_mask}:{config.error_log.psd_mask_not_full.value}') is_error = len(error_log) > 0 is_error_text = '否' if is_error else '是' if is_error: error_psd_dic[psd_name] = error_log log(f'{psd_name}:检测完毕,是否检测通过:{is_error_text}') for clog in error_log: log(clog) if not is_error: occlusion_degree_file_path = f'./OcclusionDegree/{psd_name}.txt' if not os.path.exists('./OcclusionDegree/'): os.mkdir('./OcclusionDegree/') if not os.path.exists(occlusion_degree_file_path): with open(occlusion_degree_file_path, 'w') as occlusion_degree_file: for text in all_occlusion_degree: occlusion_degree_file.writelines(text) pass return len(error_log) == 0 def get_item_mask_contact_ratio(full_image, mask_image, full_rect): # full_image = full_image.convert('RGBA') # mask_image = mask_image.convert('RGBA') x, y, w, h = full_rect full_pix_count = 0 mask_pix_count = 0 for cur_x in range(x, x + w): for cur_y in range(y, y + h): full_pix = full_image.getpixel((cur_x, cur_y)) mask_pix = mask_image.getpixel((cur_x, cur_y)) if not full_pix == (255, 255, 255, 0): full_pix_count += 1 if not mask_pix == (255, 255, 255, 0) and not mask_pix == full_pix: mask_pix_count += 1 # print(f'mask_pix_count::: {mask_pix_count}') # print(f'full_pix_count {full_pix_count}') percentage = "{:.2%}".format(float(mask_pix_count) / float(full_pix_count)) return percentage def log(content, new_line=True): curr_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) if new_line: print(curr_time + ' ' + content) else: print(curr_time + ' ' + content, end=' ') ###生成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) def convert_2_zip_file(path, is_name_end_zip=False): file_info_arr = os.path.split(path) file_path = file_info_arr[0] psd_name = os.path.split(path)[1].replace('.psd', '') psd_type = psd_name.split('_')[0] if is_name_end_zip: psd_path = os.path.join('./', file_info_arr[1]) os.chdir(file_path) # 检测成功,压缩到zip utils.zip_file(psd_path, f'./{psd_name}.zip') os.remove(psd_path) os.chdir('../') os.chdir('../') else: zip_out_path = os.path.join('./Level', psd_type) if not os.path.exists(zip_out_path): os.mkdir(zip_out_path) psd_path = os.path.join('./', file_info_arr[1]) os.chdir(file_path) # 检测成功,压缩到zip utils.zip_file(psd_path, f'../{zip_out_path}/{psd_name}.zip') os.remove(psd_path) os.chdir('../') def get_psd_color_mode(psd_path): with open(psd_path, "rb") as f: # 读取文件头信息 header = f.read(24) # 获取颜色模式字节 color_mode_byte = header[10] if color_mode_byte == 0: return "Bitmap" elif color_mode_byte == 2: return "RGB" elif color_mode_byte == 4: return "CMYK" else: return "Unknown" if __name__ == '__main__': global all_psd_count all_psd_count = 0 global pass_psd_count pass_psd_count = 0 global no_change_psd_count no_change_psd_count = 0 global error_psd_dic error_psd_dic = {} global zip_fail_count zip_fail_count = 0 global re_zip_count re_zip_count = 0 load_version() psd_name_list = [] is_force = sys.argv[1] if len(sys.argv) > 1 else False # is_force = True for root, dirs, files in os.walk('./'): for name in files: cur_file_path = os.path.join(root, name) if name.endswith('.psd'): all_psd_count += 1 if name.endswith('.psd') or name.endswith('.zip'): file_info_arr = os.path.split(cur_file_path) file_path = file_info_arr[0] psd_name = file_info_arr[1] if psd_name not in psd_name_list: psd_name_list.append(psd_name) else: log("存在重复名称关卡:{}".format(psd_name)) else: continue if name.endswith('.psd') or (name.endswith('.zip') and is_force): file_info_arr = os.path.split(cur_file_path) file_path = file_info_arr[0] psd_name = file_info_arr[1] hash_old = "" if psd_name in versions: hash_old = versions[psd_name] is_zip = name.endswith('.zip') if os.path.exists(cur_file_path): hash_now = "" if name.endswith('.psd'): hash_now = utils.calc_hash(cur_file_path) if hash_now != hash_old or is_force: psd_file_path = cur_file_path if is_zip: utils.unzip_file(cur_file_path) psd_file_path = "{}.psd".format(os.path.splitext(psd_file_path)[0]) hash_now = utils.calc_hash(psd_file_path) try: is_passed = check_psd(psd_file_path) if is_passed: # 检测成功,压缩到zip convert_2_zip_file(psd_file_path, is_zip) if is_zip: re_zip_count += 1 versions[psd_name] = hash_now write_version() if name.endswith('.psd'): pass_psd_count += 1 except Exception as e: zip_fail_count += 1 log(f'检测或者压缩失败::{psd_file_path},{e}') error_psd_dic[psd_name] = [f'{psd_file_path},{e}'] elif hash_now == hash_old: no_change_psd_count += 1 convert_2_zip_file(cur_file_path, is_zip) log(f'psd压缩完毕,总共psd数量:{all_psd_count}') log(f'成功压缩新增psd个数:{pass_psd_count}') log(f'成功压缩无改动psd个数:{no_change_psd_count}') log(f'未检测通过psd个数:{len(error_psd_dic)}') log(f'重新压缩psd数量:{re_zip_count}') log(f'压缩失败个数:{zip_fail_count}') if len(error_psd_dic) > 0: log(f'以下psd出现问题:') for error_psd_name, error_psd_log in error_psd_dic.items(): log(f'psd名称:{error_psd_name}') for error_log in error_psd_log: log(error_log)