-1

I tried to create an Image using PIL. I wanted to show the image in a tkinter canvas with "create_image" method. But there is no image in the canvas. It looks empty:

self.image = Image.new("RGBA", (w, h), "white")
pixels = self.image.load()

for x in range(w):
    for y in range(h):
        pixels[x, y] = area.get_color(x, y)

photo = ImageTk.PhotoImage(self.image)
self.canvas.create_image(0, 0, image=photo)
self.canvas.pack(fill=tk.BOTH, expand=tk.TRUE)

The method "area.get_color(x, y)" returns a 4-tuple (r, g, b, alpha).

jgsedi
  • 227
  • 4
  • 18
  • 2
    Please create a [mcve]. – Bryan Oakley Feb 11 '18 at 22:38
  • Ok, I would need some executable code from you to verify this, but I have a strong feeling that your `pixels` is just a copy of your canvas instead of the canvas itself, changing that would not affect the actual canvas. You would need to write your pixels back to the image to display it. – Yunkai Xiao Feb 11 '18 at 23:43
  • Your algorithm works for me. Have you checked that the values returned by `get_color()` are different to the canvas background colour? – mhawke Feb 12 '18 at 00:07
  • @mhawke yes i did – jgsedi Feb 12 '18 at 10:21
  • what do you mean "to write the pixels back tho the image" @YunkaiXiao – jgsedi Feb 12 '18 at 10:22
  • @jgsedi Never mind, I just found that pixels generated from image.load() is actually a reference, so changes on it should get reflected on the image immediately. BTW check out my answer, I just tested it and it works. – Yunkai Xiao Feb 13 '18 at 00:26

2 Answers2

3

Well, few things:

First of all, python has this weird garbage collecting issue with tkinter images, in order to really pass the image to your canvas, you need to anchor down first otherwise it would just got wiped when it was passed to canvas.

This is what i did after learning from other people's example:

window.image = create_image(WIDTH, HEIGHT)

Once you anchor it down to your Tk(), it shouldn't get collected and erased anymore as long as your Tk() exists.

Second problem is your placement of image, you might want to place it to the center of your canvas instead of the corner of it:

canvas.create_image(WIDTH//2, HEIGHT//2, image=window.image)

In the end your program would look like this:

window = tk.Tk()
canvas = tk.Canvas(window, width=WIDTH, height=HEIGHT)
window.image = create_image(WIDTH, HEIGHT)
canvas.create_image(WIDTH//2, HEIGHT//2, image=window.image)
canvas.pack(fill=tk.BOTH, expand=tk.TRUE)

window.mainloop()

BTW a circle of a radius of 10 is just too small in a canvas of 640 x 480, you might want to increase this number to 100 or so.

if x**2 + y**2 < 10000:

Like that^

Yunkai Xiao
  • 191
  • 12
  • ok thanks. i tried two versions of code one with a attribute on window and one with a global var - both variants are showing the picture. Thanks – jgsedi Feb 13 '18 at 19:54
  • @jgsedi Yes, it's really just a question about how to preserve the image from getting collected by garbage collector. – Yunkai Xiao Feb 13 '18 at 21:18
0

I posted just the relevant part of a pupils project code. They tried to create a tkinter application showing a fractal. But they should do it in an absolute (crazy) objectoriented manner. After that it should be done in a very much faster implementation.

All the other code works fine (all tests ok), only the PIL part ...

Ok i create a small piece of code to show the pupils idea. But this code doesn't show a black piece of a circle as expected. The canvas is still empty:

import tkinter as tk
from PIL import Image, ImageTk


WHITE = (255, 255, 255, 255)
BLACK = (0, 0, 0, 255)
WIDTH = 640
HEIGHT = 480


def get_color(x, y):
    if x**2 + y**2 < 100:
        return BLACK
    else:
        return WHITE


def create_image(w, h):
    image = Image.new("RGBA", (w, h), "white")
    pixels = image.load()
    for x in range(w):
        for y in range(h):
            pixels[x, y] = get_color(x, y)

    return ImageTk.PhotoImage(image)


window = tk.Tk()
canvas = tk.Canvas(window, width=WIDTH, height=HEIGHT)
canvas.create_image(0, 0, image=create_image(WIDTH, HEIGHT))
canvas.pack(fill=tk.BOTH, expand=tk.TRUE)

window.mainloop()
jgsedi
  • 227
  • 4
  • 18