''[Richard Suchenwirth] -- [Tk] [image]s ([bitmap], [photo], and whatever the future may bring) are handy and indispensable for fancy displays. This page shows how to enjoy them with even fewer problems (as pop up every now and then in news:comp.lang.tcl).'' '''DO DELETE UNWANTED IMAGES''': It is easy to create an image, but in more complex applications large numbers of images may hang around cramming the memory (so-called "leaks" in Tcl would mostly come from such images). So, make it a rule to delete those images when you no longer need them. In an extreme case, you can sanitize an [interp] of '''all''' images with foreach name [image names] { image delete $name } Such extreme hygiene can be handy in restoring the state of long-running processes. Also, images are memory objects. You can display the same image at various places of your GUI. No need to create it more than once, especially not in a loop. [Zarutian] 13. july 2005: here is a way to delete all unused images from thie interpreter. foreach name [image names] { if {![image inuse $name]} { image delete $name } } '''DON'T FILL photo IMAGES PIXEL BY PIXEL!''' It looks intuitive, but is extremely slow to write for {set x 0} {$x<$xmax} {incr x} { for {set y 0} {$y<$ymax} {incr y} { $photo put $color -to $x $y } } Rather, build up the data as a list of rows, each being a list of colors, and feed them to ''$photo put'' in one go: set data {{red yellow green blue} {white black orange purple} ...} $photo put $data -to 0 0 ''SH: If you still want to draw pixel by pixel and you know how large your image becomes, first draw the left bottom pixel to allocate the memory for the whole image. If you don't do that, each new pixel to draw results in a newly allocation of memory, that's slow. Another way is to specify the size of the image when creating it.'' ''You can also speed up drawing, by first deleting the image from the canvas, then drawing the pixels and then recreating it in the canvas.'' '''DON'T GIVE AN IMAGE NAME -- TAKE ONE!''' You may give an image a name at creation time, but maybe you shouldn't -- because a command with that name is created and might silently overwrite the original command or proc, be that "open", "close", or "menu" ''(DKF: you get a particularly interesting crash if you name the image "." as this completely blows Tk away within the current interpreter or crashes the whole app, depending on the version you are using)'' If you don't give an image name, image will give you a constructed name which will very probably not interfere with a proc. Example: don't say image create photo menu -arg ... but say set img(menu) [image create photo -arg ...] and use $img(menu) (which will look like image47) ever after. ''DKF: I have edited the above to use an array; I find that more visually pleasing and less likely to interfere with anything else that is lying around...'' '''DON'T USE THE -data OPTION!''' [Jan Nijtmans] wrote in [the comp.lang.tcl newsgroup]: Even faster should be not to use the "-data" option, but the " put" command. This is almost equivalent, but it prevents the storage of a copy of the binary data in memory. Just replace the line: image create photo $pic -data $data by the two lines: image create photo $pic $pic put $data ulis, 2003-07-05: '''-data''' and '''put''' are NOT almost equivalent. * '''-data''' is cooked and receives a structured image (as a gif image) * '''put''' is raw and receives lines of pixels (CJL - 'put' now treats its input as raw pixels only if it matches no known format) See the header note at [Serializing a photo]. ` ''[Ro] notes:'' If you use the line: image create photo $pic -data $data then it will throw an error if you are reading from a file of length zero. But if you use the two lines: image create photo $pic $pic put $data then it will not throw an error if you are reading from a file of length zero. But it will prevent the storage of a copy of the binary data in memory, as noted above by Jan Nijtmans. The moral of the story is: If you use the two latter lines, don't forget to check if the file is empty first, because otherwise, it will resize your picture to no size and not throw an error. This can be annoying if your picture is displaying in its own window and then all of a sudden you have a very small window to manipulate and you have to depend on your window manager to resize the window or close it. This was tested on a GNU/Linux system with X11R6 4.0.1a ''[DKF] notes:'' Actually, '''[image] put''' can take any sort of image data that the '''-data''' option can. It uses the same extensible image parsing engine underneath. ---- See http://www.satisoft.com/tcltk/icons/ for one source of images to use as [Tk] [icons]. Perhaps people will add other sources for this sort of thing. ---- [BHE]: A lot of these ideas are really helpful. I tried to do something like this: namespace eval test { image create photo theImage } image inuse test::theImage; # returns 0 image inuse theImage; # returns 1 hmm. I wanted to create the image within the test namespace so it wouldn't destroy "::theImage". What about this? namespace eval test { image create photo test::theImage } image inuse test::theImage; # returns 0! why? namespace eval test { image inuse theImage; # returns 0 image inuse test::theImage; # returns 1 } What's going on here? I gave up and switched to using the image name generated as recommended above, storing the name as an array value instead: namespace eval test { variable images set images(theImage) [image create photo] } [MG] Images are created with the name you give them, without respect to namespaces. To do what you meant, you need to do: image create photo ::test::theImage Also note that, according to the docs for Tk 8.4, ''image inuse'' returns 1 if the image is being used by a widget currently, and 0 otherwise (not whether it exists or not), which most wouldn't be anyway right after creation. ---- [BHE]: One other thing. I needed a way to "cut" an area out of an image and save it as a new image, leaving a transparent block. [image] doesnt have anything like that - the closest thing is $dst copy $src -from x1 y1 x2 y2, but the area remains in the source obviously. You could do this: set src [image create photo] set bgcolor black # load the source ... let's say it's 32x32 set dst [image create photo] $dst copy $src -from 5 5 10 10 $src put $bgcolor -to 5 5 10 10 But what do you do if you want to leave a transparent block after "cutting"? For that matter, how can you simply erase an area instead of an entire picture? ("$src blank" will delete everything.) You can use a blank photo and the "$image put" command with -compositingrule as "set" instead of "overlay" set eraser [image create photo] $src copy $eraser -to 5 5 10 10 -compositingrule set image delete $eraser ---- [yadav]Hi i am new to TclTk..And now i am stuck at an important stage...i wanna optimize a ram read from Tk which displays that ram read as Picture...The Ram contains binary data.....So now i have a working code but very slow..............Would welcome any suggestions regarding this.. can mail at yadraj@yahoo.com Thanks ----------- See also [Images with transparency and plain images] ----------------- [Category Graphics] | [Don't do that] | [Arts and crafts of Tcl-Tk programming]