kotlinbitwise-operatorsbit-shiftwebp

Parsing webp file header in Kotlin to get its height and width, but getting unexpected results


I am trying to read the WebP image header, according to the WebP Container Specification of Extended File Format.

fun get24bit(data: ByteArray, index: Int): Int {
    return ((data[0 + index].toInt()) or (data[1 + index].toInt() shl 8) or (data[2 + index].toInt() shl 16))
}

fun get32bit(data: ByteArray, index: Int): Int {
    return get24bit(data, index) or (data[3 + index].toInt() shl 24)
}

// data -> File(fileName).readBytes() for testing purpose
fun webpExtract(data: ByteArray) {
    println(String(data.copyOfRange(0, 4)))
    println("Size: ${get32bit(data, 4)}")
    println(String(data.copyOfRange(8, 12)))
    println(String(data.copyOfRange(12, 16)))
    // 16, 17, 18, 19 reserved

    val width = 1 + get24bit(data, 20)
    val height = 1 + get24bit(data, 23)

    println("Width: $width, Height: $height")
}

And the outputs are:

RIFF
Size: -52
WEBP
VP8X
Width: 17, Height: 32513

The String outputs are alright, but the Size is getting negative and Width and Heights are wrong i.e. They should be 128 and 128 respectively (for the test image I've used).

Is there something wrong in the code? I am not able to figure out what's the problem.

I've also verified the actual C++ implementation here in github. My code does the same bit shifting, but the results are not correct. As far as I know, left shifting does not has anything to do with unsigned and signed right?


Solution

  • Don't know the Spec was incomplete or something, I logged the byte values and found a pattern somehow. And found that the dimensions are at 24-26 and 27-29 indexes.

    val width = 1 + (get24bit(data, 24))
    val height = 1 + (get24bit(data, 27))
    

    This does the trick! Hopefully it is helpful to note this point as long as documentation is not updated.