Python PIL(Python Image Library)是python第三方图像处理库,由于其强大的功能和简单易用特点以及众多的使用人数,几乎被认为是python官方图像处理库了。原来只支持python2版本,后来移植到pillow,其功能和PIL差不多,但是支持python3。
PIL可以做很多和图像处理相关的工作,如创建缩略图、转换图像格式、图像旋转、改变图像尺寸等等功能。既然是图像处理,一定需要将图形图像在屏幕显示。一般文章仅介绍用Image的show方法显示图形图像,即调用操作系统默认的显示图形图像软件显示。如果编写应用程序,一般希望将图形图像的显示和处理两部分集合在同一程序中。本文介绍用python tkinter canvas显示PIL Image类图形图像的方法。使用该方法,不但可以在屏幕显示单张图片,可以创建多个Canvas同屏显示多张图片,也可分页,每页显示一张图片。
完整程序如下,其实很简单。但这里特别注意第13、16和17行,如下:
def dealWith():
global img #第13行
...
img = ImageTk.PhotoImage(image=image1) #第16行
cv.itemconfig(mainImage,image=img) #第17行
最初编写的程序并没有第13行,这种情况下img是局部变量,退出方法,img就不存在了。在第17行,image=img。一般认为虽然img不存在了,但是由于image=img,img所引用的数据又被image引用,img所代表的数据在退出方法后,不会被垃圾收集器收集,即还存在,应能正确显示图像,实际正相反该程序无图显示。为这种想法困扰了很久,找不到不能正确显示图像的原因。最后觉得可能image=img并不是引用img所代表的数据,为了使img所代表的数据不被垃圾收集器收集,增加第13行,使img变为全局变量,这样退出方法,img仍存在,其引用的数据也就不会被垃圾收集器收集。修改后,能正常工作。
import tkinter as tk
from PIL import Image,ImageTk,ImageDraw
root = tk.Tk()
root.geometry('400x350')
cv = tk.Canvas(root, width=400, height=300, bg='white')
cv.pack()
image1 = Image.new("RGB", (400, 300), 'white')#宽、高和背景和cv必须相同
img = ImageTk.PhotoImage(image=image1)
mainImage=cv.create_image(200,150,image=img)
draw = ImageDraw.Draw(image1) #将用draw在image1上画图
cv.itemconfig(mainImage,image=img)
def dealWith(): #处理图形程序,这里只画了一条线段和一个圆
global img #这条是必须的,否则img是局部变量,在函数退出后img被垃圾回收器收回,canvas无法显示
draw.line([20, 20, 80, 80], fill='red',width=3) #画线
draw.ellipse((100,100, 200, 200), fill ='red',outline='green')#画圆
img = ImageTk.PhotoImage(image=image1)
cv.itemconfig(mainImage,image=img) #img是显示数据,不能丢失
#image1.show() #用操作系统默认显示程序显示,可以去掉#试一下
tk.Button(root,command=dealWith,text='处理图像').pack()
root.mainloop()