Reputation: 511
I'm using Tkinter with Python 3. I want to display something like this, with a particular token showing up behind an overlay:
(This is the overlay, followed by a token, and finally the overlay over the token. The token may not always be centered though behind the overlay.)
The problem is that I need to create these images dynamically. I can't use predefined images .png
or .gif
images. In particular, the colors of these images are going to change frequently, and I don't know them a priori.
All of the sample code that I've seen to create images on a canvas assume that you're loading up a .gif
or .png
, something like this:
token_image = tk.PhotoImage(file="token.png")
canvas = tk.Canvas(width=500, height=500, background="black")
canvas.pack()
token = canvas.create_image((50,50), image=token_image)
But is there a way to do this generating the token_image dynamically? How would you create the irregular shape shown in the overlay, with the circular "bite" taken out of it?
Thanks.
Upvotes: 0
Views: 436
Reputation: 5933
as a basic example:
import tkinter as tk
from PIL import Image, ImageDraw, ImageTk
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.title("Dynamic Image Test")
tk.Label(self, text="Overlay").grid(column=1, row=1, sticky="nesw")
tk.Label(self, text="Token").grid(column=2, row=1, sticky="nesw")
tk.Label(self, text="Combined").grid(column=3, row=1, sticky="nesw")
self.label_1 = tk.Label(self)
self.label_1.grid(column=1, row=2, sticky="nesw")
self.label_2 = tk.Label(self)
self.label_2.grid(column=2, row=2, sticky="nesw")
self.label_3 = tk.Label(self)
self.label_3.grid(column=3, row=2, sticky="nesw")
self.images = [None, None, None]
self.photos = [None, None, None]
self.show_changes()
def overlay(self):
im = Image.new("RGBA", (100,100), (255,255,0,255))
draw = ImageDraw.Draw(im)
draw.ellipse((10,10,90,90),fill=(0,0,0,0))
return im
def token(self):
im = Image.new("RGBA", (100,100), (0,0,0,0))
draw = ImageDraw.Draw(im)
draw.ellipse((0,0,100,100),fill=(0,0,255,255))
draw.line((15,15,85,85),fill=(255,0,0,255), width=5)
draw.line((15,85,85,15),fill=(255,0,0,255), width=5)
return im
def combine(self, overlay, token):
return Image.alpha_composite(token, overlay)
def show_changes(self):
self.images[0] = self.overlay()
self.photos[0] = ImageTk.PhotoImage(self.images[0])
self.label_1.configure(image=self.photos[0])
self.images[1] = self.token()
self.photos[1] = ImageTk.PhotoImage(self.images[1])
self.label_2.configure(image=self.photos[1])
self.images[2] = self.combine(self.images[0], self.images[1])
self.photos[2] = ImageTk.PhotoImage(self.images[2])
self.label_3.configure(image=self.photos[2])
if __name__ == "__main__":
app = App()
app.mainloop()
i was going to do a more complete example, allowing changing the colours on the fly, but i'll be honest and say i can't be bothered.
the ImageDraw module lets you do basic manipulation of images, drawing lines, rectanges ellipses etc, and also supports working in RGBA format (ie transparency) so the colour tuples take the form (red, green, blue, alpha) where all values have a range of 0-255, with 255 meaning fully opaque in the alpha channel.
hopefully this shows you where you need to look to do what you want.
Upvotes: 1