00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 package provide jpeg 0.3
00013
00014 namespace ::jpeg {}
00015
00016
00017
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
00029 ret ::jpeg::isJPEG (type file) {
00030 set is [catch {openJFIF $file} fh]
00031 catch {close $fh}
00032 return [expr {!$is}]
00033 }
00034
00035
00036
00037
00038
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
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
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
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
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
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
00169
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
00200
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
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
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
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
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
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
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
00873
00874
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