二进制文件位操作

binary file bit manipuation

本文关键字:位操作 二进制文件      更新时间:2023-10-16

我有一个图像数据的二进制文件,其中每个像素正好是4位。图像数据布局如下:

有N个图像,其中第一个图像是1x1,第二个图像是2x2,第三个图像是4x4,依此类推(如果你想知道的话,它们是mipmap)。

给定一个指向数据缓冲区开始的指针,我想跳到最大的图像。

现在我知道我想跳过多少字节,但在开始时有一个烦人的1x1图像,它是4位。无论如何,我都不知道要逐位递增指针。

如何在所有数据都不偏离4位的情况下成功检索数据?

假设您可以更改文件格式,则可以执行以下操作之一:

  • 为1x1图像添加填充
  • 以相反的顺序存储图像(实际上与上面相同,但对于mip贴图来说并不理想,因为你不一定知道你会有多少图像)

如果你不能改变你的格式,你可以选择:

  • 转换数据
  • 接受缓冲区偏移了半个字节,并相应地使用它

你说:

如何在不关闭所有内容的情况下成功检索数据4位?

所以这意味着你需要转换。当您以字节为单位计算偏移量时,您会发现第一个偏移量包含前一个图像的半个字节。所以在紧要关头,你可以这样洗牌:

for( i = start; i < end; i++ ) {
    p[i] = (p[i] << 4) | (p[i+1] >> 4);
}

这是假设第一个像素是4-7位,第二个像素是0-3位,依此类推……如果相反,只需反转这两个移位。

// this assumes pixels points to bytes(unsigned chars)
index = ?;// your index to the pixel
byte_t b = pixels[index / 2];
if (index % 2) pixel = b >> 4;
else pixel = b & 15; 
// Or you can use
byte_t b = pixels[index >> 1];
if (index & 1) pixel = b >> 4;
else pixel = b & 15; 

无论哪种方式,都只需计算文件的逻辑索引。除以2,你就可以到达像素所在的字节的开头。然后只读取正确的半个字节。

所以做一个函数

byte_t GetMyPixel(unsigned char* pixels, unsigned index) {
  byte_t b = pixels[index >> 1];
  byte_t pixel;
  if (index & 1) pixel = b >> 4;
  else pixel = b & 15; 
  return pixel; 
} 

读取第一个图像。

Image1x1 = GetMyPixel(pixels,0);

Image2x2_1 = GetMyPixel(pixels,1);// Top left pixel of second image
Image2x2_2 = GetMyPixel(pixels,2);// Top Right pixel of second image
Image2x2_3 = GetMyPixel(pixels,3);// Bottom left pixel of second image
... etc

所以这是一种方法。你可能需要考虑到你正在使用的端序,所以如果它看起来不对,那么就切换像素读取的逻辑。。。

byte_t GetMyPixel(unsigned char* pixels, unsigned index) {
  byte_t b = pixels[index >> 1];
  byte_t pixel;
  #if OTHER_ENDIAN
  if (index & 1) pixel = b >> 4;
  else pixel = b & 15; 
  #else
  if (index & 1) pixel = b & 15;
  else pixel = b >> 4; 
  #endif
  return pixel; 
}