jpeg.tcl

Go to the documentation of this file.
00001 /*  jpeg.tcl --*/
00002 /* */
00003 /*        Querying and modifying JPEG 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: jpeg.tcl,v 1.12 2006/09/19 23:36:17 andreas_kupries Exp $*/
00011 
00012 package provide jpeg 0.3
00013 
00014 namespace ::jpeg {}
00015 
00016 /*  open a file, check jpeg signature, and a return a file handle*/
00017 /*  at the start of the first marker*/
00018 ret  ::jpeg::openJFIF (type file , optional mode =r) {
00019     set fh [open $file $mode]
00020     fconfigure $fh -encoding binary -translation binary -eofchar {}
00021     # jpeg sig is FFD8, FF is start of first marker
00022     if {[read $fh 3] != "\xFF\xD8\xFF"} { close $fh; return -code error "not a jpg file" }
00023     # rewind to first marker
00024     seek $fh -1 current
00025     return $fh
00026 }
00027 
00028 /*  return a boolean indicating if a file starts with the jpeg sig*/
00029 ret  ::jpeg::isJPEG (type file) {
00030     set is [catch {openJFIF $file} fh]
00031     catch {close $fh}
00032     return [expr {!$is}]
00033 }
00034 
00035 /*  takes an open filehandle at the start of a jpeg marker, and returns a list*/
00036 /*  containing information about the file markers in the jpeg file. each list*/
00037 /*  element itself a list of the marker type, offset of the start of its data,*/
00038 /*  and the length of its data.*/
00039 ret  ::jpeg::markers (type fh) {
00040     set chunks [list]
00041     while {[read $fh 1] == "\xFF"} {
00042         binary scan [read $fh 3] H2S type len
00043         # convert to unsigned
00044         set len [expr {$len & 0x0000FFFF}]
00045         # decrement len to account for marker bytes
00046         incr len -2
00047         lappend chunks [list $type [tell $fh] $len]
00048         seek $fh $len current
00049     }
00050     return $chunks
00051 }
00052 
00053 ret  ::jpeg::imageInfo (type file) {
00054     set fh [openJFIF $file r+]
00055     set data {}
00056     if {[set app0 [lsearch -inline [markers $fh] "e0 *"]] != ""} {
00057         seek $fh [lindex $app0 1] start
00058         set id [read $fh 5]
00059         if {$id == "JFIF\x00"} {
00060             binary scan [read $fh 9] cccSScc ver1 ver2 units xr yr xt yt
00061             set data [list version $ver1.$ver2 units $units xdensity $xr ydensity $yr xthumb $xt ythumb $yt]
00062         }
00063     }
00064     close $fh
00065     return $data
00066 }
00067 
00068 /*  return an images dimensions by reading the Start Of Frame marker*/
00069 ret  ::jpeg::dimensions (type file) {
00070     set fh [openJFIF $file]
00071     set sof [lsearch -inline [markers $fh] {c[0-3] *}]
00072     seek $fh [lindex $sof 1] start
00073     binary scan [read $fh 5] cSS precision height width
00074     close $fh
00075     return [list $width $height]
00076 }
00077 
00078 /*  returns a list of all comments (FE segments) in the file*/
00079 ret  ::jpeg::getComments (type file) {
00080     set fh [openJFIF $file]
00081     set comments {}
00082     foreach x [lsearch -all -inline [markers $fh] "fe *"] {
00083         seek $fh [lindex $x 1] start
00084         lappend comments [read $fh [lindex $x 2]]
00085     }
00086     close $fh
00087     return $comments
00088 }
00089 
00090 /*  add a new comment to the file*/
00091 ret  ::jpeg::addComment (type file , type comment , type args) {
00092     set fh [openJFIF $file r+]
00093     # find the SoF and save all data after it
00094     set sof [lsearch -inline [markers $fh] {c[0-3] *}]
00095     seek $fh [expr {[lindex $sof 1] - 4}] start
00096     set data2 [read $fh]
00097     # seek back to the SoF and write comment(s) segment
00098     seek $fh [expr {[lindex $sof 1] - 4}] start
00099     foreach x [linsert $args 0 $comment] {
00100         if {$x == ""} continue
00101         puts -nonewline $fh [binary format a2Sa* "\xFF\xFE" [expr {[string length $x] + 2}] $x]
00102     }
00103     # write the saved data bac
00104     puts -nonewline $fh $data2
00105     close $fh
00106 }
00107 
00108 ret  ::jpeg::replaceComment (type file , type comment) {
00109     set com [getComments $file]
00110     removeComments $file
00111     eval [list addComment $file] [lreplace $com 0 0 $comment]
00112 }
00113 
00114 /*  removes all comment segments from the file*/
00115 ret  ::jpeg::removeComments (type file) {
00116     set fh [openJFIF $file]
00117     set data "\xFF\xD8"
00118     foreach marker [markers $fh] {
00119         if {[lindex $marker 0] != "fe"} {
00120             # seek back 4 bytes to include the marker and length bytes
00121             seek $fh [expr {[lindex $marker 1] - 4}] start
00122             append data [read $fh [expr {[lindex $marker 2] + 4}]]
00123         }
00124     }
00125     append data [read $fh]
00126     close $fh
00127     set fh [open $file w]
00128     fconfigure $fh -encoding binary -translation binary -eofchar {}
00129     puts -nonewline $fh $data
00130     close $fh
00131 }
00132 
00133 /*  rewrites a jpeg file and removes all metadata (comments, exif, photoshop)*/
00134 ret  ::jpeg::stripJPEG (type file) {
00135     set fh [openJFIF $file]
00136     set data {}
00137     
00138     set markers [markers $fh]
00139     # look for a jfif header segment and save it
00140     if {[lindex $markers 0 0] == "e0"} {
00141         seek $fh [lindex $markers 0 1] start
00142         if {[read $fh 5] == "JFIF\x00"} {
00143             seek $fh -9 current
00144             set jfif [read $fh [expr {[lindex $markers 0 2] + 4}]]
00145         }
00146     }
00147     # if we dont have a jfif header (exif files), create a fake one
00148     if {![info exists jfif]} {
00149         set jfif [binary format a2Sa5cccSScc "\xFF\xE0" 16 "JFIF\x00" 1 2 1 72 72 0 0]
00150     }
00151 
00152     # remove all the e* and f* markers (metadata)
00153     foreach marker $markers {
00154         if {![string match {[ef]*} [lindex $marker 0]]} {
00155             seek $fh [expr {[lindex $marker 1] - 4}] start
00156             append data [read $fh [expr {[lindex $marker 2] + 4}]]
00157         }
00158     }
00159     append data [read $fh]
00160 
00161     close $fh
00162     set fh [open $file w+]
00163     # write a jpeg file sig, a jfif header, and all the remaining data
00164     puts -nonewline $fh \xFF\xD8$jfif$data
00165     close $fh
00166 }
00167 
00168 /*  if file contains a jpeg thumbnail return it. the returned data is the actual*/
00169 /*  jpeg data, it can be written directly to a file*/
00170 ret  ::jpeg::getThumbnail (type file) {
00171     # check if the exif information contains a thumbnail
00172     array set exif [getExif $file thumbnail]
00173     if {[info exists exif(Compression)] && \
00174              $exif(Compression) == 6 && \
00175              [info exists exif(JPEGInterchangeFormat)] && \
00176              [info exists exif(JPEGInterchangeFormatLength)]} {
00177         set fh [openJFIF $file]
00178         seek $fh [expr {$exif(ExifOffset) + $exif(JPEGInterchangeFormat)}] start
00179         set thumb [read $fh $exif(JPEGInterchangeFormatLength)]
00180         close $fh
00181         return $thumb
00182     }
00183     # check for a JFXX segment which contains a thumbnail
00184     set fh [openJFIF $file]
00185     foreach x [lsearch -inline -all [markers $fh] "e0 *"] {
00186         seek $fh [lindex $x 1] start
00187         binary scan [read $fh 6] a5H2 id excode
00188         # excode 10 is jpeg encoding, we cant interpret the other types
00189         if {$id == "JFXX\x00" && $excode == "10"} {
00190             set thumb [read $fh [expr {[lindex $x 2] - 6}]]
00191             close $fh
00192             return $thumb
00193         }
00194     }
00195     close $fh
00196 }
00197 
00198 
00199 /*  takes key-value pairs returned by getExif and converts their values into*/
00200 /*  human readable format*/
00201 ret  ::jpeg::formatExif (type exif) {
00202     variable exif_values
00203     set out {}
00204     foreach {tag val} $exif {
00205         if {[info exists exif_values($tag,$val)]} {
00206             set val $exif_values($tag,$val)
00207         } elseif {[info exists exif_values($tag,)]} {
00208             set val $exif_values($tag,)
00209         } else {
00210             switch -exact -- $tag {
00211                 UserComment {set val [string trim [string range $val 8 end] \x00]}
00212                 ComponentsConfiguration {binary scan $val cccc a b c d; set val $a,$b,$c,$d}
00213                 ExifVersion {set val [expr [string range $val 0 1].[string range $val 2 3]]}
00214                 FNumber {set val [format %2.1f $val]}
00215                 MaxApertureValue -
00216                 ApertureValue {
00217                     set val [format %2.1f [expr {2 * (log($val) / log(2))}]]
00218                 }
00219                 ShutterSpeedValue {
00220                     set val [expr {pow(2, $val)}]
00221                     if {abs(round($val) - $val) < 0.2} {set val [expr {round($val)}]}
00222                     set val 1/[string trimright [string trimright [format %.2f $val] 0] .]
00223                 }
00224                 ExposureTime {
00225                     set val 1/[string trimright [string trimright [format %.4f [expr {1 / $val}]] 0] .]
00226                 }
00227             }
00228         }
00229         lappend out $tag $val
00230     }
00231     return $out
00232 }
00233 
00234 /*  returns a list of all known exif keys*/
00235 ret  ::jpeg::exifKeys () {
00236     variable exif_tags
00237     set ret {}
00238     foreach {x y} [array get exif_tags] {lappend ret $y}
00239     return $ret
00240 }
00241 
00242 ret  ::jpeg::getExif (type file , optional type =main) {
00243     set fh [openJFIF $file]
00244     # foreach because file may have multiple e1 markers
00245     foreach app1 [lsearch -inline -all [markers $fh] "e1 *"] {
00246         seek $fh [lindex $app1 1] start
00247         # check that this e1 is really an Exif segment
00248         if {[read $fh 6] != "Exif\x00\x00"} continue
00249         # save offset because exif offsets are relative to this
00250         set start [tell $fh]
00251         # next 2 bytes determine byte order
00252         binary scan [read $fh 2] H4 byteOrder
00253         if {$byteOrder == "4d4d"} {
00254             set byteOrder big
00255         } elseif {$byteOrder == "4949"} {
00256             set byteOrder little
00257         } else {
00258             close $fh
00259             return
00260         }
00261         # the answer is 42, if we have our byte order correct
00262         _scan $byteOrder [read $fh 6] si magic next
00263         if {$magic != 42} { close $fh; return }
00264         seek $fh [expr {$start + $next}] start
00265         if {$type != "thumbnail"} {
00266             set data [_exif $fh $byteOrder $start]
00267         } else {
00268             # number of entries in this exif block
00269             _scan $byteOrder [read $fh 2] s num
00270             # each entry is 12 bytes
00271             seek $fh [expr {$num * 12}] current
00272             # offset of next exif block (for thumbnail)
00273             _scan $byteOrder [read $fh 4] i next
00274             if {$next <= 0} { close $fh; return }
00275             # but its relative to start
00276             seek $fh [expr {$start + $next}] start
00277             set data [_exif $fh $byteOrder $start]
00278         }
00279         close $fh
00280         lappend data ExifOffset $start ExifByteOrder $byteOrder
00281         return $data
00282     }
00283     close $fh
00284 }
00285 
00286 ret  ::jpeg::removeExif (type file) {
00287     set fh [openJFIF $file]
00288     set data {}
00289     set markers [markers $fh]
00290     if {[lsearch $markers "e1 *"] < 0} { close $fh; return }
00291     foreach marker $markers {
00292         if {[lindex $marker 0] != "e1"} {
00293             seek $fh [expr {[lindex $marker 1] - 4}] start
00294             append data [read $fh [expr {[lindex $marker 2] + 4}]]
00295         } else {
00296             seek $fh [lindex $marker 1] start
00297             if {[read $fh 6] == "Exif\x00\x00"} continue
00298             seek $fh -10 current
00299             append data [read $fh [expr {[lindex $marker 2] + 4}]]
00300         }
00301     }
00302     append data [read $fh]
00303     close $fh
00304     set fh [open $file w]
00305     fconfigure $fh -encoding binary -translation binary -eofchar {}
00306     puts -nonewline $fh "\xFF\xD8"
00307     if {[lindex $markers 0 0] != "e0"} {
00308         puts -nonewline $fh [binary format a2Sa5cccSScc "\xFF\xE0" 16 "JFIF\x00" 1 2 1 72 72 0 0]
00309     }
00310     puts -nonewline $fh $data
00311     close $fh
00312 }
00313 
00314 ret  ::jpeg::_exif2 (type data) {
00315     variable exif_tags
00316     set byteOrder little
00317     set start 0
00318     set i 2
00319     for {_scan $byteOrder $data @0s num} {$num > 0} {incr num -1} {
00320         binary scan $data @${i}H2H2 t1 t2
00321         if {$byteOrder == "big"} {
00322             set tag $t1$t2
00323         } else {
00324             set tag $t2$t1
00325         }
00326         incr i 2
00327         _scan $byteOrder $data @${i}si format components
00328         incr i 6
00329         set value [string range $data $i [expr {$i + 3}]]
00330         if {$tag == "8769" || $tag == "a005"} {
00331             _scan $byteOrder $value i next
00332             #set pos [tell $fh]
00333             #seek $fh [expr {$offset + $next}] start
00334             #eval lappend return [_exif $fh $byteOrder $offset]
00335             #seek $fh $pos start
00336             continue
00337         }
00338         if {![info exists exif_formats($format)]} continue
00339         if {[info exists exif_tags($tag)]} { set tag $exif_tags($tag) }
00340         set size [expr {$exif_formats($format) * $components}]
00341         if {$size > 4} {
00342             _scan $byteOrder $value i value
00343             #puts "$value"
00344             #set value [string range $data [expr {$i + $offset + $value}] [expr {$size - 1}]]
00345         }
00346         lappend ret $tag [_format $byteOrder $value $format $components]
00347     }
00348 }
00349 
00350 /*  reads an exif block and returns key-value pairs*/
00351 ret  ::jpeg::_exif (type fh , type byteOrder , type offset) {
00352     variable exif_formats
00353     variable exif_tags
00354     set return {}
00355     for {_scan $byteOrder [read $fh 2] s num} {$num > 0} {incr num -1} {
00356         binary scan [read $fh 2] H2H2 t1 t2
00357         _scan $byteOrder [read $fh 6] si format components
00358         if {$byteOrder == "big"} {
00359             set tag $t1$t2
00360         } else {
00361             set tag $t2$t1
00362         }
00363         set value [read $fh 4]
00364         # special tags, they point to more exif blocks
00365         if {$tag == "8769" || $tag == "a005"} {
00366             _scan $byteOrder $value i next
00367             set pos [tell $fh]
00368             seek $fh [expr {$offset + $next}] start
00369             eval lappend return [_exif $fh $byteOrder $offset]
00370             seek $fh $pos start
00371             continue
00372         }
00373         if {![info exists exif_formats($format)]} continue
00374         if {[info exists exif_tags($tag)]} { set tag $exif_tags($tag) }
00375         set size [expr {$exif_formats($format) * $components}]
00376         # if the data is over 4 bytes, its stored later in the file, with the
00377         # data being the offset relative to the exif header
00378         if {$size > 4} {
00379             set pos [tell $fh]
00380             _scan $byteOrder $value i value
00381             seek $fh [expr {$offset + $value}] start
00382             set value [read $fh $size]
00383             seek $fh $pos start
00384         }
00385         lappend return $tag [_format $byteOrder $value $format $components]
00386     }
00387     return $return
00388 }
00389 
00390 ret  ::jpeg::MakerNote (type offset , type byteOrder , type Make , type data) {
00391     if {$Make == "Canon"} {
00392         set data [MakerNoteCanon $offset $byteOrder $data]
00393     } elseif {[string match Nikon* $data] || $Make == "NIKON"} {
00394         set data [MakerNoteNikon $offset $byteOrder $data]
00395     } elseif {[string match FUJIFILM* $data]} {
00396         set data [MakerNoteFuji $offset $byteOrder $data]
00397     } elseif {[string match OLYMP* $data]} {
00398         set data [MakerNoteOlympus $offset $byteOrder $data]
00399     }
00400     return $data
00401 }
00402 
00403 ret  ::jpeg::MakerNoteNikon (type offset , type byteOrder , type data) {
00404     variable exif_formats
00405     set return {}
00406     if {[string match Nikon* $data]} {
00407         set i 8
00408     } else {
00409         set i 0
00410     }
00411     binary scan $data @8s num
00412     incr i 2
00413     puts [expr {($num * 12) + $i}]
00414     puts [string range $data 142 150]
00415     #exit
00416     for {} {$num > 0} {incr num -1} {
00417         binary scan $data @${i}H2H2 t1 t2
00418         if {$byteOrder == "big"} {
00419             set tag $t1$t2
00420         } else {
00421             set tag $t2$t1
00422         }
00423         incr i 2
00424         _scan $byteOrder $data @${i}si format components
00425         incr i 6
00426         set value [string range $data $i [expr {$i + 3}]]
00427         if {![info exists exif_formats($format)]} continue
00428         #if {[info exists exif_tags($tag)]} { set tag $exif_tags($tag) }
00429         set size [expr {$exif_formats($format) * $components}]
00430         if {$size > 4} {
00431             _scan $byteOrder $value i value
00432             puts "$value"
00433             set value 1
00434             #set value [string range $data [expr {$i + $offset + $value}] [expr {$size - 1}]]
00435         } else {
00436         
00437         lappend ret $tag [_format $byteOrder $value $format $components]
00438         }
00439         puts "$tag $format $components $value"
00440     }
00441     return $return
00442 }
00443 
00444 ret  ::jpeg::debug (type file) {
00445     set fh [openJFIF $file]
00446 
00447     puts "marker: d8 length: 0"
00448     puts "  SOI (Start Of Image)"
00449 
00450     foreach marker [markers $fh] {
00451         seek $fh [lindex $marker 1] 
00452         puts "marker: [lindex $marker 0] length: [lindex $marker 2]"
00453         switch -glob -- [lindex $marker 0] {
00454             c[0-3] {
00455                 binary scan [read $fh 6] cSSc precision height width color
00456                 puts "  SOF (Start Of Frame) [string map {c0 "Baseline" c1 "Non-baseline" c2 "Progressive" c3 "Lossless"} [lindex $marker 0]]"
00457                 puts "    Image dimensions: $width $height"
00458                 puts "    Precision: $precision"
00459                 puts "    Color Components: $color"
00460             }
00461             c4 {
00462                 puts "  DHT (Define Huffman Table)"
00463                 binary scan [read $fh 17] cS bits symbols
00464                 puts "    $symbols symbols"
00465             }
00466             da {
00467                 puts "  SOS (Start Of Scan)"
00468                 binary scan [read $fh 2] c num
00469                 puts "    Components: $num"
00470             }
00471             db {
00472                 puts "  DQT (Define Quantization Table)"
00473             }
00474             dd {
00475                 puts "  DRI (Define Restart Interval)"
00476                 binary scan [read $fh 2] S num
00477                 puts "    Interval: $num blocks"
00478             }
00479             e0 {
00480                 set id [read $fh 5]
00481                 if {$id == "JFIF\x00"} {
00482                     puts "  JFIF"
00483                     binary scan [read $fh 9] cccSScc ver1 ver2 units xr vr xt yt
00484                     puts "    Header: $ver1.$ver2 $units $xr $vr $xt $yt"
00485                 } elseif {$id == "JFXX\x00"} {
00486                     puts "  JFXX (JFIF Extension)"
00487                     binary scan [read $fh 1] H2 excode
00488                     if {$excode == "10"} { set excode "10 (JPEG thumbnail)" }
00489                     if {$excode == "11"} { set excode "11 (Palletized thumbnail)" }
00490                     if {$excode == "13"} { set excode "13 (RGB thumbnail)" }
00491                     puts "    Extension code: 0x$excode"
00492                 } else {
00493                     puts "  Unknown APP0 segment: $id"
00494                 }
00495             }
00496             e1 {
00497                 if {[read $fh 6] == "Exif\x00\x00"} {
00498                     puts "  EXIF data"
00499                     puts "    MAIN EXIF"
00500                     foreach {x y} [getExif $file] {
00501                         puts "    $x $y"
00502                     }
00503                     puts "    THUMBNAIL EXIF"
00504                     foreach {x y} [getExif $file thumbnail] {
00505                         puts "    $x $y"
00506                     }
00507                 } else {
00508                     puts "  APP1 (unknown)"
00509                 }
00510             }
00511             e2 {
00512                 if {[read $fh 12] == "ICC_PROFILE\x00"} {
00513                     puts "  ICC profile"
00514                 } else {
00515                     puts "  APP2 (unknown)"
00516                 }
00517             }
00518             ed {
00519                 if {[read $fh 18] == "Photoshop 3.0\0008BIM"} {
00520                     puts "  Photoshop 8BIM data"
00521                 } else {
00522                     puts "  APP13 (unknown)"
00523                 }
00524             }
00525             ee {
00526                 if {[read $fh 5] == "Adobe"} {
00527                     puts "  Adobe metadata"
00528                 } else {
00529                     puts "  APP14 (unknown)"
00530                 }
00531             }
00532             e[3456789abcf] {
00533                 puts [format "  %s%d %s" APP 0x[string index [lindex $marker 0] 1] (unknown)]
00534             }
00535             fe {
00536                 puts "  Comment: [read $fh [lindex $marker 2]]"
00537             }
00538             default {
00539                 puts "  Unknown"
00540             }
00541         }
00542     }
00543 }
00544 
00545 /*  for mapping the exif format types to byte lengths*/
00546 array  ::jpeg = ::exif_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]
00547 
00548 /*  list of recognized exif tags. if a tag is not listed here it will show up as its raw hex value*/
00549 array  ::jpeg = ::exif_tags {
00550     0100 ImageWidth
00551     0101 ImageLength
00552     0102 BitsPerSample
00553     0103 Compression
00554     0106 PhotometricInterpretation
00555     0112 Orientation
00556     0115 SamplesPerPixel
00557     011c PlanarConfiguration
00558     0212 YCbCrSubSampling
00559     0213 YCbCrPositioning
00560     011a XResolution
00561     011b YResolution
00562     0128 ResolutionUnit
00563 
00564     0111 StripOffs = 
00565     0116 RowsPerStrip
00566     0117 StripByteCounts
00567     0201 JPEGInterchangeFormat
00568     0202 JPEGInterchangeFormatLength
00569 
00570     012d TransferFunction
00571     013e WhitePoint
00572     013f PrimaryChromaticities
00573     0211 YCbCrCoefficients
00574     0213 YCbCrPositioning
00575     0214 ReferenceBlackWhite
00576 
00577     0132 DateTime
00578     010e ImageDescription
00579     010f Make
00580     0110 Model
00581     0131 Software  
00582     013b Artist
00583     8298 Copyright
00584     
00585     9000 ExifVersion  
00586     a000 FlashpixVersion
00587 
00588     a001 ColorSpace
00589 
00590     9101 ComponentsConfiguration
00591     9102 CompressedBitsPerPixel
00592     a002 ExifImageWidth
00593     a003 ExifImageHeight
00594 
00595     927c MakerNote
00596     9286 UserComment
00597 
00598     a004 RelatedSoundFile
00599 
00600     9003 DateTimeOriginal
00601     9004 DateTimeDigitized
00602     9290 SubsecTime
00603     9291 SubsecTimeOriginal
00604     9292 SubsecTimeDigitized
00605 
00606     829a ExposureTime
00607     829d FNumber
00608     8822 ExposureProgram
00609     8824 SpectralSensitivity
00610     8827 ISOSpeedRatings
00611     8828 OECF
00612     9201 ShutterSpeedValue
00613     9202 ApertureValue
00614     9203 BrightnessValue
00615     9204 ExposureBiasValue
00616     9205 MaxApertureValue
00617     9206 SubjectDistance
00618     9207 MeteringMode
00619     9208 LightSource
00620     9209 Flash
00621     920a FocalLength
00622     9214 SubjectArea
00623     a20b FlashEnergy
00624     a20c SpatialFrequencyResponse
00625     a20e FocalPlaneXResolution
00626     a20f FocalPlaneYResolution
00627     a210 FocalPlaneResolutionUnit
00628     a214 SubjectLocation
00629     a215 ExposureIndex
00630     a217 SensingMethod
00631     a300 FileSource
00632     a301 SceneType
00633     a302 CFAPattern
00634     a401 CustomRendered
00635     a402 ExposureMode
00636     a403 WhiteBalance
00637     a404 DigitalZoomRatio
00638     a405 FocalLengthIn35mmFilm
00639     a406 SceneCaptureType
00640     a407 GainControl
00641     a408 Contrast
00642     a409 Saturation
00643     a40a Sharpness
00644     a40b DeviceSettingDescription
00645     a40c SubjectDistanceRange
00646     a420 ImageUniqueID
00647 
00648     
00649     0001 InteroperabilityIndex
00650     0002 InteroperabilityVersion
00651     1000 RelatedImageFileFormat
00652     1001 RelatedImageWidth
00653     1002 RelatedImageLength
00654     
00655     00fe NewSubfileType
00656     00ff SubfileType
00657     013d Predictor
00658     0142 TileWidth
00659     0143 TileLength
00660     0144 TileOffs = 
00661     0145 TileByteCounts
00662     014a SubIFDs
00663     015b JPEGTables
00664     828d CFARepeatPatternDim
00665     828e CFAPattern
00666     828f BatteryLevel
00667     83bb IPTC/NAA
00668     8773 InterColorProfile
00669     8825 GPSInfo
00670     8829 Interlace
00671     882a TimeZoneOff
00672     882b =  SelfTimerMode
00673     920c SpatialFrequencyResponse
00674     920d Noise
00675     9211 ImageNumber
00676     9212 SecurityClassification
00677     9213 ImageHistory
00678     9215 ExposureIndex
00679     9216 TIFF/EPStandardID
00680 }
00681 
00682 /*  for mapping exif values to plain english by [formatExif]*/
00683 array  ::jpeg = ::exif_values {
00684     Compression,1 none
00685     Compression,6 JPEG
00686     Compression,  unknown
00687 
00688     PhotometricInterpretation,2 RGB
00689     PhotometricInterpretation,6 YCbCr
00690     PhotometricInterpretation,  unknown
00691 
00692     Orientation,1 normal
00693     Orientation,2 mirrored
00694     Orientation,3 "180 degrees"
00695     Orientation,4 "180 degrees, mirrored"
00696     Orientation,5 "90 degrees ccw, mirrored"
00697     Orientation,6 "90 degrees cw"
00698     Orientation,7 "90 degrees cw, mirrored"
00699     Orientation,8 "90 degrees ccw"
00700     Orientation,  unknown
00701 
00702     PlanarConfiguration,1 chunky
00703     PlanarConfiguration,2 planar
00704     PlanarConfiguration,  unknown
00705 
00706     YCbCrSubSampling,2,1 YCbCr4:2:2
00707     YCbCrSubSampling,2,2 YCbCr4:2:0
00708     YCbCrSubSampling,    unknown
00709 
00710     YCbCrPositioning,1 centered
00711     YCbCrPositioning,2 co-sited
00712     YCbCrPositioning,  unknown
00713 
00714     FlashpixVersion,0100 "Flashpix Format Version 1.0"
00715     FlashpixVersion,     unknown
00716 
00717     ColorSpace,1     sRGB
00718     ColorSpace,32768 uncalibrated
00719     ColorSpace,      unknown
00720 
00721     ExposureProgram,0 undefined
00722     ExposureProgram,1 manual
00723     ExposureProgram,2 normal
00724     ExposureProgram,3 "aperture priority"
00725     ExposureProgram,4 "shutter priority"
00726     ExposureProgram,5 creative
00727     ExposureProgram,6 action
00728     ExposureProgram,7 portrait
00729     ExposureProgram,8 landscape
00730     ExposureProgram,  unknown
00731 
00732     LightSource,0   unknown
00733     LightSource,1   daylight
00734     LightSource,2   flourescent
00735     LightSource,3   tungsten
00736     LightSource,4   flash
00737     LightSource,9   "fine weather"
00738     LightSource,10  "cloudy weather"
00739     LightSource,11  shade
00740     LightSource,12  "daylight flourescent"
00741     LightSource,13  "day white flourescent"
00742     LightSource,14  "cool white flourescent"
00743     LightSource,15  "white flourescent"
00744     LightSource,17  "standard light A"
00745     LightSource,18  "standard light B"
00746     LightSource,19  "standard light C"
00747     LightSource,20  D55
00748     LightSource,21  D65
00749     LightSource,22  D75
00750     LightSource,23  D50
00751     LightSource,24  "ISO studio tungsten"
00752     LightSource,255 other
00753     LightSource,    unknown
00754 
00755     Flash,0  "no flash"
00756     Flash,1  "flash fired"
00757     Flash,5  "strobe return light not detected"
00758     Flash,7  "strobe return light detected"
00759     Flash,9  "flash fired, compulsory flash mode"
00760     Flash,13 "flash fired, compulsory flash mode, return light not detected"
00761     Flash,15 "flash fired, compulsory flash mode, return light detected"
00762     Flash,16 "flash did not fire, compulsory flash mode"
00763     Flash,24 "flash did not fire, auto mode"
00764     Flash,25 "flash fired, auto mode"
00765     Flash,29 "flash fired, auto mode, return light not detected"
00766     Flash,31 "flash fired, auto mode, return light detected"
00767     Flash,32 "no flash function"
00768     Flash,65 "flash fired, red-eye reduction mode"
00769     Flash,69 "flash fired, red-eye reduction mode, return light not detected"
00770     Flash,71 "flash fired, red-eye reduction mode, return light detected"
00771     Flash,73 "flash fired, compulsory mode, red-eye reduction mode"
00772     Flash,77 "flash fired, compulsory mode, red-eye reduction mode, return light not detected"
00773     Flash,79 "flash fired, compulsory mode, red-eye reduction mode, return light detected"
00774     Flash,89 "flash fired, auto mode, red-eye reduction mode"
00775     Flash,93 "flash fired, auto mode, return light not detected, red-eye reduction mode"
00776     Flash,95 "flash fired, auto mode, return light detected, red-eye reduction mode"
00777     Flash,   unknown
00778 
00779     ResolutionUnit,2 inch
00780     ResolutionUnit,3 centimeter
00781     ResolutionUnit,  unknown
00782 
00783     SensingMethod,1 undefined
00784     SensingMethod,2 "one chip color area sensor"
00785     SensingMethod,3 "two chip color area sensor"
00786     SensingMethod,4 "three chip color area sensor"
00787     SensingMethod,5 "color sequential area sensor"
00788     SensingMethod,7 "trilinear sensor"
00789     SensingMethod,8 "color sequential linear sensor"
00790     SensingMethod,  unknown
00791 
00792     SceneType,\x01\x00\x00\x00 "directly photographed image"
00793     SceneType,                 unknown
00794 
00795     CustomRendered,0 normal
00796     CustomRendered,1 custom
00797 
00798     ExposureMode,0 auto
00799     ExposureMode,1 manual
00800     ExposureMode,2 "auto bracket"
00801     ExposureMode,  unknown
00802 
00803     WhiteBalance,0 auto
00804     WhiteBlanace,1 manual
00805     WhiteBlanace,  unknown
00806 
00807     SceneCaptureType,0 standard
00808     SceneCaptureType,1 landscape
00809     SceneCaptureType,2 portrait
00810     SceneCaptureType,3 night
00811     SceneCaptureType,  unknown
00812 
00813     GainControl,0 none
00814     GainControl,1 "low gain up"
00815     GainControl,2 "high gain up"
00816     GainControl,3 "low gain down"
00817     GainControl,4 "high gain down"
00818     GainControl,  unknown
00819 
00820     Contrast,0 normal
00821     Contrast,1 soft
00822     Contrast,2 hard
00823     Contrast,  unknown
00824 
00825     Saturation,0 normal
00826     Saturation,1 low
00827     Saturation,2 high
00828     Saturation,  unknown
00829 
00830     Sharpness,0 normal
00831     Sharpness,1 soft
00832     Sharpness,2 hard
00833     Sharpness,  unknown
00834 
00835     SubjectDistanceRange,0 unknown
00836     SubjectDistanceRange,1 macro
00837     SubjectDistanceRange,2 close
00838     SubjectDistanceRange,3 distant
00839     SubjectDistanceRange,  unknown
00840     
00841     MeteringMode,0   unknown
00842     MeteringMode,1   average
00843     MeteringMode,2   "center weighted average"
00844     MeteringMode,3   spot
00845     MeteringMode,4   multi-spot
00846     MeteringMode,5   multi-segment
00847     MeteringMode,6   partial
00848     MeteringMode,255 other
00849     MeteringMode,    unknown
00850     
00851     FocalPlaneResolutionUnit,2 inch
00852     FocalPlaneResolutionUnit,3 centimeter
00853     FocalPlaneResolutionUnit,  none
00854     
00855     DigitalZoomRatio,0 "not used"
00856     
00857     FileSource,\x03\x00\x00\x00 "digital still camera"
00858     FileSource,                 unknown
00859 }
00860 
00861 /*  [binary scan], in the byte order indicated by $e*/
00862 ret  ::jpeg::_scan (type e , type v , type f , type args) {
00863      foreach x $args { upvar 1 $x $x }
00864      if {$e == "big"} {
00865          eval [list binary scan $v [string map {b B h H s S i I} $f]] $args
00866      } else {
00867          eval [list binary scan $v $f] $args
00868      }
00869 }
00870 
00871 
00872 /*  formats exif values, the numbers correspond to data types*/
00873 /*  values may be either byte order, as indicated by $end*/
00874 /*  see the exif spec for more info*/
00875 ret  ::jpeg::_format (type end , type value , type type , type num) {
00876     if {$num > 1 && $type != 2 && $type != 7} {
00877         variable exif_formats
00878         set r {}
00879         for {set i 0} {$i < $num} {incr i} {
00880             set len $exif_formats($type)
00881             lappend r [_format $end [string range $value [expr {$len * $i}] [expr {($len * $i) + $len - 1}]] $type 1]
00882         }
00883         return [join $r ,]
00884     }
00885     switch -exact -- $type {
00886         1 { _scan $end $value c value }
00887         2 { set value [string trimright $value \x00] }
00888         3 {
00889             _scan $end $value s value
00890             set value [format %u $value]
00891         }
00892         4 {
00893             _scan $end $value i value
00894             set value [format %u $value]
00895         }
00896         5 {
00897             _scan $end $value ii n d
00898             set n [format %u $n]
00899             set d [format %u $d]
00900             if {$d == 0} {set d 1}
00901             #set value [string trimright [string trimright [format %5.4f [expr {double($n) / $d}]] 0] .]
00902             set value [string trimright [string trimright [expr {double($n) / $d}] 0] .]
00903             #set value "$n/$d"
00904         }
00905         6 { _scan $end $value c value }
00906         8 { _scan $end $value s value }
00907         9 { _scan $end $value i value }
00908         10 {
00909             _scan $end $value ii n d
00910             if {$d == 0} {set d 1}
00911             #set value [string trimright [string trimright [format %5.4f [expr {double($n) / $d}]] 0] .]
00912             set value [string trimright [string trimright [expr {double($n) / $d}] 0] .]
00913             #set value "$n/$d"
00914         }
00915         11 { _scan $end $value i value }
00916         12 { _scan $end $value w value }
00917     }
00918     return $value
00919 }
00920 
00921 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1