fantascey
fantascey

Reputation: 23

How to screenshot the entire tkinter canvas as png or pdf

I'm creating a program that is designed... well it is designed to make character building more easy for D&D honestly. (I am a DM and I spend ages putting the sheets together when it should be a simple process when i know what i want, This code is eventually going to be part of a massive program that simplifies the process from hours to minutes. to me, well worth it.) All of the character creation parts are in a separate code, but what i have been working on is being able to open a character sheet, put all the answers to the questions into it, and save the output for later printing. note im on python3, using windows 8, and have all my modules actually pip installed yes.

I want to :

  1. Either Open a png Image (Or PDF)

  2. Write new information onto it

  3. Save the output as a new file.

< Note that I do NOT want to use classes or functions in this at all. I want all straightforward things please.>

What I can do already:

  1. Open a PNG (but not the original PDF. I had to convert it first for SOO many reasons i wont get into here.)

  2. Display the information i want in the canvas window on the image.

Unfortunately, I cant seem to save the whole canvas. The closest I got was an ImageGrab so far which actually screenshotted my entire computer monitor. and consequentially only about 500*250 pixels of my canvas (the top corner).

I need to figure out what Im doing wrong here. I pulled some code offline to get my scrollbars working, i do not at all claim that as my own. I have a problem saving the outputs as anything I can view. I got a postscript file, which when i put it back into a viewable image resulted still in only a partial snap of the total canvas. I need something that shows even the parts you need to scroll for.

The current code raises an exception somehow in the Tkinter pack, which I found online only about 27 times in other cases, none of which have an answer that actually applied to my error. I have looked and looked and very much appreciate help as to how to solve this one.

from tkinter import *
import tkinter.ttk as ttk
import PIL.Image as Image
import PIL.ImageTk as ImageTk
import PIL.ImageGrab as ImageGrab
import os
#I imported all these PIL sections seperate because importing the whole 
#thing as one, or alltogether on one line caused so many errors in calling     
#the functions. my pc for some reason HATES functions, ive NEVER had much 
#success with them. hence trying to create programs without them.
def on_vertical(event):
    canvas.yview_scroll(-1 * event.delta, 'units')

def on_horizontal(event):
    canvas.xview_scroll(-1 * event.delta, 'units')

root = Tk()
root.title('Your Character Here')
h = Scrollbar(root, orient=HORIZONTAL)
v = Scrollbar(root, orient=VERTICAL)
canvas = Canvas(root, scrollregion=(0, 0, 1275, 4960),
     yscrollcommand=v.set, 
     xscrollcommand=h.set)
h['command'] = canvas.xview
v['command'] = canvas.yview
output = ImageTk.PhotoImage(Image.open('charpg4.png'))
canvas.create_image(0,0,image=output, anchor='nw')
canvas.grid(column=0, row=0, sticky=(N,W,E,S))

canvas.bind_all('<MouseWheel>', on_vertical)
canvas.bind_all('<Shift-MouseWheel>', on_horizontal)

h.grid(column=0, row=1, sticky=(W,E))
v.grid(column=1, row=0, sticky=(N,S))
root.grid_columnconfigure(0, weight=1)
root.grid_rowconfigure(0, weight=1)

testing=("one", "two", "three", "testing")
canvas.create_text(210,155,fill='black',font='Helvetica 10',
                   text=testing)

canvas.update()
grabcanvas=ImageGrab.grab(bbox=canvas).save("test.png")
ttk.grabcanvas.save("test.png")
#the following code works but apparently takes only a direct screenshot
#ImageGrab.grab().save("test.jpg") 
#--these others have been tried but dont work for me??
#causes an error with bbox and ImageGrab
#self.grabcanvas = ImageGrab.grab(bbox=canvas)
#Causes the save error, says no such option
#ImageGrab.grab(bbox=canvas).save("test.jpg")
#froze and crashed the game, didnt do anything in the end.
#canvas.postscript(file='test.ps', size =(1275, 4960), colormode='gray')
root.mainloop()

Here is the code error that raises.

    Traceback (most recent call last):
  File "C:/Users/Autumn/Documents/programs/tests/dnd game/saving 
output/windowsize 3.py", line 42, in <module>
    grabcanvas=ImageGrab.grab(bbox=canvas).save("test.png")
  File "C:\Program Files (x86)\Python36-32\lib\site- 
   packages\PIL\ImageGrab.py", 
    line 48, in grab
        im = im.crop(bbox)
   File "C:\Program Files (x86)\Python36-32\lib\site- 
 packages\PIL\Image.py", 
    line 1078, in crop
        return self._new(self._crop(self.im, box))
      File "C:\Program Files (x86)\Python36-32\lib\site- 
   packages\PIL\Image.py", 
    line 1092, in _crop
    x0, y0, x1, y1 = map(int, map(round, box))
       File "C:\Program Files (x86)\Python36-32\lib\tkinter\__init__.py", 
line 1486, in cget
        return self.tk.call(self._w, 'cget', '-' + key)
    TypeError: must be str, not int

Usually I work out whats wrong with my code but I cant, based on everything im finding online, Image.Save or ImageGrab.save or Image.write... these should work within tk. ... it appears to refer to a function within tkinter that isnt calling 'cget' or some sort of string.. because i never did put an integer into the line it refers to anyways, and i never cropped, as the error refers to.

Upvotes: 1

Views: 4534

Answers (1)

Mike - SMT
Mike - SMT

Reputation: 15226

The problem you are having is the way you pass canvas to bbox. grab() need to take a tuple of coords and not an object like canvas.

Try this instead:

Delete this after the update() call:

grabcanvas=ImageGrab.grab(bbox=canvas).save("test.png")
ttk.grabcanvas.save("test.png")

Then add this after the update() call:

def save_canvas():
    x = root.winfo_rootx() + canvas.winfo_x()
    y = root.winfo_rooty() + canvas.winfo_y()
    xx = x + canvas.winfo_width()
    yy = y + canvas.winfo_height()
    ImageGrab.grab(bbox=(x, y, xx, yy)).save("test.gif")
root.after(1000, save_canvas)

Upvotes: 1

Related Questions