python tkinter: how to work with pixels?
Asked Answered
H

2

23

using google (and this site) i have seen some similar questions but my problem is still here:

"i want to draw an image (without reading a file) , being able to manipulate every single pixel's colour in that image."

i have seen another question where was suggested to do something like this:

from tkinter import *
A=Tk()
B=Canvas(A)
B.place(x=0,y=0,height=256,width=256)
for a in range(256):
    for b in range(256):
        B.create_line(a,b,a+1,b+1,fill=pyList[a][b])#where pyList is a matrix of hexadecimal strings
A.geometry("256x256")
mainloop()

in fact this answers my question but... it is extremely slow. what should i do with a 1920x1080 image ? wait for my death?

so i am asking something to perform the same as the above code but in a faster way

i have found a way to improve the method suggested by jsbueno , it is explained in the page linked :

Why is Photoimage put slow?

Himes answered 5/9, 2012 at 14:58 Comment(7)
"... without using any third-party module." Why? Tkinter's canvas was not designed to be managed pixel-by-pixel.Flotation
ok if the canvas does not allow to do it fastly , what other tkinter widget should i use to do it? P.S. i modifyed the questionHimes
There is nothing in Tkinter to do what you want quickly. So again I ask, why no third party modules? It seems unnecessary restriction.Flotation
ok you can link me some non official modules - but they must be cross platformHimes
I have little experience with image processing, but the main candidates seem to be PIL, python bindings for ImageMagic, Pycairo, and scipy.ndimage. I know that PIL runs on Windows, Mac, and Linux and plays nicely with Tkinter.Flotation
ok , at least it is an answer, i found only PIL and Pycairo too but i wanted to do it with tkinter. tkinter is slow and so i decide: i will use PIL. could you post an answer with an example of how to use PIL?(or a link to a tutorial)Himes
Individual manipulation of pixels from Python like the O.P. wants should be no faster in PIL than using Tkinter directly as in my answer bellow. Even other libraries will run at about the same speed for that - one still have a Python function call per pixel. The only way to go faster is having your drawing primitives running in another language. Or, using JIT accelerated Pypy - check pypy.orgBuddle
B
41

It is indeed tricky -- I thought you had to use a Canvas widget, but that has no access to Pixels either. Image items embedded in the Canvas do have, though. The Tkinter.PhotoImage class does have a "put" method that accepts a color in hex format and pixel coordinates:

from tkinter import Tk, Canvas, PhotoImage, mainloop
from math import sin

WIDTH, HEIGHT = 640, 480

window = Tk()
canvas = Canvas(window, width=WIDTH, height=HEIGHT, bg="#000000")
canvas.pack()
img = PhotoImage(width=WIDTH, height=HEIGHT)
canvas.create_image((WIDTH/2, HEIGHT/2), image=img, state="normal")

for x in range(4 * WIDTH):
    y = int(HEIGHT/2 + HEIGHT/4 * sin(x/80.0))
    img.put("#ffffff", (x//4,y))

mainloop()

The good news is that even it being done this way, the updates are "live": you set pixels on the image, and see them showing up on screen.


This should be much faster than the way drawing higher level lines on screen - but for lots of pixels it still will be slow, due to a Python function call needed for every pixel. Any other pure python way of manipulating pixels directly will suffer from that - the only way out is calling primitives that manipulate several pixels at a time in native code from your Python code.

A nice cross-platform library for getting 2d drawing, however poorly documented as well is Cairo - it would should have much better primitives than Tkinter's Canvas or PhotoImage.

Buddle answered 5/9, 2012 at 17:54 Comment(5)
Well - you can always accept the answer, if it fits. If you object is creating a Gane, I 'd suggest using pre-made images, and moving the images on the Tkinter Canvas, as per #12250617Buddle
I know that. You can't use regular cPython for a videogame that requires pixel by pixel acess of image. Still...very few videogame styles actually require it - they are rather done by rendering 3d objects/scene with a low level library - in which case it is ok to use python to position all objects in your scene and call teh render function, or simply redrawing the view moving 2D shapes around - which is also ok with Python. Still, you can achieve about a 10 fold improvement over regular Python by using Pypy - I just don't know which multimedia able libraries will br available.Buddle
Coming in a decade later to say "from Tkinter" needs to be lowercase (and also thank you for the answer)Frodine
well, a decade ago it was usually uppercase. That is on of the changes from Python2 to Python3Buddle
Best answer after searching for several hours! PhotoImage is not even mentioned in "Modern Tkinter for Busy Python Developers" by Mark Roseman :-(Slier
S
7

Don't forget to save a reference after canvas.create_image. In some cases, especially when working with the PIL module, python will garbage-collect the image, even though it is being displayed! Syntax is something like canvas.create_image((WIDTH/2, HEIGHT/2), image=img) canvas.image = img

Sol answered 25/12, 2016 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.