在计算机上画图未完成,需要保存未完成图形以便以后继续,或者完成画图,要保存为通用格式文件,方便浏览。如使用python tkinter Canvas画图,其好像没有将图像保存通用格式文件的方法,但可以将图像保存为postscript类型文件,这是一种页面描述语言,主要用于高质量打印。为了将Canvas图像保存为通用格式文件,网上介绍了许多种方法。一个网页介绍了将canvas中的图形图像保存为通用格式文件的5种方法,这里把该网页中翻译的相关文字、代码和个人的理解,写在下面,供大家参考,理解不对之处请指正。网址如下:https://stackoverflow.com/questions/9886274/how-can-i-convert-canvas-content-to-an-image
介绍第1种方法,首先将canvas的图像保存为postscript类型文件代码如下,扩展名可为ps或esp。代码有修改,能够正确运行。
from tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
cv.update()
cv.postscript(file="a.ps", colormode='color') #扩展名可为ps或esp
root.mainloop()
#cv.postscript(file="saved.ps", height=100, width=100, colormode="color")
将canvas的图形图像保存为postscript类型文件后,无论文件扩展名为ps还是esp,都可用软件ImageMagick或Ghostscript等软件查看,并保存为通用格式文件。据说Adobe Photoshop能打开esp文件。但似乎canvas没有提供读postscript类型文件方法。
介绍第2种方法,是在PIL Image和tkinter Canvas上同时绘制相同的图像,可用PIL Image保存为jpg图像。个人认为该法有很大局限,在tkinter Cabvas上绘图,可移动图形或图像,放大或缩小或图像,删除图形或图像,PIL Image如何实现?该代码未做验证。
from Tkinter import *
import Image, ImageDraw
width = 400
height = 300
center = height//2
white = (255, 255, 255)
green = (0,128,0)
root = Tk()
# Tkinter create a canvas to draw on
cv = Canvas(root, width=width, height=height, bg='white')
cv.pack()
# PIL create an empty image and draw object to draw on
# memory only, not visible
image1 = Image.new("RGB", (width, height), white)
draw = ImageDraw.Draw(image1)
# do the Tkinter canvas drawings (visible)
cv.create_line([0, center, width, center], fill='green')
# do the PIL image/draw (in memory) drawings
draw.line([0, center, width, center], green)
# PIL image can be saved as .png .jpg .gif or .bmp file (among others)
filename = "my_drawing.jpg"
image1.save(filename)
root.mainloop()
介绍第3种方法是调用PIL库中的ImageGrab.grab()函数,实现截屏,这个函数的参数是截取矩形的左上和右下坐标,不带参数的话默认截全屏。其缺点是Canvas尺寸超过屏幕尺寸,不能得到Canvas所有图形和图像。代码如下,该代码未做验证。
from PIL import ImageGrab
def getter(widget):
x=root.winfo_rootx()+widget.winfo_x()
y=root.winfo_rooty()+widget.winfo_y()
x1=x+widget.winfo_width()
y1=y+widget.winfo_height()
ImageGrab.grab().crop((x,y,x1,y1)).save("file path here")
以下是原文作者对其的说明:命令root.winfo_rootx()和root.winfo_rooty()获取整个根窗口左上角的像素位置。然后,将widget.winfo_x()和widget.winfo_y()添加到其中,基本上就是获取您想要捕获的小部件左上角像素的像素坐标(在屏幕的像素(x,y)处)。然后找到小部件左下角的像素(x1,y1)。grab()生成一个截屏,然后我对其进行裁剪,以只获得包含小部件的位。尽管不是完美的,也不能制作出最好的图像,但对于获取任何小部件的图像并保存它来说,这是一个很好的工具。应该只能用于Window。
个人认为,也许截全屏,然后用类似画图等软件,再截取有用部分保存更方便。
介绍的第4种方法,使用Pillow转换从Postscript为PNG文件,其代码如下:
from PIL import Image
def save_as_png(canvas,fileName):
# save postscipt image
canvas.postscript(file = fileName + '.eps')
# use PIL to convert to PNG
img = Image.open(fileName + '.eps')
img.save(fileName + '.png', 'png')
为了能正常运行,自己编写的验证代码如下:
from tkinter import *
from PIL import Image
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
cv.update()
cv.postscript(file="a.eps",colormode='color') #如将扩展名改为ps,出错信息相同
img = Image.open("a.eps")
img.save("a.png", "png") #运行后,此句出错
root.mainloop()
运行出错信息如下:
C:/Users/gengzhaoying/AppData/Local/Programs/Python/Python38/python.exe d:/myPythonFile/保存为postscript文件1.py
Traceback (most recent call last):
File “d:/myPythonFile/保存为postscript文件1.py”, line 10, in
img.save(“a.png”, “png”)
File “C:\Users\gengzhaoying\AppData\Local\Programs\Python\Python38\lib\site-packages\PIL\Image.py”, line 2130, in save
self._ensure_mutable()
File “C:\Users\gengzhaoying\AppData\Local\Programs\Python\Python38\lib\site-packages\PIL\Image.py”, line 619, in _ensure_mutable
self._copy()
File “C:\Users\gengzhaoying\AppData\Local\Programs\Python\Python38\lib\site-packages\PIL\Image.py”, line 612, in _copy
self.load()
File “C:\Users\gengzhaoying\AppData\Local\Programs\Python\Python38\lib\site-packages\PIL\EpsImagePlugin.py”, line 332, in load
self.im = Ghostscript(self.tile, self.size, self.fp, scale)
File “C:\Users\gengzhaoying\AppData\Local\Programs\Python\Python38\lib\site-packages\PIL\EpsImagePlugin.py”, line 134, in Ghostscript
raise OSError(“Unable to locate Ghostscript on paths”)
OSError: Unable to locate Ghostscript on paths
无论转换文件的扩展名是eps或ps,都会发生系统错误:OSError: Unable to locate Ghostscript on paths,翻译为中文:无法在路径上定位Ghostscript。其实本人使用的计算机根本未安装所要求的Ghostscript库。这说明该方法要求安装postscript库。下载Ghostscript库网址为:https://www.ghostscript.com/download/gsdnld.html
介绍的第5种方法,使用window操作系统的API拷屏。其缺点是Canvas尺寸超过屏幕尺寸,不能拷贝Canvas所有图形和图像。这段代码未验证。
import win32gui
from PIL import ImageGrab
HWND = canvas.winfo_id() #得到canvasID
rect = win32gui.GetWindowRect(HWND) # 得到canvas的矩形坐标
im = ImageGrab.grab(rect) #得到屏幕指定矩形处包含所有点颜色的Image对象
以上5种方法都不能实现画图未完成,保存未完成图形,以便以后重新打开该文件,继续工作的功能。