用来快速合并贴图
前言
忽然接到一个需求 写一个 PS 的工具。 自动合并图片序列的通道。
之前写过一个 PS 的小脚本,10-20 行的。 解决了 PS 动作进行批处理保存贴图,输出的时候却带有副本的名称。 用脚本替换掉动作的输出,就可以保存出不带 副本 字样的图片。
但是感受了这次给的需求,做 PS 的工具感觉不太香,如果不是 立足 于 PS 的环境,做 PS 的脚本其实并不是好方案。 毕竟 Python 也有 cv 和 PIL 等等的图像处理库,直接 Python 来处理那不香吗~
github 地址
GUI 开发
这次界面依然选择了 Tkinter 进行开发,因为最近做 Bilibili 字幕上传工具。 我发现 Tkinter 用得好也可以实现和 PyQt 差不多的界面效果,但是 Tkinter 打包起来比起 Qt 可小了很多。
因为有了之前搞 Tkinter 工具经验,这次开发就很快了,毕竟需求不复杂界面也相对简单。
这次依然利用之前搞过的 ConfigDumperMixin 类,实现 GUI 界面的数据记录。 然后统一数据之后将数据存储到 临时目录里面。
关于进度条处理,这里使用了之前写好的进度条类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class ProgressDialog (tk.Toplevel): canceled = False def __init__ (self, *args, **kwargs ): self.parent = kwargs.pop("parent" , None ) tk.Toplevel.__init__(self, self.parent, *args, **kwargs) self.grab_set() self.progress = ttk.Progressbar( self, orient=tk.HORIZONTAL, length=100 , mode="determinate" ) self.progress.pack(side="top" , fill="x" , expand=1 , padx=5 , pady=5 ) self.button = tk.Button( self, text="Cancel" , command=lambda : [None for self.canceled in [True ]] ) self.button.pack() @classmethod def loop (cls, seq, **kwargs ): self = cls(**kwargs) maximum = len (seq) for i, item in enumerate (seq): if self.canceled: break try : yield i, item except : import traceback traceback.print_exc() self.destroy() self.progress["value" ] = i / maximum * 100 self.update() self.destroy()
用 classmethod 方便实例化对象 通过 yield 实现迭代器直接直接放到 for 循环里面使用~
图像处理
图像处理上使用的是简单 Pillow PIL 图像库。 其实混合通道不难,可以晚上搜索一下,又很多文章 链接 我这里只是读取两个目录里图片的序号批量匹配,然后融合通道之后批量根据序号进行输出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 @error_log def img_combine (self ): output_path = self.output_path.get() input_path_1 = self.input_path_1.get() input_path_2 = self.input_path_2.get() if not os.path.exists(output_path): self.output_path.set ("" ) messagebox.showwarning("警告" , "输出路径不存在" ) return elif not os.path.exists(input_path_1): self.self.input_path_1.set ("" ) messagebox.showwarning("警告" , "第一种贴图路径不存在" ) return elif not os.path.exists(input_path_2): self.input_path_2.set ("" ) messagebox.showwarning("警告" , "第二种贴图路径不存在" ) return regx = re.compile (r".*?(\d+)\..*?$" ) input_path_1_dict = { regx.search(f).group(1 ): os.path.join(input_path_1, f) for f in os.listdir(input_path_1) if regx.search(f) } for i, img in ProgressDialog.loop(os.listdir(input_path_2)): match = regx.search(img) if not match : continue num = match .group(1 ) img_1 = input_path_1_dict.get(num, "" ) img_2 = os.path.join(input_path_2, img) if not os.path.exists(img_1): continue img_1 = Image.open (img_1).convert("RGBA" ) img_2 = Image.open (img_2).convert("RGBA" ) r_1, g_1, b_1, a_1 = img_1.split() r_2, g_2, b_2, a_2 = img_2.split() R = r_1 if self.R.get() == "1" else r_2 G = g_1 if self.G.get() == "1" else g_2 B = b_1 if self.B.get() == "1" else b_2 A = a_1 if self.A.get() == "1" else a_2 image = Image.merge("RGBA" , [R, G, B, A]) img = os.path.splitext(img)[0 ] ext = self.image_extension.get() image.save(os.path.join(output_path, f"{img} .{ext} " )) messagebox.showinfo("恭喜您" , "合并完成" ) subprocess.Popen(["start" , "" , output_path], shell=True )
总结
这个工具的功能不复杂,一个早上就写完了。 简单记录一下。
补充 2020-12-30
混合通道使用 imagemagick 命令行高效秒杀这个需求。
分离 合并