Reads TGA images into an easily manipulatable format. Requires fishpool.easyOps 0.1, which can be found at http://www.fishpool.com/~setok/proj/easyOpers.tcl. The idea would be to collect a whole series of these under the same namespace for managing different image formats. namespace import ::easyOps::* # Reads image from file 'filePath', interprets it as a TGA image and # returns it as a list that can be used with Tk photos: # A list of lists. Each list is one row of the image and contains # pixels in the following format #RRGGBB, with R, G and B being HEX # values for red, green and blue, respectively. proc readData {filePath} { set imageFile [open [lindex $filePath 0] r] fconfigure $imageFile -translation binary -encoding binary set fileData [read $imageFile] close $imageFile array set header [getHeader $fileData] array set imageSpec [getImgSpec $fileData] # Pixels # :NOTE: We assume colour map is 0 for now (just deal with # truecolour). # Naughty naughty. set pixels [string range $fileData [+ 18 $header(idLength)] \ [+ 18 $header(idLength) \ [* $imageSpec(width) \ $imageSpec(height) \ [/ $imageSpec(pixDepth) 8]] -1]] # Check order to process pixels in. We always build the list from top # to bottom, left to right. if {$imageSpec(rightLeft)} { # Image should be draw from right to left set startX $imageSpec(width) set endX -1 set incrX -1 } else { set startX 0 set endX [- $imageSpec(width) 1] set incrX 1 } if {$imageSpec(topDown)} { # Image should be drawn from top to bottom set startY 0 set endY $imageSpec(height) set incrY 1 } else { set startY [- $imageSpec(height) 1] set endY -1 set incrY -1 } set imageDat [list] for {set y $startY} {$y != $endY} {incr y $incrY} { set row [list] for {set x $startX} {$x != $endX} {incr x $incrX} { set idx [* [+ [* $y $imageSpec(width)] $x] 3] set rgbString [string range $pixels $idx [+ $idx 2]] binary scan $rgbString "ccc" b g r set r [& $r 0xFF] set g [& $g 0xFF] set b [& $b 0xFF] lappend row "#[format "%02x%02x%02x" $r $g $b]" } lappend imageDat $row } return $imageDat } ## Get image specification. ## ## 'imgData' contains the full TGA data, including headers. ## ## Returns key-value list with the following fields: xOrigin, yOrigin ## width, height, pixDepth, alpha, rightLeft, topDown. ## xOrigin, yOrigin Abolute co-ordinates for lower left corner. ## width, height Hm.. obvious. ## pixDepth Amount of bits per pixel. ## attrBits Number of attribute bits per pixel (f.ex. alpha). ## rightLeft If true, to be drawn from right to left. ## topDown If true, to be drawn from top to bottom. proc getImgSpec {imgData} { binary scan $imgData "@8 sssscc" imageSpec(xOrigin) \ imageSpec(yOrigin) imageSpec(width) imageSpec(height) \ imageSpec(pixDepth) \ imageDesc set imageSpec(attrBits) [& $imageDesc 0x7] set imageSpec(rightLeft) [>> [& $imageDesc 0x8] 3] set imageSpec(topDown) [>> [& $imageDesc 0x16] 4] return [array get imageSpec] } ## Get image header. ## ## 'imgData' contains the full TGA data, including headers. ## ## Returns key-value list with fields: idLength, colourMap, imageData, ## [compression, colourModel]. ## idLength Length in bytes of ID field. ## colourMap If true, image uses a colour map. ## imageData If true, header contained image data. ## compression Compression model, either RLE or none. ## colourModel Model of colour. Either "mapped", "true-colour" or ## "black-and-white" ## 'compression' and 'colourModel' are only set if 'imageData' is true. proc getHeader {imgData} { set hdrData [string range $imgData 0 18] binary scan $hdrData "ccc" header(idLength) header(colourMap) \ imageType if {$imageType == 0} { # No image data present. set header(imageData) false return } else { set header(imageData) true } if {$imageType >= 1 && $imageType <= 3} { # No imagecompression set header(compression) none } else { set header(compression) RLE } switch -- $imageType { 1 - 9 { set header(colourModel) mapped } 2 - 10 { set header(colourModel) true-colour } 3 - 11 { set header(colourModel) black-and-white } } return [array get header] } } ---- [Category Graphics]