#!/usr/bin/env python3
# coding=UTF-8

'''
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
readme: 此文件为 Python 界面，执行 python3 dev-shell.py 可查看
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'''

from tkinter import *
from tkinter import filedialog, messagebox
import os, subprocess, imghdr


# ----------------------- image -----------------------
class ImgHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        # 当前处理图片的类型
        self._handle_type = ''
        self._tip_msg = ''

    def create_app_icon(self):
        self._handle_type = 'ka'
        self._tip_msg = '提示：请选择一张图片生成所有尺寸 AppIcon，图片大小最好为 1024px x 1024px。'
        self.create_ui()

    def create_launch_image(self):
        self._handle_type = 'kb'
        self._tip_msg = '提示：请选择一张竖屏图片生成 LaunchImage，部分图片会变形，图片作为 Demo 测试用。'
        self.create_ui()

    def convert_2x3x(self):
        self._handle_type = 'kc'
        self._tip_msg = '提示：请选择想要转换为 2x 3x 图片的目录，一键为目录下所有图片生产 2x 3x 图片。'
        self.create_ui()

    def convert_png(self):
        self._handle_type = 'kd'
        self._tip_msg = '提示：请选择想要转换为 PNG 格式的图片目录，一键将目录下所有图片转换为 PNG 格式。'
        self.create_ui()

    # 创建界面
    def create_ui(self):
        img_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label = Label(img_frame, text=self._tip_msg, fg='DarkCyan')
        path_label = Label(img_frame, text='项目路径：', fg='black')

        # 选择项目路径按钮
        self._str_var.set('输入或者选择路径')

        path_input = Entry(img_frame, textvariable=self._str_var, width=field_width)
        select_path_btn = Button(img_frame, text='选择路径', command=self.select_path_btn_click)
        # 提交按钮
        sure_btn = Button(img_frame, text='确定', command=self.sure_btn_click)
        # 布局
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            file_path = filedialog.askopenfilename()
        else:
            file_path = filedialog.askdirectory()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        # 如果是图片，则判断图片格式
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            if not self.judge_img(dst_path):
                return

        # 如果是路径，判断路径合法性
        if self._handle_type == 'kc' or self._handle_type == 'kd':
            if not self.judge_path(dst_path):
                return

        # 判断 shell 脚本是否存在
        if not os.path.isfile('image-shell.sh'):
            messagebox.showinfo(title='提示', message='请将 image-shell.sh 文件拖到 python 脚本所在目录')
            return
        # 如果选择的是文件，则将文件名称和目录分开
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        if self._handle_type == 'ka':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path + ' && CreateIconImage ' + file_name)
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 IconFolder 文件夹中')
        elif self._handle_type == 'kb':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path + ' && CreateLaunchImage ' + file_name)
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 LaunchImageFolder 文件夹中')
        elif self._handle_type == 'kc':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path + ' && CreateXXImage')
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 XXFolder 文件夹中')
        elif self._handle_type == 'kd':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path + ' && ConvertAllToPng')
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 PngFolder 文件夹中')

    # 判断图片格式
    @staticmethod
    def judge_img(file_path):
        # 判断文件是否存在
        if not os.path.isfile(file_path):
            messagebox.showinfo(title='提示', message='文件不存在')
            return False
        # sips 支持的图片格式
        img_types_str = 'jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga'
        with open(file_path, 'rb') as img_file:
            img_type = imghdr.what(img_file)
            if img_type is None or img_type not in img_types_str:
                messagebox.showinfo(title='提示',
                                    message='不支持的图片格式\n支持的格式为 jpeg | tiff | png | gif'
                                            ' | jp2 | pict | bmp | qtif | psd | sgi | tga')
                return False
        return True

    # 判断路径
    @staticmethod
    def judge_path(dir_path):
        # 判断是否为路径
        if not os.path.isdir(dir_path):
            messagebox.showinfo(title='提示', message='路径不正确')
            return False
        return True


# ----------------------- Archive -----------------------
class ArchiveHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        # 工程输入框
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        # Debug/Release 单选结果
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        # scheme 输入框
        self._str_sche = StringVar()
        # ExportOptions.plist 所在路径
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        # ipa 文件输出路径
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        # 创建界面
        self.create_ui()
        # 判断 python 文件所在目录有无 shell 脚本
        if not os.path.isfile("auto-archive.sh"):
            messagebox.showinfo(title='提示', message='请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return

        # 获取默认值
        self.auto_defalut()

    # 自动获取默认值
    def auto_defalut(self):
        config_str = ". ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode " \
                     "&& echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path"
        config_proc = subprocess.Popen(config_str, shell=True, stdout=subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()

        # 读取路径
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()

        # 编译模式
        if cg_development_mode == "Debug":
            self._str_mode.set('Debug')

        # 读取 scheme
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)

        # 读取 ExportOptions.plist
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)

        # ipa 导出目录
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)

    # 在当前脚本目录下搜索
    def auto_read_proj(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.xcodeproj'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
            if file_name.endswith('.xcworkspace'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
                break
        temp_proj_str = self._str_proj.get()
        if len(temp_proj_str) > 0:
            self.auto_read_scheme()

    # 自动读取 scheme
    def auto_read_scheme(self):
        temp_proj_str = self._str_proj.get()
        temp_proj_dir = os.path.dirname(temp_proj_str)
        temp_proj_full_name = os.path.basename(temp_proj_str)
        proj_name, proj_ext = os.path.splitext(temp_proj_full_name)

        scheme_str = ". ./auto-archive.sh python " + "&& cd " + temp_proj_dir \
                     + " && FindScheme " + proj_name + " && echo $g_scheme_name"
        scheme_proc = subprocess.Popen(scheme_str, shell=True, stdout=subprocess.PIPE)
        scheme_out = scheme_proc.stdout.readlines()
        scheme_name = scheme_out[-1].decode('utf-8').strip()
        if len(scheme_name) > 0:
            self._str_sche.set(scheme_name)

    # 创建界面
    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label1 = Label(arch_frame, text="提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，\n"
                                            "            脚本会自动获取工程名称，scheme等信息。", fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text="提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。", fg='DarkCyan')
        tip_label3 = Label(arch_frame, text="提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。", fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)

        # 选择项目路径
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj, width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        
        # 选择 Debug/Release
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self._str_mode, text="Release",
                                          value="Release", command=self.mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode, text="Debug",
                                        value="Debug", command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)

        # scheme
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)

        # ExportOptions.plist 所在路径
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo, width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)

        # ipa 导出路径
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap, width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)

        # 提交按钮
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    # 选择项目文件路径
    def proj_path_btn_click(self):
        proj_file_path = filedialog.askopenfilename()
        self._str_proj.set(proj_file_path)
        if len(proj_file_path) > 0:
            self.auto_read_scheme()

    # 选择导出模式 Release
    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    # ExportOptions.plist 所在路径
    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    # ipa 导出路径
    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    # 确认按钮
    def sure_btn_click(self):
        if not os.path.isfile("auto-archive.sh"):
            messagebox.showinfo(title='提示', message='请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return

        # 读取输入框
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()

        # 判断工程路径是否存在
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return

        # 获取文件名称
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)

        # 判断 ExportOptions.plist 输入框是否为空
        if expo_str.strip() == "":
            expo_str = "ExportOptions.plist"
        # 判断项目目录下 ExportOptions.plist 是否存在，不存在创建
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system(". ./auto-archive.sh python && cd " + proj_path + " && CreateExportOptionsPlist " + expo_str)

        # BuildWorkspace  BuildProj
        if proj_ext == ".xcworkspace":
            arch_str = ". ./auto-archive.sh python && cd " + proj_path + " && BuildWorkspace " + proj_name + " " + mode_str \
                       + " " + sche_str + " " + expo_path + " " + ipaf_str + " && echo $g_current_time"
        else:
            arch_str = ". ./auto-archive.sh python && cd " + proj_path + " && BuildProj " + proj_name + " " + mode_str \
                       + " " + sche_str + " " + expo_path + " " + ipaf_str + " && echo $g_current_time"

        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        # ipa_folder="$proj_ipa_path/$proj_scheme$g_current_time"
        if len(arch_time) > 0:
            path_abs_str = "cd " + ipaf_str + " && pwd"
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True, stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + "/" + sche_str + ".ipa"
            # ipa 的绝对路径
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' + arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


