Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python tkinter: how to work with pixels?

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?

like image 837
Alberto Perrella Avatar asked Sep 05 '12 14:09

Alberto Perrella


People also ask

Can tkinter display images?

Tkinter's label widget can be used to display either images or text. To display an image requires the use of Image and ImageTk imported from the Python Pillow (aka PIL) package.

Does tkinter work with PNG?

Tkinter PhotoImage only supports the GIF, PGM, PPM, and PNG file formats.

Can tkinter read JPG?

It can open various image formats including PPM, PNG, JPEG, GIF, TIFF, and BMP.


2 Answers

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.

like image 92
jsbueno Avatar answered Oct 16 '22 05:10

jsbueno


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

like image 39
EriktheRed Avatar answered Oct 16 '22 06:10

EriktheRed