Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a bitmap real quick in python using Tk only?

Here is a problem. I want to visualize a specific vector field as a bitmap. It's ok with the representation itself, so I allready have some matrix of RGB lists like [255,255,115], but I have no good idea of how to draw it on screen. So far I make thousands of colored 1px rectangles, but this works too slow. I'm sure there is a better way to draw a bitmap.

like image 910
akalenuk Avatar asked Oct 17 '09 09:10

akalenuk


2 Answers

ATTEMPT 3 - I swear last one...

I believe this is the fastest pure TK way to do this. Generates 10,000 RGB values in a list of lists, creates a Tkinter.PhotoImage and then puts the pixel values into it.

import Tkinter, random
class App:
    def __init__(self, t):
        self.i = Tkinter.PhotoImage(width=100,height=100)
        colors = [[random.randint(0,255) for i in range(0,3)] for j in range(0,10000)]
        row = 0; col = 0
        for color in colors:
           self.i.put('#%02x%02x%02x' % tuple(color),(row,col))
           col += 1
           if col == 100:
               row +=1; col = 0        
        c = Tkinter.Canvas(t, width=100, height=100); c.pack()
        c.create_image(0, 0, image = self.i, anchor=Tkinter.NW)

t = Tkinter.Tk()
a = App(t)    
t.mainloop()

ATTEMPT 1 - using the create_rectangle method

I wrote this as a test. On my Intel Core 2 duo at 2.67 Ghz, it'll draw about 5000 pixels in 0.6 seconds including the time to generate my random RGB values:

from Tkinter import *
import random

def RGBs(num):
 # random list of list RGBs
 return [[random.randint(0,255) for i in range(0,3)] for j in range(0,num)]

def rgb2Hex(rgb_tuple):
    return '#%02x%02x%02x' % tuple(rgb_tuple)

def drawGrid(w,colors):
 col = 0; row = 0
 colors = [rgb2Hex(color) for color in colors]
 for color in colors:
  w.create_rectangle(col, row, col+1, row+1, fill=color, outline=color)
  col+=1
  if col == 100:
   row += 1; col = 0

root = Tk()
w = Canvas(root)
w.grid()
colors = RGBs(5000)
drawGrid(w,colors)
root.mainloop()

ATTEMPT 2 - Using PIL

I know you said TK only but PIL makes this really easy and fast.

def rgb2Hex(rgb_tuple):
    return '#%02x%02x%02x' % tuple(rgb_tuple)

num = 10000 #10,000 pixels in 100,100 image
colors = [[random.randint(0,255) for i in range(0,3)] for j in range(0,num)]
colors = [rgb2Hex(color) for color in colors]
im = Image.fromstring('RGB',(100,100),"".join(colors))
tkpi = ImageTk.PhotoImage(im)
## add to a label or whatever...
label_image = Tkinter.Label(root, image=tkpi)
like image 103
Mark Avatar answered Oct 04 '22 04:10

Mark


There is a faster pure tkinter method:

import Tkinter, random
import random

class App:
    def __init__(self, t):
        self.width = 320
        self.height = 200
        self.i = Tkinter.PhotoImage(width=self.width,height=self.height)
        rgb_colors = ([random.randint(0,255) for i in range(0,3)] for j in range(0,self.width*self.height))
        pixels=" ".join(("{"+" ".join(('#%02x%02x%02x' %
            tuple(next(rgb_colors)) for i in range(self.width)))+"}" for j in range(self.height)))
        self.i.put(pixels,(0,0,self.width-1,self.height-1))
        c = Tkinter.Canvas(t, width=self.width, height=self.height); c.pack()
        c.create_image(0, 0, image = self.i, anchor=Tkinter.NW)

t = Tkinter.Tk()
a = App(t)    
t.mainloop()

You can use put() to draw a rectangle with some color data (a string), in this case the whole image. This way you don't need the loop which is quite expensive.

like image 33
pythonista Avatar answered Oct 04 '22 03:10

pythonista