如何将画布内容转换为图像?
- 2025-01-09 08:46:00
- admin 原创
- 84
问题描述:
from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
我想将画布内容转换为位图或其他图像,然后执行其他操作,例如旋转或缩放图像,或更改其坐标。
如果我不再绘图,位图可以提高效率来显示。
我应该怎么办?
解决方案 1:
您可以生成一个 postscript 文档(输入到其他工具中:ImageMagick、Ghostscript 等):
from Tkinter import *
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50)
cv.pack()
root.mainloop()
cv.update()
cv.postscript(file="file_name.ps", colormode='color')
root.mainloop()
或者在 PIL 和 Tkinter 的画布上并行绘制相同的图像(参见:保存 Tkinter 画布绘图(Python))。例如(受同一篇文章启发):
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()
解决方案 2:
我找到了一种非常好的方法,它确实很有用。为此,您需要 PIL 模块。以下是代码:
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()
获取整个窗口左上角的像素位置root
。
然后,将widget.winfo_x()
和widget.winfo_y()
添加到,基本上只是获取您想要捕获的小部件左上角像素的像素坐标(在屏幕的像素(x,y)处)。
然后我找到 (x1,y1),即小部件的左下角像素。然后ImageGrab.grab()
制作一个截屏,然后我裁剪它以仅获取包含小部件的部分。虽然并不完美,并且无法制作出最好的图像,但这是一个很棒的工具,可以获取任何小部件的图像并保存它。
如果您有任何疑问,请发表评论!希望这能有所帮助!
解决方案 3:
使用 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')
解决方案 4:
也许您可以尝试使用 widget_winfo_id 来获取画布的 HWND。
import win32gui
from PIL import ImageGrab
HWND = canvas.winfo_id() # get the handle of the canvas
rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
im = ImageGrab.grab(rect) # get image of the current location
解决方案 5:
而不是依赖:
特定平台的屏幕捕获,或者
将图像不必要地写入磁盘,然后将其读回,或者
浪费时间和内存写入两个画布
我认为最好将画布渲染为 EPS 并将 PostScript 包装在其中BytesIO
并允许 PIL 读取它而不使用磁盘:
#!/usr/bin/env python3
from tkinter import *
from PIL import Image, ImageTk
from io import BytesIO
root = Tk()
cv = Canvas(root)
cv.create_rectangle(10,10,50,50, fill='green')
cv.pack()
cv.update()
# Get the EPS corresponding to the canvas
eps = cv.postscript(colormode='color')
# Save canvas as "in-memory" EPS and pass to PIL without writing to disk
im = Image.open(BytesIO(bytes(eps,'ascii')))
im.save('result.png')
root.mainloop()
解决方案 6:
@B.Jenkins 的答案有一个更好的方法,它不需要引用根对象:
from PIL import ImageGrab
def save_widget_as_image(widget, file_name):
ImageGrab.grab(bbox=(
widget.winfo_rootx(),
widget.winfo_rooty(),
widget.winfo_rootx() + widget.winfo_width(),
widget.winfo_rooty() + widget.winfo_height()
)).save(file_name)
解决方案 7:
在我的系统中,ghostscript 和 ImageGrab 总体上存在严重问题。解决方案是在 PIL Image 上绘制,另存为文件,在 PhotoImage 上加载文件,用于创建新的 TKinter Canvas。
canvas = Canvas(win, width=IMG_W, height=IMG_H)
img = PILImg.new("RGB", (IMG_W, IMG_H), "#000")
draw = ImageDraw.Draw(img)
draw.rectangle([x,y,w,h], fill=color, outline=border)
img.save("stock-chart.png")
copyImg = PhotoImage(file="stock-chart.png")
canvas.create_image(IMG_W_2, IMG_H_2, image=copyImg)
解决方案 8:
有一种更简单的方法可以做到这一点,无需任何 ImageGrab 或其他任何东西。
您可以从画布上抓取每个像素,然后将其绘制到图像中。就像这个程序一样。
如果画布上有很多东西,它可能会有点慢……但至少它不使用 ghostscript。而且您只需保留findobjat
,save
函数即可。
from tkinter import *
from PIL import Image
import webcolors
drawing = False
def findobjat(x,y,C):
obj = C.find_overlapping(x,y,x,y)
if len(obj) == 0:
return (255,255,255)
color = C.itemcget(obj[-1],"fill")
if type(color) == str:
color = webcolors.name_to_rgb(color)
return color
def save(C,w,h):
im = Image.new("RGB",(w,h))
for x in range(w):
for y in range(h):
color = findobjat(x,y,C)
im.putpixel((x,y),color)
return im
def postsave():
save(C,200,200).save("image.png")
def drawstart(event):
global drawing
drawing = True
def drawstop(event):
global drawing
drawing = False
def draw(event):
if drawing:
C.create_oval(event.x-5,event.y-5,event.x+5,event.y+5,fill = "black")
root = Tk()
root.geometry("200x200")
C = Canvas(root,bg = "white",width = 200,height = 200)
C.bind("<Button-1>",drawstart)
C.bind("<ButtonRelease-1>",drawstop)
C.bind("<B1-Motion>",draw)
button = Button(root,text = "Save image",command = postsave)
button.pack()
C.pack()
root.mainloop()