Saving a Tkinter Canvas Drawing (Python)

vegaseat 4 Tallied Votes 19K Views Share

The Tkinter GUI toolkit's canvas object is very nice for all sorts of drawings and plotting. However, when it comes to saving the image Tkinter limits you to postscript printer files. One solution is to draw the same image in parallel on PIL's image-draw object in memory. This is made relatively simple, as the Tkinter and PIL methods function pretty much the same.

Here is a Python code snippet showing you the basics in the form of a plot of two trig functions.

# plot functions like y = sin(x) and y = cos(x) 
# with Tkinter canvas and line (visible), but can be saved only in .ps format 
# simultaneously use
# PIL image, draw, line (draws in memory, but can be saved in many formats)
# Python Image Library (PIL) free from:
# http://www.pythonware.com/products/pil/index.htm
# tested with Python24      vegaseat       15may2007

# use namespace to avoid conflict with PIL's Image
import Tkinter as tk
import math
import os
# needs Python Image Library (PIL)
import Image, ImageDraw

# some color constants for PIL
white = (255, 255, 255)
black = (0, 0, 0)
blue = (0, 0, 255)
red = (255, 0, 0)
green = (0,128,0)

root = tk.Tk()
root.title("Simple plot using canvas and line")

width = 400
height = 300
center = height//2
x_increment = 1
# width stretch
x_factor = 0.04
# height stretch
y_amplitude = 80

# Tkinter create a canvas to draw on
cv = tk.Canvas(width=width, height=height, bg='white')
cv.pack()

# PIL create an empty image and draw object to draw on
# memory only, not visible
image1 = Image.new("RGB", (width, height), white)
draw = ImageDraw.Draw(image1)

# create the coordinate list for the sin() curve
# have to be integers for Tkinter
sine_list = []
for x in range(400):
    # x coordinates
    sine_list.append(x * x_increment)
    # y coordinates
    sine_list.append(int(math.sin(x * x_factor) * y_amplitude) + center)

# create the coordinate list for the cos() curve
cos_list = []
for x in range(400):
    # x coordinates
    cos_list.append(x * x_increment)
    # y coordinates
    cos_list.append(int(math.cos(x * x_factor) * y_amplitude) + center)

# do the Tkinter canvas drawings (visible)
str1 = "sin(x)=blue  cos(x)=red"
cv.create_text(10, 20, anchor='sw', text=str1)
center_line = cv.create_line([0, center, width, center], fill='green')
sin_line = cv.create_line(sine_list, fill='blue')
cos_line = cv.create_line(cos_list, fill='red')

# Tkinter canvas object can only be saved as a postscipt file
# which is actually a postscript printer language text file
cv.postscript(file="my_drawing.ps", colormode='color')

# do the PIL image/draw (in memory) drawings
draw.text((10, 20), str1, black)
draw.line([0, center, width, center], green)
draw.line(sine_list, blue)
draw.line(cos_list, red)

# PIL image can be saved as .png .jpg .gif or .bmp file
filename = "my_drawing.jpg"
image1.save(filename)

# to test, view the saved file, works with Windows only
# behaves like double-clicking on the saved file
os.startfile(filename)

root.mainloop()
MSV22 0 Newbie Poster

Hi

I am drawing different figures like circle,rectangle,line etc in my application. I am using wxpython. I have created a menu. I want to save the file and store its content . I have created the file dialog. But I am not getting how to store the contents.How do I go about it??
Do I have to use Cpickle?? I tried understanding it but not much luck in that.

Thanks

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

To do a similar thing with wxPython see:
http://www.daniweb.com/forums/post1070295.html#post1070295

MSV22 0 Newbie Poster

Thank you for the quick reply :)

MatthiasBl 0 Newbie Poster
def savebitmap(event):
   form = "Saving {0}%"
   img = PhotoImage(width = canvas_width, height = canvas_height)
   perc = -1
   for y in range(canvas_height):
      perc1 = (100*y) // canvas_height
      if perc1 != perc:
         perc = perc1
         setmessage(form.format(perc), True)
      row = "{"
      for x in range(canvas_width):
         ids = w.find_overlapping(x, y, x, y)
         color = w.itemcget(ids[-1], "fill") if ids else canvas_background
         row += color + " "
      img.put(row + "}", (0, y))
   img.write("kritzel.ppm", format="ppm")
   setmessage()

This is my way to save the canvas elements as bitmap.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.