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

Reply via email to