我目前正在实现一个程序来读取和解码 BMP 文件中的图像。但我对像素格式,尤其是位字节顺序感到非常困惑。
我目前的理解是,当提到像素格式时,例如RGBA32,我们以人类的方式说它,即使用大端,因此第一个字节是R,第二个G,第三个B,第四个字节答:
RGBA32
11111111 22222222 33333333 44444444
R G B A
当将大/小尾数附加到此格式时,例如 RGBA32BE/RGBA32LE,这将相应地改变字节顺序,如下所示:
RGBA32BE (unchanged)
11111111 22222222 33333333 44444444
R G B A
RGBA32LE (reversed)
11111111 22222222 33333333 44444444
A B G R
这对我来说看起来很自然,只要我们是假设每个组件的单独值正是我们读取的字节值。
然而,当组件大小小于 1 字节或 8 位时,事情开始让我感到困惑。说RGB555BE,我想下面是它如何表示为字节数组:
RGB555BE
1'22222'33 333'44444
A R G B
0'00001'00 000'00000
-
我们将 R 组件读取为 10000=16或<代码>00001=1?
-
我更困惑的是我们读取组件的方式(位字节序)是否与字节字节序有关?
-
RGB555LE格式在字节数组中的表示方式是什么?
<前><代码>RGB555LE_v1
333'44444 1'22222'33
G”酒吧G'
000'00000 0'00001'00
或 RGB555LE_v2 ?
44444'333 33'22222'1
BGRA
00000'000 00'10000'0
I am currently implementing a program to read and decode image from a BMP file. But I am really confused about the pixel format and especially about bit endianness.
My current understanding is when referring to a pixel format, e.g. RGBA32, we are saying it in our human way, which is using big endian, thus the first byte is R, second G, third B, fourth A:
RGBA32
11111111 22222222 33333333 44444444
R G B A
And when appending big/little endian to this format, such as RGBA32BE/RGBA32LE, this will change the byte order accordingly, as:
RGBA32BE (unchanged)
11111111 22222222 33333333 44444444
R G B A
RGBA32LE (reversed)
11111111 22222222 33333333 44444444
A B G R
This all looks naturally to me, as long as we are assuming the individual value of each component is exactly the value of byte we read.
However things start to confuse me when component size is less than 1 byte or 8 bits. Say RGB555BE, I suppose below is how it is represented as byte array:
RGB555BE
1'22222'33 333'44444
A R G B
0'00001'00 000'00000
-
Do we read the R component as 10000=16
or 00001=1
?
-
I'm even more confused about if the way we read the component (bit endianness) is related to byte endianness?
-
Which way is RGB555LE format represented in byte array?
RGB555LE_v1
333'44444 1'22222'33
G" B A R G'
000'00000 0'00001'00
or RGB555LE_v2 ?
44444'333 33'22222'1
B G R A
00000'000 00'10000'0
发布评论
评论(2)
我们可以使用 FFmpeg 来测试不同的像素格式。
结论是:
uint16
) 时,字节序相关。Little endian:
uint16
元素的字节顺序为:[LSB,MSB]。位尾序:
uint16
元素的字节顺序为:[MSB,LSB]。执行 FFmpeg CLI 命令进行测试:
从
rgb24
开始,例如:使用一些十六进制查看器,例如 HxD 用于检查原始文件内容。
red.raw FF 00 00 FF 00 00
...blue.raw 00 FF 00 00 FF 00
...green.raw 00 00 FF 00 00 FF
...rgba
像素格式:r:
FF 00 00 FF
g:
00 FF 00 FF
b:
00 00 FF FF
FFmpeg 约定字节顺序。
我们无法确定命名是应用小端还是大端。
使用
uint16
组件(而不是uint8
组件)时,字节序是相关的。rgba
像素格式:r:
FF 00 00 FF
g:
00 FF 00 FF
b:
00 00 FF FF
A
然后R
然后G
然后B
然后< code>A...我们可以将
rgba
称为RGBA32BE
,但这太混乱了...rgb555le
像素格式:r :<代码>00 7C 00 7C
g:
E0 03 E0 03
b:
1F 00 1F 00
我们还可以检查较低位(用于位排序):
将颜色设置为 8,因此移位后值为 1。
r:
01 00 01 00
2 位字节:00000001 00000000
g:
20 00 20 00
2 个字节(以位为单位):00100000 00000000
b:
00 04 00 04
2 个字节(以位为单位):00000000 00000100
rgb555be 像素格式:
r:
7C 00 7C 00
g:
03 E0 03 E0
b:
00 1F 00 1F
检查低位(用于位排序):
r:
00 01 00 01
g:
00 20 00 20
b:
04 00 04 00
在大端格式中,仅交换字节。
(对于每个 uint16 元素(两个字节),第一个和第二个字节的顺序交换)。
问题答案:
10000=16
还是00001=1 ?
答案:
对于 rgb555le:
00000001 00000000
对于 rgb555be:
00000000 00000001
答案:
在像素格式的上下文中,不存在“位字节顺序”,只有“字节字节顺序”。
位字节序与串行通信更相关,从软件角度来看,我们看不到每个字节中位的顺序。
答案:
RGB555LE(如 RGB555LE_v1):
byte0 byte1
gggbbbbb 0rrrrrgg
(最左边的位是每个字节的高位)。
我们最好将数据视为一个
uint16
元素:b:
0000000000011111
(纯蓝色)g:
0000001111100000
(纯绿色)r:
0111110000000000
(纯红色)我们可以将其视为
uint16
:0rrrrggggggbbbbbb
We may use FFmpeg for testing the different pixel formats.
The conclusion are:
uint16
).Little endian: bytes order of
uint16
element is: [LSB, MSB].Bit endian: bytes order of
uint16
element is: [MSB, LSB].Executing FFmpeg CLI commands for testing:
Start with
rgb24
for example:Use some hex viewer like HxD for inspecting the raw file content.
red.raw FF 00 00 FF 00 00
...blue.raw 00 FF 00 00 FF 00
...green.raw 00 00 FF 00 00 FF
...rgba
pixel format:r:
FF 00 00 FF
g:
00 FF 00 FF
b:
00 00 FF FF
The FFmpeg convention the order of the bytes.
We can't say if the naming applies little or big endian.
The endianness is relevant when using
uint16
components (notuint8
components).rgba
pixel format:r:
FF 00 00 FF
g:
00 FF 00 FF
b:
00 00 FF FF
A
thenR
thenG
thenB
thenA
...We may refer
rgba
asRGBA32BE
, but it's too confusing...rgb555le
pixel format:r:
00 7C 00 7C
g:
E0 03 E0 03
b:
1F 00 1F 00
We may also check the lower bit (for bits ordering):
Set the color to 8 so after shifting the value be 1.
r:
01 00 01 00
2 bytes in bits:00000001 00000000
g:
20 00 20 00
2 bytes in bits:00100000 00000000
b:
00 04 00 04
2 bytes in bits:00000000 00000100
rgb555be pixel format:
r:
7C 00 7C 00
g:
03 E0 03 E0
b:
00 1F 00 1F
Checking the lower bit (for bits ordering):
r:
00 01 00 01
g:
00 20 00 20
b:
04 00 04 00
In big endian format, only the bytes are swapped.
(For every uint16 element (two bytes), order of the first and second byte is swapped).
Answers to questions:
10000=16
or00001=1 ?
Answer:
For rgb555le:
00000001 00000000
For rgb555be:
00000000 00000001
Answer:
In context of pixel format, there is no "bit endianness" there is only "byte endianness".
Bits endianness is more relevant to serial communication, from software perspective, we don't see the order of bits in each byte.
Answer:
RGB555LE (as RGB555LE_v1):
byte0 byte1
gggbbbbb 0rrrrrgg
(most left bit is the upper bit in each byte).
We better look at the data as one
uint16
element:b:
0000000000011111
(pure blue)g:
0000001111100000
(pure green)r:
0111110000000000
(pure red)We may look at it as
uint16
as:0rrrrrgggggbbbbb
我认为字节序对
rgb555
并不重要,这就是为什么您的链接会聚集rgb555
、rgb555le
和rgb555be
一起。就此而言,您的 rgba 示例也不是字节序敏感的,因为它的组件都是 <= 8 位。至于
rgb555
如何用2个字节(好吧,15位)表示,您可以在FFmpeg存储库中搜索rgb555
并查看编码器/解码器如何处理这种像素格式。这是我发现的rpzaenc.c
第138行:编码器采用
rgb555
,一个 16 位无符号整数,使用put_bits()
实用函数将这 15 位推送到其比特流,如 第 683 行这是put_bits.h
I don't think endianness matters to
rgb555
, and that's why your link bunchesrgb555
,rgb555le
, andrgb555be
together. For that matter, your example withrgba
also isn't endian sensitive as its components are all <= 8 bits.As for how
rgb555
is represented in 2 bytes (well, 15 bits), you can search FFmpeg repo forrgb555
and see how encoders/decoders handle such pixel format. Here is one I foundrpzaenc.c
Line 138:the encoder takes
rgb555
, a 16-bit unsigned int, an usesput_bits()
utility function to push these 15 bits to its bitstream as shown on Line 683Here is the link to put_bits.h