Img

The venerable Img package by Jan Nijtmans, now maintained by Paul Obermeier, provides the handling of several image formats beyond the standard formats in Tk.

Latest version is 1.4.16, released 2023/11/20.

Img source code and binaries for Windows, Linux and Darwin are available at SourceForge .

Synopsis

% package require Tk
% 8.6.13
% image create photo -file wish.ico
ERROR: couldn't recognize data in image file "wish.ico"
% package require Img
1.4.15
% image create photo im -file wish.ico
image1

Description

Img is a Tk extension, adding support for many other Image format. The list below includes many of the supported formats, but is not formally kept in sync with the code:

  • bmp: Windows bitmap format. See img-bmp .
  • gif: The venerable graphics interchange format (with transparency, but without LZW. The latter due to patent issues). See img-gif .
  • ico: Windows icon files. See img-ico .
  • jpeg: The format for lossy compressed still pictures specified by the Joint Picture Experts Group. See img-jpeg .
  • pcx: Paintbrush image format. See img-pcx .
  • pixmap: While the other formats are handlers for the Tk photo image type this is a new image type for Tk. See img-pixmap .
  • png: Portable Network Graphics, successor to GIF. See img-png .
  • ppm: Portable Pixmaps. See img-ppm .
  • ps: Postscript and PDF (Portable document format). Requires an external application, ghostview, for its operation. See img-ps .
  • sgi: Native SGI format. See img-sgi .
  • sun: Sun raster images. See img-sun .
  • tga: Targa files. See img-tga .
  • tiff: Tagged Interchange File Format. See img-tiff .
  • window: ??? (not a file but window snapshot) See img-window .
  • xbm: X Bitmaps. See img-xbm .
  • xpm: X Pixmaps. See img-xpm .

Version 1.4.x only works with Tcl/Tk 8.3 or higher.

Version 1.3 only works with Tcl/Tk 8.2 or higher.

If you are using Tk 8.1 or lower please stick with Img 1.2.4 (which is still available).

And if you are using Tk4.2 or lower, please stick with Img 1.1.4 (which is also still available).


Discussion

GIF and PNG Support

Tk provides built-in support for GIF, and TkPNG is a good alternative to Img for PNG support.

AMG: Recent versions of Tk have built-in PNG support, which was derived from TkPNG.

peterc 2009-09-01: Possibly worth noting that the Unisys GIF/LZW patents expired in mid 2004 [L1 ]. PNG is generally preferred over GIF by most graphics people anyhow as it supports Alpha channel transparency.


Example: converting graphics formats

I often have a need to convert from one graphics format to another. As long as I have ActiveTcl around, the chore is easy; all I need is a script on the order of

    package require Img

    cd /temp

    foreach file [glob *.bmp] {
        set root [file rootname $file]
        set image [image create photo -file $file]
        foreach {format suffix} {JPEG jpg GIF gif PNG png} {
            $image write $root.$suffix -format $format
        }
    }

Capturing a window (or canvas) to an image

Synopsis *

# $W is a Tk window ID
image create photo -format window -data $W

tklib's canvas::snap is based on George Petasis' version of canvas2Photo below.

* Discussion **

(posted by Mark G. Saye in comp.lang.tcl):

proc capture {W format file} {
    set image [image create photo -format window -data $W]
    $image write -format $format $file
    puts "capture -> '$file' ([file size $file] bytes)"
    image delete $image
}

package require -exact Img 1.2.4

set top .t
toplevel $top
frame $top.f
pack  $top.f -fill both -expand 1

label $top.f.hello -text "Hello World"
pack  $top.f.hello -s top -e 0 -f none -padx 10 -pady 10
update
bind $top <Key-x> [list capture $top gif capture.gif]