# ----------------------- App 转 ipa -----------------------
class AppToIpaHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    # 在当前脚本目录下搜索
    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    # 创建界面
    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label = Label(app_frame, text="请选择后缀名为 .app 的文件", fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')

        # 选择项目路径按钮
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.select_path_btn_click)
        # 提交按钮
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        # 布局
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    # 选择 .app 文件
    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        # 判断是否是.app 文件
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return

        if not os.path.isfile("convert-ipa.sh"):
            messagebox.showinfo(title='提示', message='请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        # 如果选择的是文件，则将文件名称和目录分开
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path + ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path + '/IPAFolder 文件夹中')


# ----------------------- App -----------------------
class App:
    def __init__(self, master):
        self._master = master

        # 创建标题Verdana 10 bold
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black', bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black', bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg='black', bg='White', justify='right')

        # 创建按钮
        img_app_icon_btn = Button(master, text="生成 AppIcon", command=self.create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text="生成 LaunchImage", command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text="生成 2x 3x图片", command=self.create_2x3x_view, justify='left')
        img_png_btn = Button(master, text="图片转 PNG", command=self.create_png_view, justify='left')
        arch_btn = Button(master, text="自动化打包", command=self.create_archive_view, justify='left')
        ipa_btn = Button(master, text="app 转 ipa", command=self.create_app_ipa_view, justify='left')

        # 创建提示
        tip_app_icon_label = Label(master, text='一键缩放图片生成 App 所有尺寸 icon 图标。',
                                   fg='DarkCyan', bg='LightGray', justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
                                       fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
                               fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。',
                              fg='DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
                               fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text='将 command + b 编译的 .app 文件转成 ipa。',
                              fg='DarkCyan', bg='LightGray', justify='left')

        # 布局标题
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5, pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)

        # 布局按钮
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)

        # 布局提示
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    # 创建 AppIcon 的图标
    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


# ----------------------- Main -----------------------
if __name__ == '__main__':
    py_full_path = os.path.abspath(__file__)
    py_dir = os.path.dirname(py_full_path)
    os.chdir(py_dir)

    root_win = Tk()
    root_win.title('Shell 功能列表')
    root_sw = root_win.winfo_screenwidth()
    root_sh = root_win.winfo_screenheight()
    root_win.geometry('%dx%d+%d+%d' % (root_sw * 0.5, root_sh * 0.5, root_sw * 0.25, root_sh * 0.15))
    App(root_win)


dbe8eaedd057ef1e5656789da120a2b2d3b2eca8
<mask token>


class ArchiveHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        self._str_sche = StringVar()
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        self.create_ui()
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        self.auto_defalut()

    def auto_defalut(self):
        config_str = (
            '. ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode && echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path'
            )
        config_proc = subprocess.Popen(config_str, shell=True, stdout=
            subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()
        if cg_development_mode == 'Debug':
            self._str_mode.set('Debug')
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)
    <mask token>
    <mask token>

    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label1 = Label(arch_frame, text=
            """提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，
            脚本会自动获取工程名称，scheme等信息。"""
            , fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text=
            '提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。', fg='DarkCyan')
        tip_label3 = Label(arch_frame, text=
            '提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。', fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj,
            width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.
            proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self.
            _str_mode, text='Release', value='Release', command=self.
            mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode,
            text='Debug', value='Debug', command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=
            field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo,
            width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.
            expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap,
            width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.
            ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)
    <mask token>

    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    def sure_btn_click(self):
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)
        if expo_str.strip() == '':
            expo_str = 'ExportOptions.plist'
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system('. ./auto-archive.sh python && cd ' + proj_path +
                ' && CreateExportOptionsPlist ' + expo_str)
        if proj_ext == '.xcworkspace':
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildWorkspace ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        else:
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildProj ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=
            subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        if len(arch_time) > 0:
            path_abs_str = 'cd ' + ipaf_str + ' && pwd'
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True,
                stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + '/' + sche_str + '.ipa'
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' +
                    arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


class AppToIpaHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(app_frame, text='请选择后缀名为 .app 的文件', fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.
            select_path_btn_click)
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return
        if not os.path.isfile('convert-ipa.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path +
            ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path +
            '/IPAFolder 文件夹中')


class App:

    def __init__(self, master):
        self._master = master
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black',
            bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black',
            bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg=
            'black', bg='White', justify='right')
        img_app_icon_btn = Button(master, text='生成 AppIcon', command=self.
            create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text='生成 LaunchImage',
            command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text='生成 2x 3x图片', command=self.
            create_2x3x_view, justify='left')
        img_png_btn = Button(master, text='图片转 PNG', command=self.
            create_png_view, justify='left')
        arch_btn = Button(master, text='自动化打包', command=self.
            create_archive_view, justify='left')
        ipa_btn = Button(master, text='app 转 ipa', command=self.
            create_app_ipa_view, justify='left')
        tip_app_icon_label = Label(master, text=
            '一键缩放图片生成 App 所有尺寸 icon 图标。', fg='DarkCyan', bg='LightGray',
            justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。', fg=
            'DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text=
            '将 command + b 编译的 .app 文件转成 ipa。', fg='DarkCyan', bg=
            'LightGray', justify='left')
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5,
            pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


<mask token>

<mask token>


