Search code examples
pythontkinterpython-imaging-librarypython-turtle

how to save turtle drawing as a png?


i am making a paint like app in python using tkinter and turtle. im trying to save the image drawn as a png.

short version of my program :

import tkinter as tk
from functools import partial
from turtle import TurtleScreen, RawTurtle, Shape
from PIL import Image

def draw(x, y):
    turtle.ondrag(None)
    turtle.pendown()
    turtle.goto(x, y)
    turtle.penup()
    screen.update()
    turtle.ondrag(draw)

def move(x, y):
    screen.onclick(None)
    turtle.goto(x, y)
    screen.onclick(move)
    screen.update()
    

def set_color(color):
    global pen_color
    pen_color = color
    turtle.pencolor(color)
    screen.update()
    
    # --- add widgets ---

root = tk.Tk()

canvas = tk.Canvas(root, width=500, height=500)
canvas.pack(side='right', expand=True, fill='both')

frame = tk.Frame(root)
frame.pack(side='left', fill='y')

tk.Label(frame, text='COLORS').grid(column=0, row=0)

tk.Button(frame, bg='red', width=10, command=partial(set_color, 'red')).grid(column=0, row=1)
tk.Button(frame, bg='yellow', width=10, command=partial(set_color, 'yellow')).grid(column=0, row=2)
tk.Button(frame, bg='green', width=10, command=partial(set_color, 'green')).grid(column=0, row=3)
tk.Button(frame, bg='blue', width=10, command=partial(set_color, 'blue')).grid(column=0, row=4)
tk.Button(frame, bg='black', width=10, command=partial(set_color, 'black')).grid(column=0, row=5)

def save () :
    drawing = screen.getcanvas()
    drawing.postscript(file='drawing.ps')
    img = Image.open( 'drawing.ps')
    img.save('drawing.png')
    print('...dumping gui window to png')
bsave = tk.Button(
    frame,
    text='save *',
    width=10,
    command=save
)
bsave.grid(column=0, row=6)

screen = TurtleScreen(canvas)
screen.tracer(False)

pen_color = 'black'

turtle = RawTurtle(screen)
#turtle.hideturtle()
turtle.shape("circle")
polygon = turtle.get_shapepoly()
fixed_color_turtle = Shape("compound")
fixed_color_turtle.addcomponent(polygon, "", "")
screen.register_shape('fixed', fixed_color_turtle)
turtle.shape("fixed")
turtle.penup()
turtle.pensize(5)
turtle.turtlesize(2000,2000)
turtle.ondrag(draw)
screen.onscreenclick(move)
screen.update()
screen.mainloop()

when i run this i get the error : OSError : Unable to locate Ghostscript on paths

i want to save the image without using ghostscript as this program need to run on the school computers and they don't have it.

i also tried this but the x and y values returned are always wrong

def save () :
    x0 = frame.winfo_rootx()
    y0 = frame.winfo_rooty()
    x1 = x0 + frame.winfo_width()
    y1 = y0 + frame.winfo_height()
    ImageGrab.grab().crop((x0, y0, x1, y1)).save('painting.png')

Solution

  • Your ImageGrab approach was almost there. The only change I have made is to use root instead of frame. Sometimes it useful to adjust the result by the total border thickness which is composed of borderthickness and highlightthickness but in this case it seems that it is not necessary. Use it in another context if needed. The usual default values are assigned to the variables:

    import tkinter as tk
    from functools import partial
    from turtle import TurtleScreen, RawTurtle, Shape
    from PIL import Image
    from PIL import ImageGrab
    
    def draw(x, y):
        turtle.ondrag(None)
        turtle.pendown()
        turtle.goto(x, y)
        turtle.penup()
        screen.update()
        turtle.ondrag(draw)
    
    def move(x, y):
        screen.onclick(None)
        turtle.goto(x, y)
        screen.onclick(move)
        screen.update()
        
    
    def set_color(color):
        global pen_color
        pen_color = color
        turtle.pencolor(color)
        screen.update()
        
        # --- add widgets ---
    
    root = tk.Tk()
    
    canvas = tk.Canvas(root, width=500, height=500)
    canvas.pack(side='right', expand=True, fill='both')
    
    frame = tk.Frame(root)
    frame.pack(side='left', fill='y')
    
    tk.Label(frame, text='COLORS').grid(column=0, row=0)
    
    tk.Button(frame, bg='red', width=10, command=partial(set_color, 'red')).grid(column=0, row=1)
    tk.Button(frame, bg='yellow', width=10, command=partial(set_color, 'yellow')).grid(column=0, row=2)
    tk.Button(frame, bg='green', width=10, command=partial(set_color, 'green')).grid(column=0, row=3)
    tk.Button(frame, bg='blue', width=10, command=partial(set_color, 'blue')).grid(column=0, row=4)
    tk.Button(frame, bg='black', width=10, command=partial(set_color, 'black')).grid(column=0, row=5)
    
    def save () :
    
        bordterthickness = 2
        highlightthickness = 1
        brdt = bordterthickness + highlightthickness
        
        x0 = frame.winfo_rootx()
        y0 = frame.winfo_rooty()
        x1 = x0 + root.winfo_width() 
        y1 = y0 + root.winfo_height()
        ImageGrab.grab().crop((x0, y0, x1, y1)).save('saveScreenshot.png')
    
    bsave = tk.Button(
        frame,
        text='save *',
        width=10,
        command=save
    )
    
    bsave.grid(column=0, row=6)
    
    screen = TurtleScreen(canvas)
    screen.tracer(False)
    
    pen_color = 'black'
    
    turtle = RawTurtle(screen)
    #turtle.hideturtle()
    turtle.shape("circle")
    polygon = turtle.get_shapepoly()
    fixed_color_turtle = Shape("compound")
    fixed_color_turtle.addcomponent(polygon, "", "")
    screen.register_shape('fixed', fixed_color_turtle)
    turtle.shape("fixed")
    turtle.penup()
    turtle.pensize(5)
    turtle.turtlesize(2000,2000)
    turtle.ondrag(draw)
    screen.onscreenclick(move)
    screen.update()
    screen.mainloop()
    

    Below a screenshot of the Window:

    window

    Here the result of clicking the save button:

    screenshot