Saves a white image only, however ;-(. Paul Obermeier has this:

proc canvas2Photo { canvId } {
    # The following line grabs the contents of the canvas canvId into photo image ph.
    set retVal [catch {image create photo -format window -data $canvId} ph]
    if { $retVal != 0 } {
        puts "\n\tFATAL ERROR: Cannot create photo from canvas window"
        exit 1
    } 
    return $ph
}

RS: experimented with this and found that it can convert canvas, text and listbox widgets, but not a compound toplevel. Hence, the name might better be widget2photo... or, by using default error handlers, be simplified to an interp alias:

interp alias {} capture {} image create photo -format window -data

George Petasis 2004-10-24:

I have written an improved version of the canvas2Photo procedure. This one is able to capture *all* canvas items in the image, and not the visible part only...

NOTE: this is now included in tklib as canvas::snap.

proc canvas2Photo {canvas image} {
    ## Ensure that the window is on top of everything else, so as not to get
    ## white ranges in the image, due to overlapped portions of the window with
    ## other windows...
    raise [winfo toplevel $canvas] 
    update
    set border [expr {[$canvas cget -borderwidth] +
                                        [$canvas cget -highlightthickness]}]
    set view_height [expr {[winfo height $canvas]-2*$border}]
    set view_width  [expr {[winfo width  $canvas]-2*$border}]
    foreach {x1 y1 x2 y2} [$canvas bbox all] {break}
    set x1 [expr {int($x1-10)}]
    set y1 [expr {int($y1-10)}]
    set x2 [expr {int($x2+10)}]
    set y2 [expr {int($y2+10)}]
    set width  [expr {$x2-$x1}]
    set height [expr {$y2-$y1}]
    image create photo $image \
            -height $height -width $width
    ## Arrange the scrollregion of the canvas to get the whole window visible,
    ## so as to grab it into an image...
    set scrollregion [$canvas cget -scrollregion]
    set xscrollcommand [$canvas cget -xscrollcommand]
    set yscrollcommand [$canvas cget -yscrollcommand]
    $canvas configure -xscrollcommand {}
    $canvas configure -yscrollcommand {}
    set grabbed_x $x1
    set grabbed_y $y1
    set image_x 0
    set image_y 0
    while {$grabbed_y < $y2} {
        while {$grabbed_x < $x2} {
            $canvas configure -scrollregion [
                list $grabbed_x $grabbed_y [
                expr {$grabbed_x + $view_width}] [
                expr {$grabbed_y + $view_height}]]
            update
            ## Take a screenshot of the visible canvas part...
            image create photo ${image}_tmp \
                -format window -data $canvas
            ## Copy the screenshot to the target image...
            $image copy ${image}_tmp \
                -to $image_x $image_y -from $border $border
            incr grabbed_x $view_width
            incr image_x   $view_width
        }
        set grabbed_x $x1
        set image_x 0
        incr grabbed_y $view_height
        incr image_y   $view_height
    }
    $canvas configure -scrollregion $scrollregion
    $canvas configure -xscrollcommand $xscrollcommand
    $canvas configure -yscrollcommand $yscrollcommand
    return $image
}

Uncategorised discussion

Can anyone provide examples of how to use this package with Tk to display some of the above image types?

MG: Sure..

package require Img
image create photo myJpeg -file "image.jpeg"
pack [label .l -image myJpeg] ;# to show it works ok

It's as simple as that :) As for writing images (after you've executed the above code)...

myJpeg write "image.png" -format PNG

Where can one get freely distributable win32 binaries?

MG: Img is included in the ActiveTcl binaries. I don't know where you can find a binary of Img on its own, though...

