For context, I'm writing a Python program that writes out images. But these images are a bit special in the sense that they are used as intermediate data containers that are further digested by other programs written in C and use the libgd
library. I have no clue about C.
My precise problem is that I have a Numpy array of dtype='uint32'
. I want to decode this array to get 4 arrays of dtype='uint8'
, and then use them to write out an image. This can be done with numpy.view
:
img_decoded = img_coded[:, :, np.newaxis].view('uint8')
Now, img_decoded
is of shape (dimY, dimX, 4)
. My doubt is what index of the third dimension should I make correspond to what channel . The C programs I'm interacting with expect that the most significative byte is written to the Alpha channel, then Red, then Green and finally Blue. How can I make sure that this correspondence is fulfilled? I'm aware this has something to do with endianness, but this concept is still fuzzy to me.
Related to all this, I have been playing with this to try to gain insight in these concepts, but yet commands like this blow my mind:
In []: np.array([256 * 4 + 1], dtype='uint16').view(dtype='uint8')
Out[]: array([1, 4], dtype=uint8)
What does this tell me about the order of the most significant bit? Why is the output [1,4]
and not the other way around? What has this to do with endianness?
The C programs I'm interacting with expect that the most significative byte is written to the Alpha channel, then Red, then Green and finally Blue. How can I make sure that this correspondence is fulfilled?
This is highly dependent of both the pixel encoding method and the target platform .
Regarding the encoding, some libraries use the BGRA format while some use the RGBA format for example. Many support multiple format but one need to be selected at a time.
On conventional/mainstream platforms, an uint32
type is composed of 4 x 8 bits and is stored in 4 consecutive 8-bit bytes of memory. The 8 most significant bits can be stored in the byte with the lowest memory address or the highest memory address regarding the platform. This is indeed what is called endianness . Some platform can have weird endianness (like middle endian) or can support multiple endianness resulting in some case to runtime-defined endianness (AFAIK, ARM and POWER for example support that although the "default" endianness should be the little-endian nowadays). Endianness issues happens only on native types (or low-level unions) with a size of multiple bytes.
You can check the endianness at runtime with the example code you provided (although using a uint32
-typed variable is safer). Regarding the result (ie. [1, 4]
or [4, 1]
) you can guess the endianness. Based on the endianness, you can use a if-else statement to encode, decode or even directly compute the pixels (you can put that in a generic encoding/decoding function).
An alternative solution is not to use views at all and use portable bit-wise operations (independent of the endianness of the target platform).
Here is an example:
alpha = img_coded >> 24
red = (img_coded >> 16) & 0xFF
green = (img_coded >> 8) & 0xFF
blue = img_coded & 0xFF
What does this tell me about the order of the most significant bit? Why is the output [1,4] and not the other way around? What has this to do with endianness?
This means your platform use the little-endian format. This is what mainstream x86-64 platforms use. The little-endian format store the less-significant bytes first ( 1
here). The same code on a big-endian platform should result in [4,1]
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.