HaskellElephant
HaskellElephant

Reputation: 9891

Why is Photoimage put() slow?

When manipulating PhotoImage objects with:

import tkinter as tk

img = tk.PhotoImage(file="myFile.gif")
for x in range(0,1000):
  for y in range(0,1000):
    img.put("{red}", (x, y))

The put operation takes a very long time. Is there a faster method of doing this?

Upvotes: 8

Views: 6406

Answers (3)

JCKE
JCKE

Reputation: 394

Simply using the to optional parameter of the put() command is enough, no need to create a complex string:

import tkinter as tk
root = tk.Tk()

img = tk.PhotoImage(width=1000, height=1000)
data = 'red'
img.put(data, to=(0, 0, 1000, 1000))
label = tk.Label(root, image=img).pack()

root_window.mainloop()

Further observations

I couldn't find much in the way of documentation for PhotoImage, but the to parameter scales the data much more efficiently than a standard loop would. Here's some info I would have found helpful that doesn't seem to be properly documented well online.

The data parameter takes in a string of space-separated color values that are either named (official list), or an 8-bit color hex code. The string represents an array of colors to be repeated per pixel, where rows with more than one color are contained in curly braces and columns are just space separated. The rows must have the same number of columns/colors.

acceptable:
3 column 2 row: '{color color color} {color color color}'
1 column 2 row: 'color color', 'color {color}'
1 column 1 row: 'color', '{color}'

unacceptable:
{color color} {color}

If using a named color containing spaces, it must be encased in curly braces. ie. '{dodger blue}'

Here are a couple examples to illustrate the above in action, where a lengthy string would be required:

img = tk.PhotoImage(width=80, height=80)
data = ('{{{}{}}} '.format('{dodger blue} ' * 20, '#ff0000 ' * 20) * 20 +
        '{{{}{}}} '.format('LightGoldenrod ' * 20, 'green ' * 20) * 20)
img.put(data, to=(0, 0, 80, 80))

enter image description here

data = ('{{{}{}}} '.format('{dodger blue} ' * 20, '#ff0000 ' * 10) * 20 +
        '{{{}{}}} '.format('LightGoldenrod ' * 20, 'green ' * 10) * 10)

enter image description here

Upvotes: 6

noob oddy
noob oddy

Reputation: 1339

Use a bounding box:

from Tkinter import *
root = Tk()
label = Label(root)
label.pack()
img = PhotoImage(width=300,height=300)
data = ("{red red red red blue blue blue blue}")
img.put(data, to=(20,20,280,280))
label.config(image=img)
root.mainloop()

Upvotes: 7

soulcheck
soulcheck

Reputation: 36767

Try constructing a 2d array of colors and call put with that array as parameter.

Like this:

import tkinter as tk

img = tk.PhotoImage(file="myFile.gif")
# "#%02x%02x%02x" % (255,0,0) means 'red'
line = '{' + ' '.join(["#%02x%02x%02x" % (255,0,0)] * 1000) + '}'
img.put(' '.join([line] * 1000))

Upvotes: 3

Related Questions