Saving canvas from tkinter to file

…衆ロ難τιáo~ 提交于 2020-03-27 19:49:09

问题


So I followed this post: How can I convert canvas content to an image?

And when I tried to do as mentioned in the last suggestion, I get the following problem:

When I call it out like this, the image/screenshot is taken too early and therefore the required image won't be captured. Here's the code:

from tkinter import *
from PIL import ImageGrab
root = Tk()
cv = Canvas(root)

cv.pack()

cv.create_rectangle(10,10,50,50)
#cv.create_line([0, 10, 10, 10], fill='green')


cv.update()


#print(root.winfo_width())

def getter(widget):
    x=root.winfo_rootx()+widget.winfo_x()
    print(x)
    y=root.winfo_rooty()+widget.winfo_y()
    print(y)
    x1=x+widget.winfo_width()
    print(x1)
    y1=y+widget.winfo_height()
    print(y1)
    ImageGrab.grab().crop((x,y,x1,y1)).save("em.jpg")

getter(cv)
root.mainloop()

By the way, if there is a simplier solution, I would appreciate it! The thing is that the saving part will be added to the code dynamically later so the solution should be as light as possible.

Thanks in advance!

PS: Maybe it is even possible to save the canvas without displaying it beforehand? Just by the code?


回答1:


Below is the code for taking screenshots of just the tkinter canvas. PIL.ImageGrab module does not work in Linux; replaced that with pyscreenshot. Tested this code in Ubuntu 16.04. You may have to check if it operates in Windows/OSx. Please note the remarks in function self._grabtofile.

Remark: In Ubuntu, this script had to be executed directly on commandline/terminal to work. It did not work when executed from IDLE for python3.

Summary:

  1. Able to display the screenschoot of a tkinter canvas and save it to file a using two events.
  2. Able to screenshot tkinter canvas (w/o displaying it) and save it to file using one event.

Working code:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

try:
    import tkinter as tk # Python 3 tkinter modules
except ImportError:
    import Tkinter as tk # Python 2 tkinter modules

from PIL import Image, ImageTk 
#from PIL import Image, ImageTk, ImageGrab  # For Windows & OSx
import pyscreenshot as ImageGrab # For Linux

class App(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)
        self.parent=parent

        file = 'images.jpg'
        self.img = Image.open(file)
        #self.img.show() #Check to proof image can be read in and displayed correctly.
        self.photo = ImageTk.PhotoImage(self.img)
        print('size of self.img =', self.img.size)
        centerx= self.img.size[0]//2
        centery= self.img.size[1]//2
        print ('center of self.img = ', centerx, centery)

        self.cv = tk.Canvas(self)
        self.cv.create_image(centerx, centery, image=self.photo)
        self.cv.create_rectangle(centerx*0.5,centery*0.5,centerx*1.5,centery*1.5,
                                 outline='blue')
        self.cv.grid(row=0, column=0, columnspan=3, sticky='nsew') 

        self.snappic=tk.Button(self, text='SNAP', command=self._snapCanvas)
        self.snappic.grid(row=1, column=0, sticky='nsew')

        self.savepic=tk.Button(self, text='SAVE', command=self._save)
        self.savepic.grid(row=1, column=1, sticky='nsew')

        self.directsavepic=tk.Button(self, text='Grab_to_File', command=self._grabtofile)
        self.directsavepic.grid(row=1, column=2, sticky='nsew')

        self.snapsave=tk.Button(self, text='SNAP & SAVE', command=self._snapsaveCanvas)
        self.snapsave.grid(row=2, column=0, columnspan=2, sticky='nsew')

    def _snapCanvas(self):
        print('\n def _snapCanvas(self):')
        canvas = self._canvas() # Get Window Coordinates of Canvas
        self.grabcanvas = ImageGrab.grab(bbox=canvas)
        self.grabcanvas.show()

    def _save(self):
        self.grabcanvas.save("out.jpg")
        print('Screenshoot of tkinter.Canvas saved in "out.jpg"')

    def _grabtofile(self):
        '''Remark: The intension was to directly save a screenshoot of the canvas in
                   "out_grabtofile.png".
                   Issue 1: Only a full screenshot was save.
                   Issue 2: Saved image format defaults to .png. Other format gave errors. 
                   Issue 3: "ImageGrab.grab_to_file" only able to return full screenshoot
                            and not just the canvas. '''
        print('\n def _grabtofile(self):')
        canvas = self._canvas()  # Get Window Coordinates of Canvas
        print('canvas = ', canvas)
        ImageGrab.grab_to_file("out_grabtofile.png", ImageGrab.grab(bbox=canvas))
        print('Screenshoot of tkinter.Canvas directly saved in "out_grabtofile.png"')

    def _snapsaveCanvas(self):
        print('\n def _snapsaveCanvas(self):')
        canvas = self._canvas()  # Get Window Coordinates of Canvas
        self.grabcanvas = ImageGrab.grab(bbox=canvas).save("out_snapsave.jpg")
        print('Screencshot tkinter canvas and saved as "out_snapsave.jpg w/o displaying screenshoot."')

    def _canvas(self):
        print('  def _canvas(self):')
        print('self.cv.winfo_rootx() = ', self.cv.winfo_rootx())
        print('self.cv.winfo_rooty() = ', self.cv.winfo_rooty())
        print('self.cv.winfo_x() =', self.cv.winfo_x())
        print('self.cv.winfo_y() =', self.cv.winfo_y())
        print('self.cv.winfo_width() =', self.cv.winfo_width())
        print('self.cv.winfo_height() =', self.cv.winfo_height())
        x=self.cv.winfo_rootx()+self.cv.winfo_x()
        y=self.cv.winfo_rooty()+self.cv.winfo_y()
        x1=x+self.cv.winfo_width()
        y1=y+self.cv.winfo_height()
        box=(x,y,x1,y1)
        print('box = ', box)
        return box


if __name__ == '__main__':
    root = tk.Tk()
    root.title('App'), root.geometry('300x300')
    app = App(root)
    app.grid(row=0, column=0, sticky='nsew')

    root.rowconfigure(0, weight=1)
    root.columnconfigure(0, weight=1)

    app.rowconfigure(0, weight=10)
    app.rowconfigure(1, weight=1)
    app.columnconfigure(0, weight=1)
    app.columnconfigure(1, weight=1)
    app.columnconfigure(2, weight=1)

    app.mainloop()

Screenshot of GUI:

Screenshot of GUI's tk.Canvas:




回答2:


I know this is an old post but I just want to share what worked for me, hopefully it will help somebody with similar problem.

import tkinter as tk
from PIL import Image
import io
import os
import subprocess

root = Tk()

cv = Canvas(root)
cv.pack()

cv.create_rectangle(10,10,50,50)

ps = cv.postscript(colormode='color')
img = Image.open(io.BytesIO(ps.encode('utf-8')))
img.save('filename.jpg', 'jpeg')

root.mainloop()

In this solution, you have to have ghostscript and Pillow installed. For MacOS, install ghostscript with

brew install ghostscript

and Pillow with pip install Pillow



来源:https://stackoverflow.com/questions/41940945/saving-canvas-from-tkinter-to-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!