pythonimagecanvastkinterexport

How to save grabbed image to user-input directory in Python


I have worked at this code:

from PIL import ImageGrab

def getnsave(event):
    widget=event.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()
    formats=[('Images (.png)','*.png'),('Images (.jpg)','*.jpg')]
    img=ImageGrab.grab().crop((x,y,x1,y1))
    f=filedialog.asksaveasfile(filetypes=(("Portable Network Graphics (*.png)", "*.png"),("All Files (*.*)", "*.*")),mode='w',defaultextension='.png')
    if f is None:
        return
    f.write(img)
    f.close()

and I'm getting this error:

TypeError: write() argument must be str, not Image

Please, help me. I understand, that after I select the directory, I need to command WHAT to save. Do You know how to do it?


Solution

  • To save a PIL image to a file, you have to use the Image.save method. Two things are important to make this work correctly:

    1. The file must be opened in binary mode.

      This means you have to change change the w file mode in

      filedialog.asksaveasfile(filetypes=(("Portable Network Graphics (*.png)", "*.png"),
                                          ("All Files (*.*)", "*.*")),
                               mode='w',
                               defaultextension='.png')
      

      to wb like so:

      filedialog.asksaveasfile(filetypes=(("Portable Network Graphics (*.png)", "*.png"),
                                          ("All Files (*.*)", "*.*")),
                               mode='wb',
                               defaultextension='.png')
      
    2. PIL needs to know in which format you want to save the image. You can extract the format from the file extension like so:

      filename = f.name
      extension = filename.rsplit('.', 1)[-1]
      

    Putting all of this together:

    f = filedialog.asksaveasfile(filetypes=(("Portable Network Graphics (*.png)", "*.png"),
                                            ("All Files (*.*)", "*.*")),
                                 mode='wb',
                                 defaultextension='.png')
    if f is None:
        return
    
    filename = f.name
    extension = filename.rsplit('.', 1)[-1]
    
    img.save(f, extension)
    f.close()