16 bit PNG images are stored as big endian
I just found out that the way we read 16 bit PNG images is incorrect. As specified here: https://www.w3.org/TR/PNG/#7Integers-and-byte-order 16 bit PNGs (or for color: 48 bit PNGs) are stored in big endian format, which is apparently not changed to little endian, when we read https://gitlab.idiap.ch/bob/bob.io.image/blob/master/bob/io/image/cpp/png.cpp#L152 or write https://gitlab.idiap.ch/bob/bob.io.image/blob/master/bob/io/image/cpp/png.cpp#L323 images.
Hence, when reading a 16 bit png, the byte order is changed. Running:
>>> import bob.io.image
>>> i = bob.io.image.load("16bit.png")
>>> b = (i / 256).astype("uint8")
>>> bob.io.base.save(b, "uint8.png")
we will end up with garbage, while
>>> b = i.astype("uint8")
which will cut off the Most Significant Byte (which is the LSB in our case, since we did not correct the byte order) will end up in a correct image.
A solution would be to change the endianess while reading and writing 16 bit PNGs in the above-mentioned links.
NB. I am also working on a way in C++ to be able to load 16 bit pngs into 8 bit automatically, i.e., here: https://gitlab.idiap.ch/bob/bob.io.image/blob/master/bob/io/image/include/bob.io.image/image.h#L50.
So far, I could simply replace png.read
with pmg.cast
in https://gitlab.idiap.ch/bob/bob.io.image/blob/master/bob/io/image/include/bob.io.image/png.h#L99 (which will do the same as i.astype
above). However, when we fix the endianess (which we should definitely do), this would turn into something more complicated as we now need to convert
instead of cast
ing.
I am currently working on a solution for both.