PIL提供了一个功能强大的库,可以转变原始图片格式,尺寸(可以不按比例放缩),质量等等,tkinter是一个轻量级的GUI软件,方便我们制作简单应用程序。
现在开始制作最简单的软件吧。
基本配置要求:自行安装python3.6(Aconada也可)+pil(pillow)+tkinter
涉及知识:文件读写,异常处理,GUI编程,global变量,回调函数
github:https://github.com/ivat4u/Black-Technology
如何转变图片格式
对Image模块的介绍,对于PNG、BMP和JPG彩色图像格式之间的互相转换都可以通过Image模块的open()和save()函数来完成。
具体说就是,在打开这些图像时,PIL会将它们解码为三通道的“RGB”图像。用户可以基于这个“RGB”图像,对其进行处理。
处理完毕,使用函数save(),可以将处理结果保存成PNG、BMP和JPG中任何格式。这样也就完成了几种格式之间的转换。
def call_convert(type='jpg')
#选取目录文件
path = tkinter.filedialog.askopenfilename()
#获得父路径
file_path=os.path.dirname(path)
filename=os.path.basename(path)
#文件名前缀
front=filename.split('.')[0]
#这段函数用来选取图片,如果是D:\\IMG.jpg front会为IMG file_path=D:\\
try:
img = Image.open(path)
output_path=file_path + '\\' + front + '.' + type
output_file=img
output_file.save(output_path)
except OSError:
lb.config(text="您没有选择任何文件")
tkinter.messagebox.showerror('错误', '图片格式错误,无法识别')
现在根据你定义的type,就可以转变成不同格式了,PIL很强大,至少支持jpg,png,pdf,jpeg,bmp等常用格式转换哦。
定义button和监听器
选择最简单的块状布局,然后再button,command填入回调函数,大功告成。
root = Tk()
root.geometry()
root.title('图片格式转换')
lb = Label(root,text = '选取格式后会在原路径生成对应格式')
lb.pack()
#回调函数如果带参数,记得写成lamda表达式
btn = Button(root,text="转换图片",command=lambda:call_convert(type='jpg')
btn.pack()
这时候我们按钮button就可以响应转换一张选取的图片,并且输出同目录同名.type格式的图片了。
单选框指定格式
但是我们这个程序仍然不方便使用,我们希望做成这个样子的:
即利用单选框来选择图片格式。
首先定义全局变量的数组字典:
types=[('png',0),('jpg',1),('bmp',2),('pdf',3),('jpeg',4)]
type='png'
然后创建单选框和对应回调函数:
v=IntVar()
def callRB():
for i in range(5):
if (v.get()==i):
global type
type=types[i][0]
#for循环创建单选框
for lan,num in types:
Radiobutton(fm1, text=lan, value=num, command=callRB, variable=v).pack(anchor=W,side='left')
经过反复测试,我们一定要把v的数字值写在types的第二项,v.get语句才能正常工作,如果不想用intvar可以改用StringVar(后面会用到)。
改写之前的转换函数:
#现在这个type是我们修改后的全局变量了
btn = Button(root,text="转换图片",command=lambda:call_convert(type)
经过测试,正常工作,OK
改变图片尺寸和pil滤镜
做到这里,你可能会疑问,我们辛辛苦苦写的软件,不如网站上下载的格式转换器,那有什么用呢?
现在我们就开始使用一些更强大的黑科技吧。
任意改变图片尺寸(可以不按比例放缩)
#这段代码后一个参数可以改变图片压缩率哦,不过我的代码通过save函数实现的
img=img.resize((180,180),Image.ANTIALIAS)
from PIL import Image, ImageFilter
#更多强大功能
im = Image.open(im_path)
# 高斯模糊
im.filter(ImageFilter.GaussianBlur).save(r'C:\Users\Administrator\Desktop\GaussianBlur.jpg')
# 普通模糊
im.filter(ImageFilter.BLUR).save(r'C:\Users\Administrator\Desktop\BLUR.jpg')
# 边缘增强
im.filter(ImageFilter.EDGE_ENHANCE).save(r'C:\Users\Administrator\Desktop\EDGE_ENHANCE.jpg')
# 找到边缘
im.filter(ImageFilter.FIND_EDGES).save(r'C:\Users\Administrator\Desktop\FIND_EDGES.jpg')
# 浮雕
im.filter(ImageFilter.EMBOSS).save(r'C:\Users\Administrator\Desktop\EMBOSS.jpg')
# 轮廓
im.filter(ImageFilter.CONTOUR).save(r'C:\Users\Administrator\Desktop\CONTOUR.jpg')
# 锐化
im.filter(ImageFilter.SHARPEN).save(r'C:\Users\Administrator\Desktop\SHARPEN.jpg')
# 平滑
im.filter(ImageFilter.SMOOTH).save(r'C:\Users\Administrator\Desktop\SMOOTH.jpg')
# 细节
im.filter(ImageFilter.DETAIL).save(r'C:\Users\Administrator\Desktop\DETAIL.jpg')
预览图
有些童鞋说你这软件太low了,居然不可以让我看到预览图,每次就点一个保存出现新图,自己都不知道效果怎么样?
OK,现在我们来做一个预览图和原图的功能,大致效果如下:
现在我们需要把加载图片,修改图片,确定分成三个回调函数了
#加载图片
def loadimg():
global path
global sizex
global sizey
path = tkinter.filedialog.askopenfilename()
lb.config(text=path)
if path != '':
try:
img = Image.open(path)
sizex=img.size[0]
sizey=img.size[1]
x.set(sizex)
y.set(sizey)
img=img.resize((180,180),Image.ANTIALIAS)
global img_origin
img_origin = ImageTk.PhotoImage(img)
global label_img
label_img.configure(image=img_origin)
label_img.pack()
except OSError:
tkinter.messagebox.showerror('错误', '图片格式错误,无法识别')
#修改图片
def convert(path,type='png',x=sizex,y=sizey,):
x=int(x)
y=int(y)
file_path=os.path.dirname(path)
filename=os.path.basename(path)
front=filename.split('.')[0]
def function(img):
try:
if (0 in cl_dict):
img = img.convert('RGB').transpose(Image.FLIP_LEFT_RIGHT)
if (1 in cl_dict):
img = img.convert('RGB').transpose(Image.FLIP_TOP_BOTTOM)
if (2 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.GaussianBlur)
if (3 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.BLUR)
if (4 in cl_dict):
img = img.convert('RGB').filter((ImageFilter.EDGE_ENHANCE))
if (5 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.FIND_EDGES)
if (6 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.EMBOSS)
if (7 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.CONTOUR)
if (8 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.SHARPEN)
if (9 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.SMOOTH)
if (10 in cl_dict):
img = img.convert('RGB').filter(ImageFilter.DETAIL)
except ValueError as e:
tkinter.messagebox.showerror('错误',repr(e))
return img
if path != '':
try:
img = Image.open(path)
img=function(img)
img = img.resize((x, y), Image.ANTIALIAS)
img_n = img.resize((180, 180), Image.ANTIALIAS)
global img_new
img_new = ImageTk.PhotoImage(img_n)
label_img2.configure(image=img_new)
label_img2.pack()
global output_path,output_file
output_path=file_path + '\\' + front + '.' + type
output_file=img
except OSError:
lb.config(text="您没有选择任何文件")
tkinter.messagebox.showerror('错误', '图片格式错误,无法识别')
else:
tkinter.messagebox.showerror('错误', '未发现路径')
#确定
def output():
global output_file,output_path
output_file.save(output_path,quality=quality)
回调函数之间,应该利用全局变量来通信,而不是协程、生成器对象(我知道你们像这么做,但是不可能的)。
以下为功能测试:
写道最后,应用程序打包
如果我们的文件,一直是什么.py格式的话,相信也不会有人愿意用它。
现在我们尝试走一遍python应用程序的打包,打开cmd,输入:
pyinstaller -Fw 图片格式转换.py
会生成dist文件夹,打开一看,正常是正常,但是文件大小不可描述…
这就是不用虚拟环境的坏处,pyinstaller把我的aconda所有库给塞进去了。
现在我们来安装虚拟环境吧。
安装pipenv
pip install pipenv
在干净目录下初始化python环境, 系统会自动在环境变量里搜索符合要求的python环境
pipenv --python 3.6
进入虚拟环境(第一次进入会自动进行安装 pipenv install)
pipenv shell
pip install pillow
pip install tkinter
pyinstaller -Fw 图片格式转换.py
ok,大功告成,源码我会放在github上:https://github.com/ivat4u/Black-Technology
喜欢的朋友务必点个star哦,有什么更好的建议可以直接m我。