class ImgHandle:
    <mask token>
    <mask token>
    <mask token>
    <mask token>
    <mask token>

    def create_ui(self):
        img_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(img_frame, text=self._tip_msg, fg='DarkCyan')
        path_label = Label(img_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择路径')
        path_input = Entry(img_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(img_frame, text='选择路径', command=self.
            select_path_btn_click)
        sure_btn = Button(img_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)
    <mask token>

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            if not self.judge_img(dst_path):
                return
        if self._handle_type == 'kc' or self._handle_type == 'kd':
            if not self.judge_path(dst_path):
                return
        if not os.path.isfile('image-shell.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 image-shell.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        if self._handle_type == 'ka':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateIconImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 IconFolder 文件夹中')
        elif self._handle_type == 'kb':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateLaunchImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 LaunchImageFolder 文件夹中')
        elif self._handle_type == 'kc':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && CreateXXImage')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 XXFolder 文件夹中')
        elif self._handle_type == 'kd':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && ConvertAllToPng')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 PngFolder 文件夹中')
    <mask token>

    @staticmethod
    def judge_path(dir_path):
        if not os.path.isdir(dir_path):
            messagebox.showinfo(title='提示', message='路径不正确')
            return False
        return True


class ArchiveHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        self._str_sche = StringVar()
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        self.create_ui()
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        self.auto_defalut()

    def auto_defalut(self):
        config_str = (
            '. ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode && echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path'
            )
        config_proc = subprocess.Popen(config_str, shell=True, stdout=
            subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()
        if cg_development_mode == 'Debug':
            self._str_mode.set('Debug')
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)

    def auto_read_proj(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.xcodeproj'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
            if file_name.endswith('.xcworkspace'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
                break
        temp_proj_str = self._str_proj.get()
        if len(temp_proj_str) > 0:
            self.auto_read_scheme()

    def auto_read_scheme(self):
        temp_proj_str = self._str_proj.get()
        temp_proj_dir = os.path.dirname(temp_proj_str)
        temp_proj_full_name = os.path.basename(temp_proj_str)
        proj_name, proj_ext = os.path.splitext(temp_proj_full_name)
        scheme_str = ('. ./auto-archive.sh python ' + '&& cd ' +
            temp_proj_dir + ' && FindScheme ' + proj_name +
            ' && echo $g_scheme_name')
        scheme_proc = subprocess.Popen(scheme_str, shell=True, stdout=
            subprocess.PIPE)
        scheme_out = scheme_proc.stdout.readlines()
        scheme_name = scheme_out[-1].decode('utf-8').strip()
        if len(scheme_name) > 0:
            self._str_sche.set(scheme_name)

    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label1 = Label(arch_frame, text=
            """提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，
            脚本会自动获取工程名称，scheme等信息。"""
            , fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text=
            '提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。', fg='DarkCyan')
        tip_label3 = Label(arch_frame, text=
            '提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。', fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj,
            width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.
            proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self.
            _str_mode, text='Release', value='Release', command=self.
            mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode,
            text='Debug', value='Debug', command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=
            field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo,
            width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.
            expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap,
            width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.
            ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def proj_path_btn_click(self):
        proj_file_path = filedialog.askopenfilename()
        self._str_proj.set(proj_file_path)
        if len(proj_file_path) > 0:
            self.auto_read_scheme()

    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    def sure_btn_click(self):
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)
        if expo_str.strip() == '':
            expo_str = 'ExportOptions.plist'
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system('. ./auto-archive.sh python && cd ' + proj_path +
                ' && CreateExportOptionsPlist ' + expo_str)
        if proj_ext == '.xcworkspace':
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildWorkspace ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        else:
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildProj ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=
            subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        if len(arch_time) > 0:
            path_abs_str = 'cd ' + ipaf_str + ' && pwd'
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True,
                stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + '/' + sche_str + '.ipa'
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' +
                    arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


class AppToIpaHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(app_frame, text='请选择后缀名为 .app 的文件', fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.
            select_path_btn_click)
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return
        if not os.path.isfile('convert-ipa.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path +
            ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path +
            '/IPAFolder 文件夹中')


class App:

    def __init__(self, master):
        self._master = master
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black',
            bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black',
            bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg=
            'black', bg='White', justify='right')
        img_app_icon_btn = Button(master, text='生成 AppIcon', command=self.
            create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text='生成 LaunchImage',
            command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text='生成 2x 3x图片', command=self.
            create_2x3x_view, justify='left')
        img_png_btn = Button(master, text='图片转 PNG', command=self.
            create_png_view, justify='left')
        arch_btn = Button(master, text='自动化打包', command=self.
            create_archive_view, justify='left')
        ipa_btn = Button(master, text='app 转 ipa', command=self.
            create_app_ipa_view, justify='left')
        tip_app_icon_label = Label(master, text=
            '一键缩放图片生成 App 所有尺寸 icon 图标。', fg='DarkCyan', bg='LightGray',
            justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。', fg=
            'DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text=
            '将 command + b 编译的 .app 文件转成 ipa。', fg='DarkCyan', bg=
            'LightGray', justify='left')
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5,
            pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


<mask token>

<mask token>


class ImgHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self._handle_type = ''
        self._tip_msg = ''
    <mask token>

    def create_launch_image(self):
        self._handle_type = 'kb'
        self._tip_msg = '提示：请选择一张竖屏图片生成 LaunchImage，部分图片会变形，图片作为 Demo 测试用。'
        self.create_ui()

    def convert_2x3x(self):
        self._handle_type = 'kc'
        self._tip_msg = '提示：请选择想要转换为 2x 3x 图片的目录，一键为目录下所有图片生产 2x 3x 图片。'
        self.create_ui()

    def convert_png(self):
        self._handle_type = 'kd'
        self._tip_msg = '提示：请选择想要转换为 PNG 格式的图片目录，一键将目录下所有图片转换为 PNG 格式。'
        self.create_ui()

    def create_ui(self):
        img_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(img_frame, text=self._tip_msg, fg='DarkCyan')
        path_label = Label(img_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择路径')
        path_input = Entry(img_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(img_frame, text='选择路径', command=self.
            select_path_btn_click)
        sure_btn = Button(img_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            file_path = filedialog.askopenfilename()
        else:
            file_path = filedialog.askdirectory()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            if not self.judge_img(dst_path):
                return
        if self._handle_type == 'kc' or self._handle_type == 'kd':
            if not self.judge_path(dst_path):
                return
        if not os.path.isfile('image-shell.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 image-shell.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        if self._handle_type == 'ka':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateIconImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 IconFolder 文件夹中')
        elif self._handle_type == 'kb':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateLaunchImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 LaunchImageFolder 文件夹中')
        elif self._handle_type == 'kc':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && CreateXXImage')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 XXFolder 文件夹中')
        elif self._handle_type == 'kd':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && ConvertAllToPng')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 PngFolder 文件夹中')

    @staticmethod
    def judge_img(file_path):
        if not os.path.isfile(file_path):
            messagebox.showinfo(title='提示', message='文件不存在')
            return False
        img_types_str = (
            'jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga'
            )
        with open(file_path, 'rb') as img_file:
            img_type = imghdr.what(img_file)
            if img_type is None or img_type not in img_types_str:
                messagebox.showinfo(title='提示', message=
                    """不支持的图片格式
支持的格式为 jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga"""
                    )
                return False
        return True

    @staticmethod
    def judge_path(dir_path):
        if not os.path.isdir(dir_path):
            messagebox.showinfo(title='提示', message='路径不正确')
            return False
        return True


class ArchiveHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        self._str_sche = StringVar()
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        self.create_ui()
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        self.auto_defalut()

    def auto_defalut(self):
        config_str = (
            '. ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode && echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path'
            )
        config_proc = subprocess.Popen(config_str, shell=True, stdout=
            subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()
        if cg_development_mode == 'Debug':
            self._str_mode.set('Debug')
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)

    def auto_read_proj(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.xcodeproj'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
            if file_name.endswith('.xcworkspace'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
                break
        temp_proj_str = self._str_proj.get()
        if len(temp_proj_str) > 0:
            self.auto_read_scheme()

    def auto_read_scheme(self):
        temp_proj_str = self._str_proj.get()
        temp_proj_dir = os.path.dirname(temp_proj_str)
        temp_proj_full_name = os.path.basename(temp_proj_str)
        proj_name, proj_ext = os.path.splitext(temp_proj_full_name)
        scheme_str = ('. ./auto-archive.sh python ' + '&& cd ' +
            temp_proj_dir + ' && FindScheme ' + proj_name +
            ' && echo $g_scheme_name')
        scheme_proc = subprocess.Popen(scheme_str, shell=True, stdout=
            subprocess.PIPE)
        scheme_out = scheme_proc.stdout.readlines()
        scheme_name = scheme_out[-1].decode('utf-8').strip()
        if len(scheme_name) > 0:
            self._str_sche.set(scheme_name)

    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label1 = Label(arch_frame, text=
            """提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，
            脚本会自动获取工程名称，scheme等信息。"""
            , fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text=
            '提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。', fg='DarkCyan')
        tip_label3 = Label(arch_frame, text=
            '提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。', fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj,
            width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.
            proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self.
            _str_mode, text='Release', value='Release', command=self.
            mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode,
            text='Debug', value='Debug', command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=
            field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo,
            width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.
            expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap,
            width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.
            ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def proj_path_btn_click(self):
        proj_file_path = filedialog.askopenfilename()
        self._str_proj.set(proj_file_path)
        if len(proj_file_path) > 0:
            self.auto_read_scheme()

    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    def sure_btn_click(self):
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)
        if expo_str.strip() == '':
            expo_str = 'ExportOptions.plist'
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system('. ./auto-archive.sh python && cd ' + proj_path +
                ' && CreateExportOptionsPlist ' + expo_str)
        if proj_ext == '.xcworkspace':
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildWorkspace ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        else:
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildProj ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=
            subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        if len(arch_time) > 0:
            path_abs_str = 'cd ' + ipaf_str + ' && pwd'
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True,
                stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + '/' + sche_str + '.ipa'
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' +
                    arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


class AppToIpaHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(app_frame, text='请选择后缀名为 .app 的文件', fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.
            select_path_btn_click)
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return
        if not os.path.isfile('convert-ipa.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path +
            ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path +
            '/IPAFolder 文件夹中')


class App:

    def __init__(self, master):
        self._master = master
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black',
            bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black',
            bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg=
            'black', bg='White', justify='right')
        img_app_icon_btn = Button(master, text='生成 AppIcon', command=self.
            create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text='生成 LaunchImage',
            command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text='生成 2x 3x图片', command=self.
            create_2x3x_view, justify='left')
        img_png_btn = Button(master, text='图片转 PNG', command=self.
            create_png_view, justify='left')
        arch_btn = Button(master, text='自动化打包', command=self.
            create_archive_view, justify='left')
        ipa_btn = Button(master, text='app 转 ipa', command=self.
            create_app_ipa_view, justify='left')
        tip_app_icon_label = Label(master, text=
            '一键缩放图片生成 App 所有尺寸 icon 图标。', fg='DarkCyan', bg='LightGray',
            justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。', fg=
            'DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text=
            '将 command + b 编译的 .app 文件转成 ipa。', fg='DarkCyan', bg=
            'LightGray', justify='left')
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5,
            pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


<mask token>

<mask token>


class ImgHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self._handle_type = ''
        self._tip_msg = ''

    def create_app_icon(self):
        self._handle_type = 'ka'
        self._tip_msg = '提示：请选择一张图片生成所有尺寸 AppIcon，图片大小最好为 1024px x 1024px。'
        self.create_ui()

    def create_launch_image(self):
        self._handle_type = 'kb'
        self._tip_msg = '提示：请选择一张竖屏图片生成 LaunchImage，部分图片会变形，图片作为 Demo 测试用。'
        self.create_ui()

    def convert_2x3x(self):
        self._handle_type = 'kc'
        self._tip_msg = '提示：请选择想要转换为 2x 3x 图片的目录，一键为目录下所有图片生产 2x 3x 图片。'
        self.create_ui()

    def convert_png(self):
        self._handle_type = 'kd'
        self._tip_msg = '提示：请选择想要转换为 PNG 格式的图片目录，一键将目录下所有图片转换为 PNG 格式。'
        self.create_ui()

    def create_ui(self):
        img_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(img_frame, text=self._tip_msg, fg='DarkCyan')
        path_label = Label(img_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择路径')
        path_input = Entry(img_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(img_frame, text='选择路径', command=self.
            select_path_btn_click)
        sure_btn = Button(img_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            file_path = filedialog.askopenfilename()
        else:
            file_path = filedialog.askdirectory()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            if not self.judge_img(dst_path):
                return
        if self._handle_type == 'kc' or self._handle_type == 'kd':
            if not self.judge_path(dst_path):
                return
        if not os.path.isfile('image-shell.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 image-shell.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        if self._handle_type == 'ka':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateIconImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 IconFolder 文件夹中')
        elif self._handle_type == 'kb':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path +
                ' && CreateLaunchImage ' + file_name)
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 LaunchImageFolder 文件夹中')
        elif self._handle_type == 'kc':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && CreateXXImage')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 XXFolder 文件夹中')
        elif self._handle_type == 'kd':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path +
                ' && ConvertAllToPng')
            messagebox.showinfo(title='提示', message=
                '图片已经保存到图片目录下的 PngFolder 文件夹中')

    @staticmethod
    def judge_img(file_path):
        if not os.path.isfile(file_path):
            messagebox.showinfo(title='提示', message='文件不存在')
            return False
        img_types_str = (
            'jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga'
            )
        with open(file_path, 'rb') as img_file:
            img_type = imghdr.what(img_file)
            if img_type is None or img_type not in img_types_str:
                messagebox.showinfo(title='提示', message=
                    """不支持的图片格式
支持的格式为 jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga"""
                    )
                return False
        return True

    @staticmethod
    def judge_path(dir_path):
        if not os.path.isdir(dir_path):
            messagebox.showinfo(title='提示', message='路径不正确')
            return False
        return True


class ArchiveHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        self._str_sche = StringVar()
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        self.create_ui()
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        self.auto_defalut()

    def auto_defalut(self):
        config_str = (
            '. ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode && echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path'
            )
        config_proc = subprocess.Popen(config_str, shell=True, stdout=
            subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()
        if cg_development_mode == 'Debug':
            self._str_mode.set('Debug')
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)

    def auto_read_proj(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.xcodeproj'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
            if file_name.endswith('.xcworkspace'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
                break
        temp_proj_str = self._str_proj.get()
        if len(temp_proj_str) > 0:
            self.auto_read_scheme()

    def auto_read_scheme(self):
        temp_proj_str = self._str_proj.get()
        temp_proj_dir = os.path.dirname(temp_proj_str)
        temp_proj_full_name = os.path.basename(temp_proj_str)
        proj_name, proj_ext = os.path.splitext(temp_proj_full_name)
        scheme_str = ('. ./auto-archive.sh python ' + '&& cd ' +
            temp_proj_dir + ' && FindScheme ' + proj_name +
            ' && echo $g_scheme_name')
        scheme_proc = subprocess.Popen(scheme_str, shell=True, stdout=
            subprocess.PIPE)
        scheme_out = scheme_proc.stdout.readlines()
        scheme_name = scheme_out[-1].decode('utf-8').strip()
        if len(scheme_name) > 0:
            self._str_sche.set(scheme_name)

    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label1 = Label(arch_frame, text=
            """提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，
            脚本会自动获取工程名称，scheme等信息。"""
            , fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text=
            '提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。', fg='DarkCyan')
        tip_label3 = Label(arch_frame, text=
            '提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。', fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj,
            width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.
            proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self.
            _str_mode, text='Release', value='Release', command=self.
            mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode,
            text='Debug', value='Debug', command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=
            field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo,
            width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.
            expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap,
            width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.
            ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def proj_path_btn_click(self):
        proj_file_path = filedialog.askopenfilename()
        self._str_proj.set(proj_file_path)
        if len(proj_file_path) > 0:
            self.auto_read_scheme()

    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    def sure_btn_click(self):
        if not os.path.isfile('auto-archive.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)
        if expo_str.strip() == '':
            expo_str = 'ExportOptions.plist'
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system('. ./auto-archive.sh python && cd ' + proj_path +
                ' && CreateExportOptionsPlist ' + expo_str)
        if proj_ext == '.xcworkspace':
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildWorkspace ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        else:
            arch_str = ('. ./auto-archive.sh python && cd ' + proj_path +
                ' && BuildProj ' + proj_name + ' ' + mode_str + ' ' +
                sche_str + ' ' + expo_path + ' ' + ipaf_str +
                ' && echo $g_current_time')
        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=
            subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        if len(arch_time) > 0:
            path_abs_str = 'cd ' + ipaf_str + ' && pwd'
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True,
                stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + '/' + sche_str + '.ipa'
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' +
                    arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


class AppToIpaHandle:

    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        tip_label = Label(app_frame, text='请选择后缀名为 .app 的文件', fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=
            field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.
            select_path_btn_click)
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1,
            columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width,
            rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return
        if not os.path.isfile('convert-ipa.sh'):
            messagebox.showinfo(title='提示', message=
                '请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path +
            ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path +
            '/IPAFolder 文件夹中')


class App:

    def __init__(self, master):
        self._master = master
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black',
            bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black',
            bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg=
            'black', bg='White', justify='right')
        img_app_icon_btn = Button(master, text='生成 AppIcon', command=self.
            create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text='生成 LaunchImage',
            command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text='生成 2x 3x图片', command=self.
            create_2x3x_view, justify='left')
        img_png_btn = Button(master, text='图片转 PNG', command=self.
            create_png_view, justify='left')
        arch_btn = Button(master, text='自动化打包', command=self.
            create_archive_view, justify='left')
        ipa_btn = Button(master, text='app 转 ipa', command=self.
            create_app_ipa_view, justify='left')
        tip_app_icon_label = Label(master, text=
            '一键缩放图片生成 App 所有尺寸 icon 图标。', fg='DarkCyan', bg='LightGray',
            justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。', fg=
            'DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
            fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text=
            '将 command + b 编译的 .app 文件转成 ipa。', fg='DarkCyan', bg=
            'LightGray', justify='left')
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5,
            pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()
        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


if __name__ == '__main__':
    py_full_path = os.path.abspath(__file__)
    py_dir = os.path.dirname(py_full_path)
    os.chdir(py_dir)
    root_win = Tk()
    root_win.title('Shell 功能列表')
    root_sw = root_win.winfo_screenwidth()
    root_sh = root_win.winfo_screenheight()
    root_win.geometry('%dx%d+%d+%d' % (root_sw * 0.5, root_sh * 0.5, 
        root_sw * 0.25, root_sh * 0.15))
    App(root_win)

#!/usr/bin/env python3
# coding=UTF-8

'''
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
readme: 此文件为 Python 界面，执行 python3 dev-shell.py 可查看
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'''

from tkinter import *
from tkinter import filedialog, messagebox
import os, subprocess, imghdr


# ----------------------- image -----------------------
class ImgHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        # 当前处理图片的类型
        self._handle_type = ''
        self._tip_msg = ''

    def create_app_icon(self):
        self._handle_type = 'ka'
        self._tip_msg = '提示：请选择一张图片生成所有尺寸 AppIcon，图片大小最好为 1024px x 1024px。'
        self.create_ui()

    def create_launch_image(self):
        self._handle_type = 'kb'
        self._tip_msg = '提示：请选择一张竖屏图片生成 LaunchImage，部分图片会变形，图片作为 Demo 测试用。'
        self.create_ui()

    def convert_2x3x(self):
        self._handle_type = 'kc'
        self._tip_msg = '提示：请选择想要转换为 2x 3x 图片的目录，一键为目录下所有图片生产 2x 3x 图片。'
        self.create_ui()

    def convert_png(self):
        self._handle_type = 'kd'
        self._tip_msg = '提示：请选择想要转换为 PNG 格式的图片目录，一键将目录下所有图片转换为 PNG 格式。'
        self.create_ui()

    # 创建界面
    def create_ui(self):
        img_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label = Label(img_frame, text=self._tip_msg, fg='DarkCyan')
        path_label = Label(img_frame, text='项目路径：', fg='black')

        # 选择项目路径按钮
        self._str_var.set('输入或者选择路径')

        path_input = Entry(img_frame, textvariable=self._str_var, width=field_width)
        select_path_btn = Button(img_frame, text='选择路径', command=self.select_path_btn_click)
        # 提交按钮
        sure_btn = Button(img_frame, text='确定', command=self.sure_btn_click)
        # 布局
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    def select_path_btn_click(self):
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            file_path = filedialog.askopenfilename()
        else:
            file_path = filedialog.askdirectory()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        # 如果是图片，则判断图片格式
        if self._handle_type == 'ka' or self._handle_type == 'kb':
            if not self.judge_img(dst_path):
                return

        # 如果是路径，判断路径合法性
        if self._handle_type == 'kc' or self._handle_type == 'kd':
            if not self.judge_path(dst_path):
                return

        # 判断 shell 脚本是否存在
        if not os.path.isfile('image-shell.sh'):
            messagebox.showinfo(title='提示', message='请将 image-shell.sh 文件拖到 python 脚本所在目录')
            return
        # 如果选择的是文件，则将文件名称和目录分开
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        if self._handle_type == 'ka':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path + ' && CreateIconImage ' + file_name)
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 IconFolder 文件夹中')
        elif self._handle_type == 'kb':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dir_path + ' && CreateLaunchImage ' + file_name)
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 LaunchImageFolder 文件夹中')
        elif self._handle_type == 'kc':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path + ' && CreateXXImage')
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 XXFolder 文件夹中')
        elif self._handle_type == 'kd':
            os.system('. ./image-shell.sh python ' + '&& cd ' + dst_path + ' && ConvertAllToPng')
            messagebox.showinfo(title='提示', message='图片已经保存到图片目录下的 PngFolder 文件夹中')

    # 判断图片格式
    @staticmethod
    def judge_img(file_path):
        # 判断文件是否存在
        if not os.path.isfile(file_path):
            messagebox.showinfo(title='提示', message='文件不存在')
            return False
        # sips 支持的图片格式
        img_types_str = 'jpeg | tiff | png | gif | jp2 | pict | bmp | qtif | psd | sgi | tga'
        with open(file_path, 'rb') as img_file:
            img_type = imghdr.what(img_file)
            if img_type is None or img_type not in img_types_str:
                messagebox.showinfo(title='提示',
                                    message='不支持的图片格式\n支持的格式为 jpeg | tiff | png | gif'
                                            ' | jp2 | pict | bmp | qtif | psd | sgi | tga')
                return False
        return True

    # 判断路径
    @staticmethod
    def judge_path(dir_path):
        # 判断是否为路径
        if not os.path.isdir(dir_path):
            messagebox.showinfo(title='提示', message='路径不正确')
            return False
        return True


# ----------------------- Archive -----------------------
class ArchiveHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        # 工程输入框
        self._str_proj = StringVar()
        self._str_proj.set('输入或者选择后缀名为 .xcworkspace 或 .xcodeproj 的文件路径')
        # Debug/Release 单选结果
        self._str_mode = StringVar()
        self._str_mode.set('Release')
        # scheme 输入框
        self._str_sche = StringVar()
        # ExportOptions.plist 所在路径
        self._str_expo = StringVar()
        self._str_expo.set('ExportOptions.plist')
        # ipa 文件输出路径
        self._str_ipap = StringVar()
        self._str_ipap.set('~/Desktop/auto-ipa')
        # 创建界面
        self.create_ui()
        # 判断 python 文件所在目录有无 shell 脚本
        if not os.path.isfile("auto-archive.sh"):
            messagebox.showinfo(title='提示', message='请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return

        # 获取默认值
        self.auto_defalut()

    # 自动获取默认值
    def auto_defalut(self):
        config_str = ". ./auto-archive.sh python && echo $g_project_name && echo $g_development_mode " \
                     "&& echo $g_scheme_name && echo $g_export_options && echo $g_ipa_path"
        config_proc = subprocess.Popen(config_str, shell=True, stdout=subprocess.PIPE)
        config_out = config_proc.stdout.readlines()
        if len(config_out) < 5:
            return
        cg_project_name = config_out[-5].decode('utf-8').strip()
        cg_development_mode = config_out[-4].decode('utf-8').strip()
        cg_scheme_name = config_out[-3].decode('utf-8').strip()
        cg_export_options = config_out[-2].decode('utf-8').strip()
        cg_ipa_path = config_out[-1].decode('utf-8').strip()

        # 读取路径
        if len(cg_project_name) > 0:
            self._str_proj.set(cg_project_name)
        else:
            self.auto_read_proj()

        # 编译模式
        if cg_development_mode == "Debug":
            self._str_mode.set('Debug')

        # 读取 scheme
        if len(cg_scheme_name) > 0:
            self._str_sche.set(cg_scheme_name)

        # 读取 ExportOptions.plist
        if len(cg_export_options) > 0:
            self._str_expo.set(cg_export_options)

        # ipa 导出目录
        if len(cg_ipa_path) > 0:
            self._str_ipap.set(cg_ipa_path)

    # 在当前脚本目录下搜索
    def auto_read_proj(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.xcodeproj'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
            if file_name.endswith('.xcworkspace'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_proj.set(temp_full_path)
                break
        temp_proj_str = self._str_proj.get()
        if len(temp_proj_str) > 0:
            self.auto_read_scheme()

    # 自动读取 scheme
    def auto_read_scheme(self):
        temp_proj_str = self._str_proj.get()
        temp_proj_dir = os.path.dirname(temp_proj_str)
        temp_proj_full_name = os.path.basename(temp_proj_str)
        proj_name, proj_ext = os.path.splitext(temp_proj_full_name)

        scheme_str = ". ./auto-archive.sh python " + "&& cd " + temp_proj_dir \
                     + " && FindScheme " + proj_name + " && echo $g_scheme_name"
        scheme_proc = subprocess.Popen(scheme_str, shell=True, stdout=subprocess.PIPE)
        scheme_out = scheme_proc.stdout.readlines()
        scheme_name = scheme_out[-1].decode('utf-8').strip()
        if len(scheme_name) > 0:
            self._str_sche.set(scheme_name)

    # 创建界面
    def create_ui(self):
        arch_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label1 = Label(arch_frame, text="提示1：将 dev-shell.py，auto-archive.sh 复制到与.xcodeproj同级目录下，\n"
                                            "            脚本会自动获取工程名称，scheme等信息。", fg='DarkCyan', justify='left')
        tip_label2 = Label(arch_frame, text="提示2：自动获取不正确请修改或配置 auto-archive.sh 中全局变量。", fg='DarkCyan')
        tip_label3 = Label(arch_frame, text="提示3：配置文件 ExportOptions.plist 不配置会自动检测创建。", fg='DarkCyan')
        tip_label1.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        tip_label2.grid(row=1, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        tip_label3.grid(row=2, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)

        # 选择项目路径
        proj_path_label = Label(arch_frame, text='项目路径：', fg='black')
        proj_path_input = Entry(arch_frame, textvariable=self._str_proj, width=field_width)
        proj_path_btn = Button(arch_frame, text='选择文件', command=self.proj_path_btn_click)
        proj_path_label.grid(row=10, column=0, padx=5, pady=5)
        proj_path_input.grid(row=10, column=1, padx=5, pady=5)
        proj_path_btn.grid(row=10, column=2, padx=5, pady=5)
        
        # 选择 Debug/Release
        mode_label = Label(arch_frame, text='编译模式：', fg='black')
        mode_frame = Frame(arch_frame)
        model_release_radio = Radiobutton(mode_frame, variable=self._str_mode, text="Release",
                                          value="Release", command=self.mode_radio_click)
        model_debug_radio = Radiobutton(mode_frame, variable=self._str_mode, text="Debug",
                                        value="Debug", command=self.mode_radio_click)
        mode_label.grid(row=11, column=0, padx=5, pady=5)
        mode_frame.grid(row=11, column=1, padx=5, pady=5, sticky=W)
        model_release_radio.pack(anchor=W, side=LEFT)
        model_debug_radio.pack(anchor=W, side=LEFT)

        # scheme
        sche_label = Label(arch_frame, text='Scheme：', fg='black')
        sche_input = Entry(arch_frame, textvariable=self._str_sche, width=field_width)
        sche_label.grid(row=12, column=0, padx=5, pady=5)
        sche_input.grid(row=12, column=1, padx=5, pady=5)

        # ExportOptions.plist 所在路径
        expo_path_label = Label(arch_frame, text='配置文件：', fg='black')
        expo_path_input = Entry(arch_frame, textvariable=self._str_expo, width=field_width)
        expo_path_btn = Button(arch_frame, text='选择文件', command=self.expo_path_btn_click)
        expo_path_label.grid(row=13, column=0, padx=5, pady=5)
        expo_path_input.grid(row=13, column=1, padx=5, pady=5)
        expo_path_btn.grid(row=13, column=2, padx=5, pady=5)

        # ipa 导出路径
        ipa_path_label = Label(arch_frame, text='ipa路径：', fg='black')
        ipa_path_input = Entry(arch_frame, textvariable=self._str_ipap, width=field_width)
        ipa_path_btn = Button(arch_frame, text='选择路径', command=self.ipa_path_btn_click)
        ipa_path_label.grid(row=14, column=0, padx=5, pady=5)
        ipa_path_input.grid(row=14, column=1, padx=5, pady=5)
        ipa_path_btn.grid(row=14, column=2, padx=5, pady=5)

        # 提交按钮
        sure_btn = Button(arch_frame, text='确定', command=self.sure_btn_click)
        sure_btn.grid(row=15, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    # 选择项目文件路径
    def proj_path_btn_click(self):
        proj_file_path = filedialog.askopenfilename()
        self._str_proj.set(proj_file_path)
        if len(proj_file_path) > 0:
            self.auto_read_scheme()

    # 选择导出模式 Release
    def mode_radio_click(self):
        mode_str = self._str_mode.get()
        print(mode_str)

    # ExportOptions.plist 所在路径
    def expo_path_btn_click(self):
        expo_file_path = filedialog.askopenfilename()
        self._str_expo.set(expo_file_path)

    # ipa 导出路径
    def ipa_path_btn_click(self):
        ipa_folder_path = filedialog.askdirectory()
        self._str_ipap.set(ipa_folder_path)

    # 确认按钮
    def sure_btn_click(self):
        if not os.path.isfile("auto-archive.sh"):
            messagebox.showinfo(title='提示', message='请将 auto-archive.sh 文件拖到 python 脚本所在目录')
            return

        # 读取输入框
        proj_str = self._str_proj.get()
        mode_str = self._str_mode.get()
        sche_str = self._str_sche.get()
        expo_str = self._str_expo.get()
        ipaf_str = self._str_ipap.get()

        # 判断工程路径是否存在
        if not os.path.isdir(proj_str):
            messagebox.showinfo(title='提示', message='工程文件不存在，请从新选择')
            return

        # 获取文件名称
        proj_full_name = os.path.basename(proj_str)
        proj_path = os.path.dirname(proj_str)
        proj_name, proj_ext = os.path.splitext(proj_full_name)

        # 判断 ExportOptions.plist 输入框是否为空
        if expo_str.strip() == "":
            expo_str = "ExportOptions.plist"
        # 判断项目目录下 ExportOptions.plist 是否存在，不存在创建
        expo_path = os.path.join(proj_path, expo_str)
        if not os.path.isfile(expo_path):
            os.system(". ./auto-archive.sh python && cd " + proj_path + " && CreateExportOptionsPlist " + expo_str)

        # BuildWorkspace  BuildProj
        if proj_ext == ".xcworkspace":
            arch_str = ". ./auto-archive.sh python && cd " + proj_path + " && BuildWorkspace " + proj_name + " " + mode_str \
                       + " " + sche_str + " " + expo_path + " " + ipaf_str + " && echo $g_current_time"
        else:
            arch_str = ". ./auto-archive.sh python && cd " + proj_path + " && BuildProj " + proj_name + " " + mode_str \
                       + " " + sche_str + " " + expo_path + " " + ipaf_str + " && echo $g_current_time"

        arch_proc = subprocess.Popen(arch_str, shell=True, stdout=subprocess.PIPE)
        arch_out = arch_proc.stdout.readlines()
        arch_time = arch_out[-1].decode('utf-8').strip()
        # ipa_folder="$proj_ipa_path/$proj_scheme$g_current_time"
        if len(arch_time) > 0:
            path_abs_str = "cd " + ipaf_str + " && pwd"
            path_abs_proc = subprocess.Popen(path_abs_str, shell=True, stdout=subprocess.PIPE)
            path_abs_out = path_abs_proc.stdout.readlines()
            path_abs = path_abs_out[-1].decode('utf-8').strip()
            arch_ipa_path = sche_str + arch_time + "/" + sche_str + ".ipa"
            # ipa 的绝对路径
            arch_ipa_full_path = os.path.join(path_abs, arch_ipa_path)
            if os.path.isfile(arch_ipa_full_path):
                arch_ipa_dir = os.path.dirname(arch_ipa_full_path)
                messagebox.showinfo(title='提示', message='打包成功，ipa 文件路径：\n' + arch_ipa_dir)
            else:
                messagebox.showinfo(title='提示', message='打包失败，请检查项目')


# ----------------------- App 转 ipa -----------------------
class AppToIpaHandle:
    def __init__(self, master):
        self._master = master
        self._frame = Frame(master)
        self._frame.grid()
        self._str_var = StringVar()
        self.create_ui()
        self.auto_find_app()

    # 在当前脚本目录下搜索
    def auto_find_app(self):
        py_dir = os.getcwd()
        file_list = os.listdir(py_dir)
        for file_name in file_list:
            if file_name.endswith('.app'):
                temp_full_path = os.path.join(py_dir, file_name)
                self._str_var.set(temp_full_path)
                break

    # 创建界面
    def create_ui(self):
        app_frame = self._frame
        field_width = 40
        pad_width = 35
        # 提示
        tip_label = Label(app_frame, text="请选择后缀名为 .app 的文件", fg='DarkCyan')
        path_label = Label(app_frame, text='项目路径：', fg='black')

        # 选择项目路径按钮
        self._str_var.set('输入或者选择 .app 文件路径')
        path_input = Entry(app_frame, textvariable=self._str_var, width=field_width)
        select_path_btn = Button(app_frame, text='选择文件', command=self.select_path_btn_click)
        # 提交按钮
        sure_btn = Button(app_frame, text='确定', command=self.sure_btn_click)
        # 布局
        tip_label.grid(row=0, column=0, padx=5, pady=5, rowspan=1, columnspan=3, sticky=W)
        path_label.grid(row=1, column=0, padx=5, pady=5)
        path_input.grid(row=1, column=1, padx=5, pady=5)
        select_path_btn.grid(row=1, column=2, padx=5, pady=5)
        sure_btn.grid(row=3, column=0, padx=pad_width, pady=pad_width, rowspan=2, columnspan=3, sticky=NSEW)

    # 选择 .app 文件
    def select_path_btn_click(self):
        file_path = filedialog.askopenfilename()
        if len(file_path) > 0:
            self._str_var.set(file_path)

    def sure_btn_click(self):
        dst_path = self._str_var.get()
        # 判断是否是.app 文件
        if not dst_path.endswith('.app'):
            messagebox.showinfo(title='提示', message='请选择 .app 文件')
            return

        if not os.path.isfile("convert-ipa.sh"):
            messagebox.showinfo(title='提示', message='请将 convert-ipa.sh 文件拖到 python 脚本所在目录')
            return
        # 如果选择的是文件，则将文件名称和目录分开
        file_name = os.path.basename(dst_path)
        dir_path = os.path.dirname(dst_path)
        os.system('. ./convert-ipa.sh python ' + '&& cd ' + dir_path + ' && AppToIpa ' + file_name)
        messagebox.showinfo(title='提示', message='图片已经保存' + dir_path + '/IPAFolder 文件夹中')


# ----------------------- App -----------------------
class App:
    def __init__(self, master):
        self._master = master

        # 创建标题Verdana 10 bold
        img_label = Label(master, text='图片批处理', font='宋体 23', fg='black', bg='White', justify='right')
        arch_label = Label(master, text='自动化打包', font='宋体 23', fg='black', bg='White', justify='right')
        ipa_label = Label(master, text='.app 转 .ipa', font='宋体 23', fg='black', bg='White', justify='right')

        # 创建按钮
        img_app_icon_btn = Button(master, text="生成 AppIcon", command=self.create_icon_view, justify='left')
        img_launch_image_btn = Button(master, text="生成 LaunchImage", command=self.create_launch_view, justify='left')
        img_2x3x_btn = Button(master, text="生成 2x 3x图片", command=self.create_2x3x_view, justify='left')
        img_png_btn = Button(master, text="图片转 PNG", command=self.create_png_view, justify='left')
        arch_btn = Button(master, text="自动化打包", command=self.create_archive_view, justify='left')
        ipa_btn = Button(master, text="app 转 ipa", command=self.create_app_ipa_view, justify='left')

        # 创建提示
        tip_app_icon_label = Label(master, text='一键缩放图片生成 App 所有尺寸 icon 图标。',
                                   fg='DarkCyan', bg='LightGray', justify='left')
        tip_launch_image_label = Label(master, text='一键缩放图片生成 App 所需启动图。',
                                       fg='DarkCyan', bg='LightGray', justify='left')
        tip_2x3x_label = Label(master, text='一键将文件夹内图片生成 2x/3x 图片并自动重命名。',
                               fg='DarkCyan', bg='LightGray', justify='left')
        tip_png_label = Label(master, text='一键将文件夹内所有图片转为 PNG 格式。',
                              fg='DarkCyan', bg='LightGray', justify='left')
        tip_arch_label = Label(master, text='利用 xcode build 指令将项目打包为 ipa。',
                               fg='DarkCyan', bg='LightGray', justify='left')
        tip_ipa_label = Label(master, text='将 command + b 编译的 .app 文件转成 ipa。',
                              fg='DarkCyan', bg='LightGray', justify='left')

        # 布局标题
        img_label.grid(row=0, column=0, rowspan=4, columnspan=1, padx=5, pady=5, sticky=NSEW)
        arch_label.grid(row=4, column=0, padx=5, pady=5, sticky=NSEW)
        ipa_label.grid(row=5, column=0, padx=5, pady=5, sticky=NSEW)

        # 布局按钮
        img_app_icon_btn.grid(row=0, column=1, padx=5, pady=5, sticky=NSEW)
        img_launch_image_btn.grid(row=1, column=1, padx=5, pady=5, sticky=NSEW)
        img_2x3x_btn.grid(row=2, column=1, padx=5, pady=5, sticky=NSEW)
        img_png_btn.grid(row=3, column=1, padx=5, pady=5, sticky=NSEW)
        arch_btn.grid(row=4, column=1, padx=5, pady=5, sticky=NSEW)
        ipa_btn.grid(row=5, column=1, padx=5, pady=5, sticky=NSEW)

        # 布局提示
        tip_app_icon_label.grid(row=0, column=2, padx=5, pady=5, sticky=W)
        tip_launch_image_label.grid(row=1, column=2, padx=5, pady=5, sticky=W)
        tip_2x3x_label.grid(row=2, column=2, padx=5, pady=5, sticky=W)
        tip_png_label.grid(row=3, column=2, padx=5, pady=5, sticky=W)
        tip_arch_label.grid(row=4, column=2, padx=5, pady=5, sticky=W)
        tip_ipa_label.grid(row=5, column=2, padx=5, pady=5, sticky=W)
        master.mainloop()

    # 创建 AppIcon 的图标
    def create_icon_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_app_icon()

    def create_launch_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).create_launch_image()

    def create_2x3x_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_2x3x()

    def create_png_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        img_win = Toplevel(self._master)
        img_win.title('图片处理')
        img_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ImgHandle(img_win).convert_png()

    def create_archive_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        arch_win = Toplevel(self._master)
        arch_win.title('自动化打包')
        arch_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        ArchiveHandle(arch_win)

    def create_app_ipa_view(self):
        xx = self._master.winfo_x()
        yy = self._master.winfo_y()
        hh = self._master.winfo_height()
        ww = self._master.winfo_width()

        ipa_win = Toplevel(self._master)
        ipa_win.title('app 转 ipa')
        ipa_win.geometry('%dx%d+%d+%d' % (ww, hh, xx, yy))
        AppToIpaHandle(ipa_win)


# ----------------------- Main -----------------------
if __name__ == '__main__':
    py_full_path = os.path.abspath(__file__)
    py_dir = os.path.dirname(py_full_path)
    os.chdir(py_dir)

    root_win = Tk()
    root_win.title('Shell 功能列表')
    root_sw = root_win.winfo_screenwidth()
    root_sh = root_win.winfo_screenheight()
    root_win.geometry('%dx%d+%d+%d' % (root_sw * 0.5, root_sh * 0.5, root_sw * 0.25, root_sh * 0.15))
    App(root_win)

