Reading PNG image dimensions

Developed specially for the Wiki by Donal Fellows...


 proc pngsize {filename} {
     if {[file size $filename] < 33} {
         error "File $filename not large enough to contain PNG header"
     }
     set f [open $filename r]
     fconfigure $f -encoding binary -translation binary

     # Read PNG file signature
     binary scan [read $f 8] c8 sig
     foreach b1 $sig b2 {-119 80 78 71 13 10 26 10} {
         if {$b1 != $b2} {
             close $f
             error "$filename is not a PNG file"
         }
     }

     # Read IHDR chunk signature
     binary scan [read $f 8] c8 sig
     foreach b1 $sig b2 {0 0 0 13 73 72 68 82} {
         if {$b1 != $b2} {
             close $f
             error "$filename is missing a leading IHDR chunk"
         }
     }

     # Read off the size of the image
     binary scan [read $f 8] II width height
     # Ignore the rest of the data, including the chunk CRC!
     #binary scan [read $f 5] ccccc depth type compression filter interlace
     #binary scan [read $f 4] I chunkCRC

     close $f
     return [list $width $height]
 }

See also "Reading GIF image dimensions", "CRC", and "Reading JPEG image dimensions".


AM Also see Writing PNG files for sample code to write a PNG file - precursor for a package to be ... :)


AF I accidentally duplicated this, but mine is somewhat shorter and returns all of the image info:

 proc read_png_header {file} {
    set fh [open $file r]
    fconfigure $fh -encoding binary -translation binary -eofchar {}
    if {[read $fh 8] != "\x89PNG\r\n\x1a\n"} { close $fh; return }
    binary scan [read $fh 8] Ia4 len type
    set r [read $fh $len]
    if {![eof $fh] && $type == "IHDR"} {
        binary scan $r IIccccc width height depth color compression filter interlace
        close $fh
        return [list $width $height $depth $color $compression $filter $interlace]
    }
    close $fh
    return
 }

This functionality is also present in the tcllib png module.


See also