[Would be valuable to compare its capabilities with Xbit's.]

A comparison with TclMagick would also be useful.


sheila 2004-10-18:

What is the default format that is returned when one uses the

$image_256.bmp data

as opposed to specifying -format bmp? Looks like a list of lists, and the elements of the list are #rrggbb values. When I use -format bmp I'm guessing I get base64 encoded data. You can go from this format to hex in order to manipulate bits in hex maybe

package require base64

this is a row from the first line of a dump from $image data -format bmp. (this is just a rendition, since the actual characters aren't printable to this screen)

% set row
Qk322AEAAAAAADYEAAAoAAAAkAEAACwBAAABAAgAAAAAAMDUAQBtCwAAbQsAAAABAAAAAQAA

% set d64 [base64::decode $row]

M and binary formated data

% binary scan $d64 H* hex
1
% set hex
424df6d80100000000003604000028000000900100002c0100000100080000000000c0d401006d0b00006d0b00000001000000010000

This example is a Windows BMP 24-bit format. After you get this, you can parse the file to access data of interest. I was curious about how to do a difference operation on two bitmaps, and wanted to xor the rgp data, so I was going to do a parser for the BMP file. I didn't do that after discovering the TclMagick extension for accessing the ImageMagick API (Hmm, I'd like to reduce the footprint of my ImageMagick install).

I'm still curious though. Having the rgb data already conveniently returned in #rrggbb elements is nice. Is there a way to convert that back to a format that can be used to create new bmp images automatically, or would I have to write a generator for creating a new BMP file to pass to image create?

AF: The tklib ico package will read and write BMPs to/from lists of rgb colors and tk images.


Serge Kazantzev: In order to compile tkimg1.3 on MacOSX/Jaguar with Tcl/Tk 8.4, tiff/tiffjpeg.c must be modified as follows: delete line 228: #define CALLVJPEG(sp, op) CALLJPEG(sp, 0, ((op),1)) and replace by: #define CALLVJPEG(sp, op) (SETJMP((sp)->exit_jmpbuf) ? (0) : ((op),1))


SZ: As of version 1.3, Img is very slow. I tried to use it to load images made by 3M+pixel digital camera and it loaded JPEG file in 75 seconds! Same goes to loading of Targa images (I thought it was decoding routines that slow down process).

I did a little investigation and found that Img uses Tk_PhotoPutBlock on every row it read, be it JPEG or Targa. My code (for Targa loading) that does Tk_PhotoPutBlock once complete image loaded works over 50 times (yes, fifty times) faster than Img.

This design decision is spread thinly over all Img image format handlers, as far as I can tell. So it is unreasonably to think that this Img inefficiency could be fixed quickly.

Other route is to fix Tk_PhotoPutBlock. I haven't looked into it yet.

To do not let that stop anyone, I put some workaround (whole image loading for JPEG and Targa images) into the web: [L2 ]. It's ready for Windows, but source code is there too.


Peter Newman 2005-06-07: That's interesting. I have 3 GIF files which, when tiled onto a canvas, with Img, take something like a MINUTE to render. Every other small GIF file will tile in less than a second. I was assuming that maybe these GIF files are corrupt. But I don't think so. So the other alternative was that Img has some bug in it. Which could perhaps be that Tk_PhotoPutBlock thing you mention above.


NJG 2005-06-07:

Perhaps this is the same problem as the one in the tk8.4.9 bug report [L3 ] related to the changes in handling the transparency channel of photo images.

See also: Get the color of the pixel under the pointer


TV 2006-01-28: I was wondering whether someone has compiled Img on 64 bit linux? (I want to use it fedora core 4, 64, and I think it wasn't just compilable, though it's been a while)


JA 2006-02-12: I tried to compile Img with the Borland free compiler under Windows, not Mingw, but I'm not getting anywhere. Has anyone tried it and built it successfully with either the Borland and Microsoft free C/C++ compilers?


PM 2006-03-02: I've submitted a patch on sourceforge Tkimg that fixes the jpeg slowness problem giving about a 20x speedup, using the approach mentioned by SZ above. I note that PPM is also slow, but not by half as bad as jpeg. Other formats like gif and png seem ok as is.


LV: Has anyone written additional img format handlers? If so, have you submitted a feature request to the sf.net project asking for the new handler to be included?


Img -photo has problems under Mac OS X; it renders everything as a black image. [Is there an entry in the "bug database" for this?]


John 2008-4-11: How to configure for compiling/building with MS Visual C++ v6 - Running configure under bash/cygwin forces "uname -s" to generate a cygwin or mingw set of files - Help files for tkimg1.3 indicate build with MS Visual C++ v6 platform is supported. - various google searches produce no clues, except for old (pre-1.2.4) Microsoft Windows builds - am trying to build against tcl/tk8.5.2 core


Mat 2008-06-05: I've found binaries (including win32) of this package at http://www.posoft.de/html/extTkImg.html

PO: I upload binaries compiled from SVN head for Windows (32-bit), Linux (32- and 64-bit), Irix (n32) and Mac (Intel) to the above mentioned page on a regular basis.

2011-12-04 - Newest available binaries are for version 1.4 (Revision 332).


stuart 2009-11-21 18:31:55:

I am having trouble compiling IMG 1.3 (source obtained from sourceforge) on my SunBlade 1000 running Solaris 5.8. Its using an older, Forte 7 compiler, but I don't think the compiler itself is the issue. I get a number of errors like: "sun.c", line 576: undefined symbol: TK_PHOTO_COMPOSITE_OVERLAY "sun.c", line 576: prototype mismatch: 7 args passed, 6 expected "sun.c", line 685: undefined symbol: TK_PHOTO_COMPOSITE_OVERLAY "sun.c", line 685: prototype mismatch: 7 args passed, 6 expected "sun.c", line 784: undefined symbol:

I can't find the string TK_PHOTO_COMPOSITE_OVERLAY any where in the distribution.

Any ideas?

Duoas 2009-11-21 00:45 Z:

Your Tcl/Tk distribution must be 8.2 or later to compile IMG 1.3 (as indicated above). Download the latest Tcl/Tk sources and compile them. Good luck!

{Steve Cohen} 2012-04-30 15:35

Would anyone have any ideas for speeding up the reading of interlaced JPEG files? When I have two files of almost identical resolution the interlaced version takes about ten times as long to read as the non-interlaced version... Curious.


AK 2012-05-01 17:42:14:

The img::jpeg type uses the official libjpeg (*) to perform reading, as such I would suspect that this is where the inefficiency lies.

(Ad *) The version of the library in use is part of the Img sources and build into a package 'jpegtcl' which has no Tcl level commands, only a C-level stubs table the img::jpeg can call on.


uniquename 2014-01-08:

I would like to refer readers of this page to my suggestion for a JFIF-read capability in the 'wish' interpreter --- item 92 on the wiki page Tk 9.0 WishList. I think that you may find the references there (on JPEG-JFIF and JPEG-2000 information) enlightening, as I did --- in particular, the historical-insight quote from the 1999 book by John Miano.


bll 2014-2-6:

This package (version 1.3) is broken on recent debian/ubuntu/linuxmint. Go to: http://packages.debian.org/jessie/libtk-img and scroll down to the bottom of the page to download a fixed version (version 1.4.2). Use dpkg -i <filename> to install it.


andrasy 2016-07-22

Loading JPEG image, if one gets error: Failed to create temporary file then, setting environment variable JPEGMEM may solve problem (for example, try to set it to 1000M).

Set BMP resolution when writing

oehhar 2020-12-04: One may use the optional parameter "-resolution" to set the resolution field when writing BMP:

Here is the definition (I have not found any manual, sorry):

-resolution <list>: Set the resolution property of the output file.
                     The default is 74 dpi (no option)
                     Possible forms for list:
                     {xRes unit} : set x and y resolution to same value
                     {xRes yRes} : set x to 74dpi and y to 74*YRes/XRes
                     {xRes yRes unit} : set x and y resolution to given values
                     xRes, yRes are floats >= 0. 0 is the "no value" value.
                     unit is one of "c" cm, "m" mm, "i" inch or "p" inch/72.

Example1:

set DPI 100
$img write test.bmp -format [list bmp -resolution [list $DPI i]]

Example2:

set DPI 100
set bmpdata [binary decode base64 [$img data -format [list bmp -resolution [list $DPI i]]]

See Also

zlibtcl
tclimage
as far as I can tell, tclimage is a different code base than Img.


arjen - 2022-11-25 08:22:02

I gratefully used the information on this page to do a small experiment with photo files that come from my phone. The images are 4000 by 3000 pixels, so I had to subsample them to fit on the screen. Also they needed to be rotated (sigh), but using a negative subsample factor solved that. Before I tried to make an animated GIF of the set of pictures that show the development of a pond at my workplace, but you have little control over the speed at which it is displayed (at least with an Internet browser). So, a script to display them one by one is my current plan. It will also add the date on the image, as you can easily retrieve that from the file name.