AMG: I collected code from other Wiki pages on reading image dimensions of various formats (GIF, PNG, JPEG, and BMP) and made a single proc that can determine the type and dimensions all at once.
The argument is the name of the channel connected to the image data.
The image is expected to begin at the current channel seek position, and the channel must have "binary" translation.
The returned value is a one- or three-element list. The first element is the type, which is gif, png, jpeg, bmp, or unknown. The second and third elements are the image width and height in pixels; they're omitted if the first element is unknown.
proc imageinfo {chan} { set tell [chan tell $chan] if {[chan read $chan 16] eq "\211PNG\r\n\32\n\0\0\0\rIHDR"} { set type png binary scan [chan read $chan 8] II width height } elseif {"[chan seek $chan $tell][chan read $chan 6]" in {GIF87a GIF89a}} { set type gif binary scan [chan read $chan 4] ss width height } elseif {"[chan seek $chan $tell][chan read $chan 2]" eq "\377\330"} { set type jpeg while {![chan eof $chan]} { while {[chan read $chan 1] ne "\377"} {} while {[set byte [chan read $chan 1]] eq "\377"} {} if {$byte in {\300 \301 \302 \303 \305 \306 \307 \311 \312 \313 \315 \316 \317}} { binary scan [chan read $chan 7] x3SS height width break } else { binary scan [chan read $chan 2] S offset chan seek $chan [expr {($offset & 0xffff) - 2}] current } } } elseif {"[chan seek $chan $tell][chan read $chan 2]" eq "BM"} { set type bmp binary scan [chan read $chan 24] x16ii width height } if {[info exists type] && [info exists width] && [info exists height]} { list $type [expr {$width & 0xffff}] [expr {$height & 0xffff}] } else { list unknown } }
I designed it for use with the SQLite [$db incrblob] command, which produces a channel providing incremental access to a database blob. It's also suitable for use with ordinary file I/O. Remember to close the channel when you're done with it.