Back in October, Shengu wrote:
> Dears,:
>
> I use canvas to make animation by continuously displaying objects.
> Now I want to export what is displayed in canvas to an image
file(.bmp, jpeg,png,... is OK)
> Is there such function in tkinter and how can I attain this?
>
> Thank you very much!
>
> Shengxu
I thought I'd pass along a library that I've cobbled together over time
that provides functions for copying the contents of any widget -
including a canvas - to either the clipboard or an image file. To use
the library, you will need the Python Imaging Library:
http://www.pythonware.com/products/pil/
To use the copy to and from clipboard functions you will need wx. The
library is intended to work with Tkinter widgets, but uses some wx
functionality to make the clipboard functions work properly. If you
don't want the clipboard functionality, you can skip the wx download and
comment out the import wx and PySimpleApp lines.
http://www.wxpython.org/
The library works only on Windows and includes four basic functions:
grab_image: grabs an screencap of either a widget or an area of the
screen and returns a PIL image object
copy_to_clipboard: grabs a screencap of either a widget or an area and
copies the image to the clipboard
copy_to_file: grabs a screencap of either a widget or an area and writes
the image to an image file such as jpeg, gif, etc. - whatever types PIL
supports
get_bitmap_from_clipboard: grabs a bitmap from the clipboard and returns
a PIL image object
I'd like to thank Fredrik Lundh for many years ago providing the code
that does the screen cap of the images.
Hopefully this will be helpful to people -
Dave Giesen
import sys
import tkMessageBox as tkm
import Image # Only if you need and use the PIL library.
if sys.platform.startswith('win'):
# Image grab comes from PIL (Python Imaging Library)
import ImageGrab
# We use wx to copy to the clipboard on windows machines. The
PySimpleApp line initializes wx. There does not appear to be
# a conflict between wx started this way and Tk. Note that if you
don't want the copy to clipboard or read from clipboard capability,
# you can just delete the two lines below (and all the associated wx
routines).
import wx
app = wx.PySimpleApp()
def grab_image(widget=None, bbox=None, offset1=2, offset2=2):
# widget = the Tk widget to copy to the clipboard
# bbox = the bounding box containing the area to copy to the
clipboard. Should be a tuple of 4 integers.
# either widget or bbox must not be None. If both are not None,
widget is used.
# Note that if widget is used, the screen will be updated. It can't
do that if only bbox is used, so that should be done by the caller
# offset1 & offset2 determine the amount to expand the box beyond
the widget in order to make sure the whole widget is captured
# they are used because some widgets (such as canvases)
appear to be a bit wonky in whether borders are copied or not
im = ""
if widget:
# The guts of this routine were originally provided by Fredrik Lundh
widget.update()
x0 = widget.winfo_rootx()
y0 = widget.winfo_rooty()
x1 = x0 + widget.winfo_width()
y1 = y0 + widget.winfo_height()
im = ImageGrab.grab((x0-offset1, y0-offset1, x1+offset2,
y1+offset2))
elif bbox:
im = ImageGrab.grab(bbox)
return im
def copy_to_clipboard(**keyw):
# Copies an image of a widget or screen area to the clipboard.
#
# Any arguments to this routine are passed directly to grab_image,
so see that routine for possible useful arguments
# In particular, either widget or bbox must be supplied by the user
#
if sys.platform.startswith('win'):
im = grab_image(**keyw)
if im:
bitmap = pil_to_bitmap(im)
clipboard_bitmap = wx.BitmapDataObject(bitmap)
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(clipboard_bitmap)
wx.TheClipboard.Close()
else:
tkm.showerror('Clipboard Copy Error', 'Clipboard copy not
implemented on this platform')
def copy_to_file(filename, **keyw):
# Copies an image of a widget or screen area to a file. The file
type can be any that the Python Imaging Library supports, and the
# file type is determined by the extension of filename.
#
# filename = name of file to save the image to. The file name
extension is used to determine the image type.
#
# Any arguments to this routine are passed directly to grab_image,
so see that routine for possible useful arguments
# In particular, either widget= or bbox= must be supplied by the user
#
if sys.platform.startswith('win'):
im = grab_image(**keyw)
if im:
im.save(filename)
else:
tkm.showerror('Image Grab Error', 'Image grab not implemented on
this platform')
def get_bitmap_from_clipboard():
# Returns a PIL image from the clipboard, which should have bitmap
data in it
# The PIL image can be used in Tk widgets by converting it using
ImageTk.PhotoImage(PIL image)
bm = wx.BitmapDataObject()
if wx.TheClipboard.GetData(bm):
wxbmp = bm.GetBitmap()
try:
pilimage = bitmap_to_pil(wxbmp)
return pilimage
except:
tkm.showerror('Clipboard Paste Error', 'Clipboard bitmap
data could not be converted to an image')
return False
else:
tkm.showerror('Clipboard Paste Error', 'Clipboard data is not a
recognized bitmap format')
return False
########################################
# Start of routines taken from
http://wiki.wxpython.org/index.cgi/WorkingWithImages
########################################
def bitmap_to_pil(bitmap):
return wximage_to_pil(bitmap_to_wximage(bitmap))
def bitmap_to_wximage(bitmap):
return wx.ImageFromBitmap(bitmap)
def pil_to_bitmap(pil):
return wximage_to_bitmap(pil_to_wximage(pil))
def pil_to_wximage(pil):
image = wx.EmptyImage(pil.size[0], pil.size[1])
image.SetData(pil.convert('RGB').tostring())
return image
#Or, if you want to copy alpha channels too (available from wxPython 2.5)
def piltoimage(pil,alpha=True):
if alpha:
image = apply( wx.EmptyImage, pil.size )
image.SetData( pil.convert( "RGB").tostring() )
image.SetAlphaData(pil.convert("RGBA").tostring()[3::4])
else:
image = wx.EmptyImage(pil.size[0], pil.size[1])
new_image = pil.convert('RGB')
data = new_image.tostring()
image.SetData(data)
return image
def wximage_to_pil(image):
pil = Image.new('RGB', (image.GetWidth(), image.GetHeight()))
pil.fromstring(image.GetData())
return pil
def wximage_to_bitmap(image):
return image.ConvertToBitmap()
########################################
# End of routines taken from
http://wiki.wxpython.org/index.cgi/WorkingWithImages
########################################
if __name__ == '__main__':
def copy_canvas():
copy_to_clipboard(widget=canvas)
def copy_canvas_file():
copy_to_file('testimage.jpg', widget=canvas)
print 'testing'
import Tkinter as Tk
root = Tk.Tk()
canvas = Tk.Canvas(root, bg='white')
canvas.pack()
canvas.create_oval(150, 50, 180, 150, fill='red')
canvas.create_line(3, 3, 100, 120, fill='blue', width=4)
button1 = Tk.Button(root, text='copy to clipboard', command=copy_canvas)
button1.pack(pady=5)
button2 = Tk.Button(root, text='copy to testimage.jpg',
command=copy_canvas_file)
button2.pack()
root.mainloop()
_______________________________________________
Tkinter-discuss mailing list
Tkinter-discuss@python.org
http://mail.python.org/mailman/listinfo/tkinter-discuss