tiff.tcl

Go to the documentation of this file.
00001 /*  tiff.tcl --*/
00002 /* */
00003 /*        Querying and modifying TIFF image files.*/
00004 /* */
00005 /*  Copyright (c) 2004    Aaron Faupell <afaupell@users.sourceforge.net>*/
00006 /* */
00007 /*  See the file "license.terms" for information on usage and redistribution*/
00008 /*  of this file, and for a DISCLAIMER OF ALL WARRANTIES.*/
00009 /*  */
00010 /*  RCS: @(#) $Id: tiff.tcl,v 1.3 2006/07/20 07:09:58 afaupell Exp $*/
00011 
00012 package provide tiff 0.1
00013 
00014 namespace ::tiff {}
00015 
00016 ret  ::tiff::openTIFF (type file , optional mode =r) {
00017     variable byteOrder
00018     set fh [open $file $mode]
00019     fconfigure $fh -encoding binary -translation binary -eofchar {}
00020     binary scan [read $fh 2] H4 byteOrder
00021     if {$byteOrder == "4949"} {
00022         set byteOrder little
00023     } elseif {$byteOrder == "4d4d"} {
00024         set byteOrder big
00025     } else {
00026         close $fh
00027         return -code error "not a tiff file"
00028     }
00029     _scan $byteOrder [read $fh 6] si version offset
00030     if {$version != "42"} {
00031         close $fh
00032         return -code error "not a tiff file"
00033     }
00034     seek $fh $offset start
00035     return $fh
00036 }
00037 
00038 ret  ::tiff::isTIFF (type file) {
00039     set is [catch {openTIFF $file} fh]
00040     catch {close $fh}
00041     return [expr {!$is}]
00042 }
00043 
00044 ret  ::tiff::byteOrder (type file) {
00045     global $byteOrder
00046     set fh [openTIFF $file]
00047     close $fh
00048     return $byteOrder
00049 }
00050 
00051 ret  ::tiff::nametotag (type names) {
00052     variable tiff_sgat
00053     set out {}
00054     foreach x $names {
00055         set y [lindex $x 0]
00056         if {[info exists tiff_sgat($y)]} {
00057             set y $tiff_sgat($y)
00058         } elseif {![string match {[0-9a-f][0-9a-f][0-9a-f][0-9a-f]} $x]} {
00059             error "unknown tag $y"
00060         }
00061         lappend out [lreplace $x 0 0 $y]
00062     }
00063     return $out
00064 }
00065 
00066 ret  ::tiff::tagtoname (type tags) {
00067     variable tiff_tags
00068     set out {}
00069     foreach x $tags {
00070         set y [lindex $x 0]
00071         if {[info exists tiff_tags($y)]} { set y $tiff_tags($y) }
00072         lappend out [lreplace $x 0 0 $y]
00073     }
00074     return $out
00075 }
00076 
00077 ret  ::tiff::numImages (type file) {
00078     variable byteOrder
00079     set fh [openTIFF $file]
00080     set images [llength [_ifds $fh]]
00081     close $fh
00082     return $images
00083 }
00084 
00085 ret  ::tiff::dimensions (type file , optional image =0) {
00086     return [getEntry $file {0100 0101} $image]
00087 }
00088 
00089 ret  ::tiff::imageInfo (type file , optional image =0) {
00090     return [getEntry $file {ImageWidth ImageLength BitsPerSample Compression \
00091           PhotometricInterpretation ImageDescription Orientation XResolution \
00092           YResolution ResolutionUnit DateTime Artist HostComputer} $image]
00093 }
00094 
00095 ret  ::tiff::entries (type file , optional image =0) {
00096     variable byteOrder
00097     set fh [openTIFF $file]
00098     set ret {}
00099     if {[set ifd [lindex [_ifds $fh] $image]] != ""} {
00100         seek $fh $ifd
00101         foreach e [tagtoname [_entries $fh]] {
00102             lappend ret [lindex $e 0]
00103         }
00104     }
00105     close $fh
00106     return $ret
00107 }
00108 
00109 ret  ::tiff::getEntry (type file , type entry , optional image =0) {
00110     variable byteOrder
00111     set fh [openTIFF $file]
00112     set ret {}
00113     if {[set ifd [lindex [_ifds $fh] $image]] != ""} {
00114         seek $fh $ifd 
00115         set ent [_entries $fh]
00116         foreach e $entry {
00117             if {[set x [lsearch -inline $ent "[nametotag $e] *"]] != ""} {
00118                 seek $fh [lindex $x 1]
00119                 lappend ret $e [lindex [_getEntry $fh] 1]
00120             } else {
00121                 lappend ret $e {}
00122             }
00123         }
00124     }
00125     close $fh
00126     return $ret
00127 }
00128 
00129 ret  ::tiff::addEntry (type file , type entry , optional image =0) {
00130     variable byteOrder
00131     set fh [openTIFF $file]
00132     set new [_new $file.tmp $byteOrder]
00133     set ifds [_ifds $fh]
00134     for {set i 0} {$i < [llength $ifds]} {incr i} {
00135         seek $fh [lindex $ifds $i]
00136         _readifd $fh ifd
00137         if {$i == $image || $image == "all"} {
00138             foreach e [nametotag $entry] {
00139                 set ifd($tag) [eval _unformat $byteOrder $e]
00140             }
00141         }
00142         _copyData $fh $new ifd
00143     }
00144     close $fh
00145     close $new
00146     file rename -force $file.tmp $file
00147 }
00148 
00149 ret  ::tiff::deleteEntry (type file , type entry , optional image =0) {
00150     variable byteOrder
00151     set fh [openTIFF $file]
00152     set new [_new $file.tmp $byteOrder]
00153     set ifds [_ifds $fh]
00154     for {set i 0} {$i < [llength $ifds]} {incr i} {
00155         seek $fh [lindex $ifds $i]
00156         _readifd $fh ifd
00157         if {$i == $image || $image == "all"} {
00158             foreach e [nametotag $entry] { unset -nocomplain ifd($e) }
00159         }
00160         _copyData $fh $new ifd
00161     }
00162     close $fh
00163     close $new
00164     file rename -force $file.tmp $file
00165 }
00166 
00167 ret  ::tiff::writeImage (type image , type file , optional entry ={)} {
00168     variable byteOrder
00169     set byteOrder big
00170     set fh [_new $file $byteOrder]
00171     set w [$image cget -width]
00172     set h [$image cget -height]
00173     set ifd(0100) [_unformat $byteOrder 0100 4 $w]      ;# width
00174     set ifd(0101) [_unformat $byteOrder 0101 4 $h]      ;# height
00175     set ifd(0102) [_unformat $byteOrder 0102 3 {8 8 8}] ;/*  color depth*/
00176      ifd = (0103) [_unformat $byteOrder 0103 3 1]       ;/*  compression = none*/
00177      ifd = (0106) [_unformat $byteOrder 0106 3 2]       ;/*  photometric interpretation = rgb*/
00178      ifd = (0115) [_unformat $byteOrder 0115 3 3]       ;/*  3 samples per pixel r, g, and b*/
00179      ifd = (011c) [_unformat $byteOrder 011c 3 1]       ;/*  planar configuration = rgb*/
00180     foreach {tag format value} $entry {
00181          ifd = ($tag) [_unformat $byteOrder $tag $format $value]
00182     }
00183 
00184      rowsPerStrip =  2
00185     while {$w * 3 * $rowsPerStrip < 8000} { incr rowsPerStrip }
00186     incr rowsPerStrip -1
00187      strips =  [expr {int(ceil($h / double($rowsPerStrip)))}]
00188      stripSize =  [expr {$w * $rowsPerStrip * 3}]
00189      lastStripSize =  [expr {3 * $w * ($h - (($strips - 1) * $rowsPerStrip))}]
00190     
00191     for { i =  $strips} {$i > 1} {incr i -1} { lappend sizes $stripSize }
00192     lappend sizes $lastStripSize
00193     
00194      ifd = (0116) [_unformat $byteOrder 0116 4 $rowsPerStrip]
00195      ifd = (0111) [_unformat $byteOrder 0111 4 $sizes]
00196     /*  dummy data, to get ifd size, real value inserted later*/
00197      ifd = (0117) [_unformat $byteOrder 0117 4 $sizes]
00198     
00199     /*  add 8 bytes for file header*/
00200      start =  [expr {[_ifdsize ifd] + 8}]
00201     for { i =  $strips} {$i > 0} {incr i -1} {
00202         lappend offs =  $start
00203         incr start $stripSize
00204     }
00205      ifd = (0111) [_unformat $byteOrder 0111 4 $offs = ]
00206     
00207     _writeifd $fh ifd
00208 
00209     for { y =  0} {$y < $h} {incr y} {
00210         for { x =  0} {$x < $w} {incr x} {
00211             foreach {r g b} [$image get $x $y] {
00212                 puts -nonewline $fh [_unscan $byteOrder ccc [expr {$r & 0xFF}] [expr {$g & 0xFF}] [expr {$b & 0xFF}]]
00213             }
00214         }
00215     }
00216     
00217     close $fh
00218 }
00219 
00220 ret  ::tiff::getImage (type file , optional image =0) {
00221     array set tags [getEntry $file {0100 0101 0102 0103 0106 011c 0115 0111 0117 0140} $image]
00222     if {$tags(0102) == "8 8 8" && $tags(0103) == 1 && $tags(0106) == 2 && $tags(0115) == 3 && $tags(011c) == 1} {
00223         set w $tags(0100)
00224         set h $tags(0101)
00225         set i [image create photo -height $h -width $w]
00226         set fh [open $file]
00227         fconfigure $fh -translation binary -encoding binary -eofchar {}
00228 
00229         set y 0
00230         set x 0
00231         set row {}
00232         set block {}
00233         foreach offset $tags(0111) len $tags(0117) {
00234             seek $fh $offset start
00235             binary scan [read $fh $len] c* buf
00236             foreach {r g b} $buf {
00237                 lappend row [format "#%02X%02X%02X" [expr {$r & 0xFF}] [expr {$g & 0xFF}] [expr {$b & 0xFF}]]
00238                 incr x
00239                 if {$x == $w} { lappend block $row; set row {}; set x 0 }
00240             }
00241             $i put $block -to 0 $y
00242             incr y [llength $block]
00243             set block {}
00244         }
00245         close $fh
00246     } elseif {$tags(0102) == 8 && $tags(0103) == 1 && $tags(0106) == 3 && $tags(0115) == 1 && $tags(011c) == 1} {
00247         set w $tags(0100)
00248         set h $tags(0101)
00249         set i [image create photo -height $h -width $w]
00250         set fh [open $file]
00251         fconfigure $fh -translation binary -encoding binary -eofchar {}
00252 
00253         set map {}
00254         set third [expr {[llength $tags(0140)] / 3}]
00255         set rs [lrange $tags(0140) 0 [expr {$third - 1}]]
00256         set gs [lrange $tags(0140) $third [expr {($third * 2) - 1}]]
00257         set bs [lrange $tags(0140) [expr {$third * 2}] end]
00258         foreach r $rs g $gs b $bs {
00259             set r [expr {int($r / 256) & 0xFF}]
00260             set g [expr {int($g / 256) & 0xFF}]
00261             set b [expr {int($b / 256) & 0xFF}]
00262             lappend map [format "#%02X%02X%02X" $r $g $b]
00263         }
00264         
00265         set y 0
00266         set x 0
00267         set row {}
00268         set block {}
00269         
00270         foreach offset $tags(0111) len $tags(0117) {
00271             seek $fh $offset start
00272             binary scan [read $fh $len] c* buf
00273             foreach index $buf {
00274                 lappend row [lindex $map [expr {$index & 0xFF}]]
00275                 incr x
00276                 if {$x == $w} { lappend block $row; set row {}; set x 0 }
00277             }
00278             $i put $block -to 0 $y
00279             incr y [llength $block]
00280             set block {}
00281         }
00282         close $fh
00283     } else {
00284         error "I cant read that image format"
00285     }
00286     return $i
00287 }
00288 
00289 ret  ::tiff::_copyData (type fh , type new , type var) {
00290     variable byteOrder
00291     upvar $var ifd
00292 
00293     set fix {}
00294     #       strips, free bytes, tiles,   and their sizes     
00295     foreach f_off {0111 0120 0143} f_len {0117 0121 0144} {
00296         if {![info exists ifd($f_len)] || ![info exists ifd($f_off)]} { continue }
00297         set n 0
00298         # put everything into a list
00299         foreach x [_value $ifd($f_len)] y [_value $ifd($f_off)] {
00300             lappend fix [list $n $f_len $x $f_off $y]
00301             incr n
00302         }
00303     }
00304     set offset [expr {[tell $new] + [_ifdsize ifd]}]
00305     set new_fix {}
00306     # sort the list by offset
00307     foreach x [lsort -integer -index 4 $fix] {
00308         lappend new_fix [lreplace $x 4 4 $offset]
00309         incr offset [lindex $x 2]
00310     }
00311     foreach x [lsort -integer -index 0 $new_fix] {
00312         lappend blah([lindex $x 3]) [lindex $x 4]
00313     }
00314     foreach x [array names blah] {
00315         _scan $byteOrder [lindex $ifd($x) 0] x2s format
00316         set ifd($x) [_unformat $byteOrder $x $format $blah($x)]
00317     }
00318     if {[info exists ifd(8769)]} {
00319         seek $fh [_value $ifd(8769)]
00320         _readifd $fh exif
00321         _scan $byteOrder [lindex $ifd($x) 0] x2s format
00322         set ifd(8769) [_unformat $byteOrder 8769 $format $offset]
00323     }
00324     _writeifd $new ifd
00325         
00326     foreach x $fix {
00327         seek $fh [lindex $x 4] start
00328         fcopy $fh $new -size [lindex $x 2]
00329     }
00330     if {[info exists ifd(8769)]} {
00331         _writeifd $new exif
00332     }
00333 }
00334 
00335 /*  returns a list of offsets of all the IFDs*/
00336 ret  ::tiff::_ifds (type fh) {
00337     variable byteOrder
00338 
00339     # number of entries in this ifd
00340     _scan $byteOrder [read $fh 2] s num
00341     # subract 2 to account for reading the number
00342     set ret [list [expr {[tell $fh] - 2}]]
00343     # skip the entries, 12 bytes each
00344     seek $fh [expr {$num * 12}] current
00345     # 4 byte offset to next ifd after entries
00346     _scan $byteOrder [read $fh 4] i next
00347 
00348     while {$next > 0} {
00349         seek $fh $next start
00350         _scan $byteOrder [read $fh 2] s num
00351         lappend ret [expr {[tell $fh] - 2}]
00352         seek $fh [expr {$num * 12}] current
00353         _scan $byteOrder [read $fh 4] i next
00354     }
00355     return $ret
00356 }
00357 
00358 /*  takes fh at start of IFD and returns entries, offset, and size*/
00359 ret  ::tiff::_entries (type fh) {
00360     variable byteOrder
00361     variable formats
00362     set ret {}
00363     _scan $byteOrder [read $fh 2] s num
00364     for {} {$num > 0} {incr num -1} {
00365         set offset [tell $fh]
00366         binary scan [read $fh 2] H2H2 t1 t2
00367         _scan $byteOrder [read $fh 6] si format components
00368         seek $fh 4 current
00369         if {$byteOrder == "big"} {
00370             set tag $t1$t2
00371         } else {
00372             set tag $t2$t1
00373         }
00374         #puts "$tag $format $components"
00375         set size [expr {$formats($format) * $components}]
00376         lappend ret [list $tag $offset $size]
00377     }
00378     return $ret
00379 }
00380 
00381 /*  takes fh at start of dir entry and returns tag and value(s)*/
00382 ret  ::tiff::_getEntry (type fh) {
00383     variable byteOrder
00384     variable formats
00385     binary scan [read $fh 2] H2H2 t1 t2
00386     _scan $byteOrder [read $fh 6] si format components
00387     if {$byteOrder == "big"} {
00388         set tag $t1$t2
00389     } else {
00390         set tag $t2$t1
00391     }
00392     set value [read $fh 4]
00393     set size [expr {$formats($format) * $components}]
00394     #puts "entry $tag $format $components $size"
00395     # if the data is over 4 bytes, its stored later in the file
00396     if {$size > 4} {
00397         set pos [tell $fh]
00398         _scan $byteOrder $value i value
00399         seek $fh $value start
00400         set value [read $fh $size]
00401         seek $fh $pos start
00402     }
00403     return [list $tag [_format $byteOrder $value $format $components]]
00404 }
00405 
00406 ret  ::tiff::_value (type data) {
00407     variable byteOrder
00408     _scan $byteOrder [lindex $data 0] x2si format components
00409     return [_format $byteOrder [lindex $data 1] $format $components]
00410 }
00411 
00412 ret  ::tiff::_new (type file , type byteOrder) {
00413     set fh [open $file w]
00414     fconfigure $fh -encoding binary -translation binary -eofchar {}
00415     if {$byteOrder == "big"} {
00416         puts -nonewline $fh [binary format H4 4d4d]
00417     } else {
00418         puts -nonewline $fh [binary format H4 4949]
00419     }
00420     puts -nonewline $fh [_unscan $byteOrder si 42 8]
00421     return $fh
00422 }
00423 
00424 ret  ::tiff::_readifd (type fh , type var) {
00425     variable byteOrder
00426     variable formats
00427     upvar $var ifd
00428     array set ifd {}
00429     _scan $byteOrder [read $fh 2] s num
00430     for {} {$num > 0} {incr num -1} {
00431         set one [read $fh 8]
00432         binary scan $one H2H2 t1 t2
00433         _scan $byteOrder $one x2si format components
00434         if {$byteOrder == "big"} {
00435             set tag $t1$t2
00436         } else {
00437             set tag $t2$t1
00438         }
00439         set ifd($tag) [list $one]
00440         set value [read $fh 4]
00441         set size [expr {$formats($format) * $components}]
00442         if {$size > 4} {
00443             set pos [tell $fh]
00444             _scan $byteOrder $value i value
00445             seek $fh $value start
00446             lappend ifd($tag) [read $fh $size]
00447             seek $fh $pos start
00448         } else {
00449             lappend ifd($tag) $value
00450         }
00451     }
00452 }
00453 
00454 ret  ::tiff::_writeifd (type new , type var) {
00455     variable byteOrder
00456     upvar $var ifd
00457     set num [llength [array names ifd]]
00458     puts -nonewline $new [_unscan $byteOrder s $num]
00459     set dataOffset [expr {[tell $new] + ($num * 12) + 4}]
00460     set data {}
00461     foreach tag [lsort [array names ifd]] {
00462         set entry $ifd($tag)
00463         puts -nonewline $new [lindex $entry 0]
00464         if {[string length [lindex $entry 1]] > 4} {
00465             puts -nonewline $new [_unscan $byteOrder i $dataOffset]
00466             append data [lindex $entry 1]
00467             incr dataOffset [string length [lindex $entry 1]]
00468         } else {
00469             puts -nonewline $new [lindex $entry 1]
00470         }
00471     }
00472     set next [tell $new]
00473     puts -nonewline $new [binary format i 0]
00474     puts -nonewline $new $data
00475     return $next
00476 }
00477 
00478 ret  ::tiff::_ifdsize (type var) {
00479     upvar $var ifd
00480     # 2 bytes for number of entries and 4 bytes for pointer to next ifd
00481     set size 6
00482     foreach x [array names ifd] {
00483         incr size 12
00484         # include data that doesnt fit in entry
00485         if {[string length [lindex $ifd($x) 1]] > 4} {
00486             incr size [string length [lindex $ifd($x) 1]]
00487         }
00488     }
00489     return $size
00490 }
00491 
00492 ret  ::tiff::debug (type file) {
00493     variable byteOrder
00494     variable tiff_tags
00495     set fh [openTIFF $file]
00496     set n 0
00497     foreach ifd [_ifds $fh] {
00498         seek $fh $ifd start
00499         set entries [_entries $fh]
00500         puts "IFD $n ([llength $entries] entries)"
00501         foreach ent $entries {
00502             if {[info exists tiff_tags([lindex $ent 0])]} {
00503                 puts -nonewline "  $tiff_tags([lindex $ent 0])"
00504             } else {
00505                 puts -nonewline "  [lindex $ent 0]"
00506             }
00507             if {[lindex $ent 2] < 200} {
00508                 seek $fh [lindex $ent 1] start
00509                 puts ": [lindex [_getEntry $fh] 1]"
00510             } else {
00511                 puts " offset [lindex $ent 1] size [lindex $ent 2] bytes"
00512             }
00513             if {[lindex $ent 0] == "8769"} {
00514                 seek $fh [lindex $ent 1] start
00515                 seek $fh [lindex [_getEntry $fh] 1]
00516                 foreach x [_entries $fh] {
00517                     seek $fh [lindex $x 1]
00518                     puts "    [_getEntry $fh]"
00519                 }
00520             }
00521         }
00522         incr n
00523     }
00524 }
00525 
00526 array  ::tiff = ::tiff_tags {
00527     00fe NewSubfileType
00528     00ff SubfileType 
00529     0100 ImageWidth 
00530     0101 ImageLength
00531     0102 BitsPerSample 
00532     0103 Compression
00533     0106 PhotometricInterpretation
00534     0107 Threshholding 
00535     0108 CellWidth  
00536     0109 CellLength 
00537     010a FillOrder
00538     010e ImageDescription
00539     010f Make
00540     0110 Model
00541     0111 StripOffs = 
00542     0112 Orientation   
00543     0115 SamplesPerPixel
00544     0116 RowsPerStrip
00545     0117 StripByteCounts
00546     0118 MinSampleValue
00547     0119 MaxSampleValue
00548     011a XResolution 
00549     011b YResolution
00550     011c PlanarConfiguration
00551     0120 FreeOffs = 
00552     0121 FreeByteCounts
00553     0122 GrayResponseUnit
00554     0123 GrayResponseCurve
00555     0128 ResolutionUnit
00556     0131 Software
00557     0132 DateTime
00558     013b Artist
00559     013c HostComputer
00560     0140 ColorMap
00561     0152 ExtraSamples
00562     8298 Copyright
00563 
00564     010d DocumentName 
00565     011d PageName   
00566     011e XPosition  
00567     011f YPosition   
00568     0124 T4Options
00569     0125 T6Options
00570     0129 PageNumber
00571     012d TransferFunction
00572     013d Predictor
00573     013e WhitePoint
00574     013f PrimaryChromaticities
00575     0141 HalftoneHints
00576     0142 TileWidth   
00577     0143 TileLength  
00578     0144 TileOffs = 
00579     0145 TileByteCounts  
00580     0146 BadFaxLines
00581     0147 CleanFaxData
00582     0148 ConsecutiveBadFaxLines
00583     014a SubIFDs
00584     014c InkSet
00585     014d InkNames
00586     014e NumberOfInks
00587     0150 DotRange
00588     0151 TargetPrinter
00589     0153 SampleFormat
00590     0154 SMinSampleValue
00591     0155 SMaxSampleValue
00592     0156 TransferRange
00593     0157 ClipPath
00594     0158 XClipPathUnits
00595     0159 YClipPathUnits
00596     015a Indexed
00597     015b JPEGTables
00598     015f OPIProxy
00599     0190 GlobalParametersIFD
00600     0191 ProfileType
00601     0192 FaxProfile
00602     0193 CodingMethods
00603     0194 VersionYear
00604     0195 ModeNumber
00605     01b1 Decode
00606     01b2 DefaultImageColor
00607     0200 JPEGProc
00608     0201 JPEGInterchangeFormat
00609     0202 JPEGInterchangeFormatLength
00610     0203 JPEGRestartInterval
00611     0205 JPEGLosslessPredictors
00612     0206 JPEGPointTransforms
00613     0207 JPEGQTables
00614     0208 JPEGDCTables
00615     0209 JPEGACTables
00616     0211 YCbCrCoefficients
00617     0212 YCbCrSubSampling
00618     0213 YCbCrPositioning
00619     0214 ReferenceBlackWhite
00620     022f StripRowCounts
00621     02bc XMP
00622     800d ImageID
00623     87ac ImageLayer
00624 
00625     8649 Photoshop
00626     8769 ExifIFD
00627     8773 ICCProfile
00628 }
00629 
00630 if {![info exists ::tiff::tiff_sgat]} {
00631     foreach {x y} [array get ::tiff::tiff_tags] {
00632          ::tiff = ::tiff_sgat($y) $x
00633     }
00634 }
00635 
00636 array  ::tiff = ::data_types {
00637     1 BYTE
00638     2 ASCII
00639     3 SHORT
00640     4 LONG
00641     5 RATIONAL
00642     6 SBYTE
00643     7 UNDEFINED
00644     8 SSHORT
00645     9 SLONG
00646     10 SRATIONAL
00647     11 FLOAT
00648     12 DOUBLE
00649     BYTE 1
00650     ASCII 2
00651     SHORT 3
00652     LONG 4
00653     RATIONAL 5
00654     SBYTE 6 
00655     UNDEFINED 7
00656     SSHORT 8
00657     SLONG 9
00658     SRATIONAL 10
00659     FLOAT 11
00660     DOUBLE 12
00661 }
00662 
00663 /*  for mapping the format types to byte lengths*/
00664 array  ::tiff = ::formats [list 1 1 2 1 3 2 4 4 5 8 6 1 7 1 8 2 9 4 10 8 11 4 12 8]
00665 
00666 ret  ::tiff::_seek (type chan , type offset , optional origin =start) {
00667     if {$origin == "start"} {
00668         variable start
00669         seek $chan [expr {$offset + $start}] start
00670     } else {
00671         seek $chan $offset $origin
00672     }
00673 }
00674 
00675 /*  [binary scan], in the byte order indicated by $e*/
00676 ret  ::tiff::_scan (type e , type v , type f , type args) {
00677      foreach x $args { upvar 1 $x $x }
00678      if {$e == "big"} {
00679           eval [list binary scan $v [string map {b B h H s S i I} $f]] $args
00680      } else {
00681          eval [list binary scan $v $f] $args
00682      }
00683 }
00684 
00685 /*  [binary format], in the byte order indicated by $e*/
00686 ret  ::tiff::_unscan (type e , type f , type args) {
00687      if {$e == "big"} {
00688          return [eval [list binary format [string map {b B h H s S i I} $f]] $args]
00689      } else {
00690          return [eval [list binary format $f] $args]
00691      }
00692 }
00693 
00694 /*  formats values, the numbers correspond to data types*/
00695 /*  values may be either byte order, as indicated by $end*/
00696 /*  see the tiff spec for more info*/
00697 ret  ::tiff::_format (type end , type value , type type , type num) {
00698     if {$num > 1 && $type != 2 && $type != 7} {
00699         variable formats
00700         set r {}
00701         for {set i 0} {$i < $num} {incr i} {
00702             set len $formats($type)
00703             lappend r [_format $end [string range $value [expr {$len * $i}] [expr {($len * $i) + $len - 1}]] $type 1]
00704         }
00705         #return [join $r ,]
00706         return $r
00707     }
00708     switch -exact -- $type {
00709         1 { _scan $end $value c value }
00710         2 { set value [string trimright $value \x00] }
00711         3 {
00712             _scan $end $value s value
00713             set value [format %u $value]
00714         }
00715         4 {
00716             _scan $end $value i value
00717             set value [format %u $value]
00718         }
00719         5 {
00720             _scan $end $value ii n d
00721             set n [format %u $n]
00722             set d [format %u $d]
00723             if {$d == 0} {set d 1}
00724             #set value [string trimright [string trimright [format %5.4f [expr {double($n) / $d}]] 0] .]
00725             set value [string trimright [string trimright [expr {double($n) / $d}] 0] .]
00726             #set value "$n/$d"
00727         }
00728         6 { _scan $end $value c value }
00729         8 { _scan $end $value s value }
00730         9 { _scan $end $value i value }
00731         10 {
00732             _scan $end $value ii n d
00733             if {$d == 0} {set d 1}
00734             #set value [string trimright [string trimright [format %5.4f [expr {double($n) / $d}]] 0] .]
00735             set value [string trimright [string trimright [expr {double($n) / $d}] 0] .]
00736             #set value "$n/$d"
00737         }
00738         11 { _scan $end $value i value }
00739         12 { _scan $end $value w value }
00740     }
00741     return $value
00742 }
00743 
00744 ret  ::tiff::_unformat (type end , type tag , type type , type value) {
00745     set packed_val {}
00746     set count [llength $value]
00747     if {$type == 2 || $type == 7} { set value [list $value] }
00748     foreach val $value {
00749         switch -exact -- $type {
00750             1 { set val [_unscan $end c $val] }
00751             2 {
00752                 append val \x00
00753                 set count [string length $val]
00754             }
00755             3 { set val [_unscan $end s $val] }
00756             4 { set val [_unscan $end i $val] }
00757             5 {
00758                 set val [split $val /]
00759                 set val [_unscan $end i [lindex $val 0]][_unscan $end i [lindex $val 1]]
00760             }
00761             6 { set val [_unscan $end c $val] }
00762             7 { set count [string length $val }
00763             8 { set val [_unscan $end s $val] }
00764             9 { set val [_unscan $end i $val] }
00765             10 {
00766                 set val [split $val /]
00767                 set val [_unscan $end i [lindex $val 0]][_unscan $end i [lindex $val 1]]
00768             }
00769             11 { set val [_unscan $end $value i value] }
00770             12 { set val [_unscan $end $value w value] }
00771             default { error "unknown data type $type" }
00772         }
00773         append packed_val $val
00774     }
00775     if {$tag != ""} {
00776         if {$end == "big"} {
00777             set tag [binary format H2H2 [string range $tag 0 1] [string range $tag 2 3]]
00778         } else {
00779             set tag [binary format H2H2 [string range $tag 2 3] [string range $tag 0 1]]
00780         }
00781     }
00782     if {[string length $packed_val] < 4} { set packed_val [binary format a4 $packed_val] }
00783     return [list $tag[_unscan $end si $type $count] $packed_val]
00784 }
00785         
00786 
00787 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1