Reading WEBP image dimensions

Keith Vetter 2013-06-01 : Webp is a image format for both lossy and lossless compression developed by Google in 2010. It produces smaller files than either jpeg or png. It is supported by both Chrome and Opera browsers.

Here's code to read a webp file header and return the images dimensions.

proc webpsize {fname} {
    set fin [open $fname rb]
    set chunk0 [read $fin 12]
    set chunk1 [read $fin 28]
    close $fin

    binary scan $chunk0 "a4ia4" riff size id
    if {$riff ne "RIFF" || $id ne "WEBP"} {
        error "not a webp file"
    }
    binary scan $chunk1 "a4" vp8
    if {$vp8 eq "VP8L"} { return [webp.VP8L $chunk1]}
    if {$vp8 eq "VP8 "} { return [webp.VP8 $chunk1] }
    # VP8X extended format blocks should be skipped but are handled.
    # Just seek $size bytes forward but I haven't seen an example to test.
    error "unknown VP8 block"
}
proc webp.VP8 {chunk1} {
    # http://tools.ietf.org/html/rfc6386#page-30
    binary scan $chunk1 "a4cu7cu3tt" vp8 frameTag startCode width height
    lassign $startCode b0 b1 b2
    if {$b0 != 0x9d || $b1 != 0x01 || $b2 != 0x2a} {
        error "missing start code block"
    }
    set width [expr {$width & 0x3fff}]
    set height [expr {$height & 0x3fff}]
    return [list $width $height]
}

proc webp.VP8L {chunk1} {
    # https://gerrit.chromium.org/gerrit/gitweb?p=webm/libwebp.git;a=blob;f=doc/webp-lossless-bitstream-spec.txt;hb=master
    binary scan $chunk1 a4icucu4 vp8 size signature sizeInfo
    lassign $sizeInfo b0 b1 b2 b3
    set width [expr {1 + ((($b1 & 0x3F) << 8) | $b0)}]
    set height [expr {1 + ((($b3 & 0xF) << 10) | ($b2 << 2) | (($b1 & 0xC0) >> 6))}]
    return [list $width $height]
}