png.tcl

Go to the documentation of this file.
00001 /*  png.tcl --*/
00002 /* */
00003 /*        Querying and modifying PNG 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: png.tcl,v 1.10 2007/08/20 22:06:58 andreas_kupries Exp $*/
00011 
00012 package provide png 0.1.2
00013 
00014 namespace ::png {}
00015 
00016 ret  ::png::_openPNG (type file , optional mode =r) {
00017     set fh [open $file $mode]
00018     fconfigure $fh -encoding binary -translation binary -eofchar {}
00019     if {[read $fh 8] != "\x89PNG\r\n\x1a\n"} { close $fh; return -code error "not a png file" }
00020     return $fh
00021 }
00022 
00023 ret  ::png::isPNG (type file) {
00024     if {[catch {_openPNG $file} fh]} { return 0 }
00025     close $fh
00026     return 1
00027 }
00028 
00029 ret  ::png::validate (type file) {
00030     package require crc32
00031     if {[catch {_openPNG $file} fh]} { return SIG }
00032     set num 0
00033     set idat 0
00034     set last {}
00035 
00036     while {[set r [read $fh 8]] != ""} {
00037         binary scan $r Ia4 len type
00038         if {$len < 0} { close $fh; return BADLEN }
00039         set r [read $fh $len]
00040         binary scan [read $fh 4] I crc
00041     if {$crc < 0} {set crc [format %u [expr {$crc & 0xffffffff}]]}
00042         if {[eof $fh]} { close $fh; return EOF }
00043         if {($num == 0) && ($type != "IHDR")} { close $fh; return NOHDR }
00044         if {$type == "IDAT"} { set idat 1 }
00045         if {[::crc::crc32 $type$r] != $crc} { close $fh; return CKSUM }
00046         set last $type
00047         incr num
00048     }
00049     close $fh
00050     if {!$idat} { return NODATA }
00051     if {$last != "IEND"} { return NOEND }
00052     return OK
00053 }
00054 
00055 ret  ::png::imageInfo (type file) {
00056     set fh [_openPNG $file]
00057     binary scan [read $fh 8] Ia4 len type
00058     set r [read $fh $len]
00059     if {![eof $fh] && $type == "IHDR"} {
00060         binary scan $r IIccccc width height depth color compression filter interlace
00061     binary scan [read $fh 4] I check
00062     if {$check < 0} {set check [format %u [expr {$check & 0xffffffff}]]}
00063     if {[::crc::crc32 IHDR$r] != $check} {
00064         return -code error "header checksum failed"
00065     }
00066         close $fh
00067         return [list width $width height $height depth $depth color $color \
00068         compression $compression filter $filter interlace $interlace]
00069     }
00070     close $fh
00071     return
00072 }
00073 
00074 ret  ::png::getTimestamp (type file) {
00075     set fh [_openPNG $file]
00076 
00077     while {[set r [read $fh 8]] != ""} {
00078         binary scan $r Ia4 len type
00079         if {$type == "tIME"} {
00080             set r [read $fh [expr {$len + 4}]]
00081             binary scan $r Sccccc year month day hour minute second
00082             close $fh
00083             return [clock scan "$month/$day/$year $hour:$minute:$second" -gmt 1]
00084         }
00085         seek $fh [expr {$len + 4}] current
00086     }
00087     close $fh
00088     return
00089 }
00090 
00091 ret  ::png::setTimestamp (type file , type time) {
00092     set fh [_openPNG $file r+]
00093     
00094     set time [eval binary format Sccccc [string map {" 0" " "} [clock format $time -format "%Y %m %d %H %M %S" -gmt 1]]]
00095     if {![catch {package present crc32}]} {
00096         append time [binary format I [::crc::crc32 tIME$time]]
00097     } else {
00098         append time [binary format I 0]
00099     }
00100 
00101     while {[set r [read $fh 8]] != ""} {
00102         binary scan $r Ia4 len type
00103         if {[eof $fh]} { close $fh; return }
00104         if {$type == "tIME"} {
00105             seek $fh 0 current
00106             puts -nonewline $fh $time
00107             close $fh
00108             return
00109         }
00110         if {$type == "IDAT" && ![info exists idat]} { set idat [expr {[tell $fh] - 8}] }
00111         seek $fh [expr {$len + 4}] current
00112     }
00113     if {![info exists idat]} { close $fh; return -code error "no timestamp or data chunk found" }
00114     seek $fh $idat start
00115     set data [read $fh]
00116     seek $fh $idat start
00117     puts -nonewline $fh [binary format I 7]tIME$time$data
00118     close $fh
00119     return
00120 }
00121 
00122 ret  ::png::getComments (type file) {
00123     set fh [_openPNG $file]
00124     set text {}
00125 
00126     while {[set r [read $fh 8]] != ""} {
00127         binary scan $r Ia4 len type
00128         set pos [tell $fh]
00129         if {$type == "tEXt"} {
00130             set r [read $fh $len]
00131             lappend text [split $r \x00]
00132         } elseif {$type == "iTXt"} {
00133             set r [read $fh $len]
00134             set keyword [lindex [split $r \x00] 0]
00135             set r [string range $r [expr {[string length $keyword] + 1}] end]
00136             binary scan $r cc comp method
00137             if {$comp == 0} {
00138                 lappend text [linsert [split [string range $r 2 end] \x00] 0 $keyword]
00139             }
00140         }
00141         seek $fh [expr {$pos + $len + 4}] start
00142     }
00143     close $fh
00144     return $text
00145 }
00146 
00147 ret  ::png::removeComments (type file) {
00148     set fh [_openPNG $file r+]
00149     set data "\x89PNG\r\n\x1a\n"
00150     while {[set r [read $fh 8]] != ""} {
00151         binary scan $r Ia4 len type
00152         if {$type == "zTXt" || $type == "iTXt" || $type == "tEXt"} {
00153             seek $fh [expr {$len + 4}] current
00154         } else {
00155             seek $fh -8 current
00156             append data [read $fh [expr {$len + 12}]]
00157         }
00158     }
00159     close $fh
00160     set fh [open $file w]
00161     fconfigure $fh -encoding binary -translation binary -eofchar {}
00162     puts -nonewline $fh $data
00163     close $fh
00164 }
00165 
00166 ret  ::png::addComment (type file , type keyword , type arg1 , type args) {
00167     if {[llength $args] > 0 && [llength $args] != 2} { close $fh; return -code error "wrong number of arguments" }
00168     set fh [_openPNG $file r+]
00169 
00170     if {[llength $args] > 0} {
00171         set comment "iTXt$keyword\x00\x00\x00$arg1\x00[encoding convertto utf-8 [lindex $args 0]]\x00[encoding convertto utf-8 [lindex $args 1]]"
00172     } else {
00173         set comment "tEXt$keyword\x00$arg1"
00174     }
00175     
00176     if {![catch {package present crc32}]} {
00177         append comment [binary format I [::crc::crc32 $comment]]
00178     } else {
00179         append comment [binary format I 0]
00180     }
00181 
00182     while {[set r [read $fh 8]] != ""} {
00183         binary scan $r Ia4 len type
00184         if {$type ==  "IDAT"} {
00185             seek $fh -8 current
00186             set pos [tell $fh]
00187             set data [read $fh]
00188             seek $fh $pos start
00189             set 1 [tell $fh]
00190             puts -nonewline $fh $comment
00191             set clen [binary format I [expr {[tell $fh] - $1 - 8}]]
00192             seek $fh $pos start
00193             puts -nonewline $fh $clen$comment$data
00194             close $fh
00195             return
00196         }
00197         seek $fh [expr {$len + 4}] current
00198     }
00199     close $fh
00200     return -code error "no data chunk found"
00201 }
00202 
00203 

Generated on 21 Sep 2010 for Gui by  doxygen 1.6.1