当前位置: 动力学知识库 > 问答 > 编程问答 >

Win32 C/C++ Reading BMP width and height from a byte array

问题描述:

I have read a BMP file into a byte array. So after looking into the answers of this question: byte array to int c++. Is this way of obtaining the widht and height from a BMP information header safe and correct?

long width, height;

memcpy(&width, &bmp[0x12], sizeof(long));

memcpy(&height, &bmp[0x16], sizeof(long));

And what problems could this approach bring?

long* width = (long*)(&bmp[0x12]);

long* height= (long*)(&bmp[0x16]);

According to Wikipedia BMP file format, 0x12 is the offset of the bitmap width in pixels, and 0x16 the offset of the bitmap height in pixels.

PD. I have found this solution for loading the bitmap from memory buffer but I want to keep the code simple because I only need the width, the height and the raw data of the bitmap, and I do not know if that answer is safe either.

Thanks!

网友答案:

Both approaches do essentially the same thing, and both have the same fundamental problem: won't work if the host system has a different byte-order than the BMP file uses. This is always the problem with directly accessing values larger than a single byte in binary format.

The latter approach also has the additional disadvantage of possibly breaking if the host cannot do a long access at the resulting addresses.

In short, both "solutions" are bad. It's better to extract the value byte-by-byte and re-consititute it:

static uint32_t read_uint32_t(const uint8_t *buffer, size_t offset)
{
  buffer += offset;
  const uint32_t b0 = *buffer++;
  const uint32_t b1 = *buffer++;
  const uint32_t b2 = *buffer++;
  const uint32_t b3 = *buffer++;
  return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
}

The above uses a smidgeon of C99 for brevity, porting it back to C89 is trivial.

Edit: the above works on any arcihtecture, since it's no longer doing direct accesses. Instead it assumes buffer contains bytes in little-endian format, which I believe is what the x86-originated BMP format always uses. So, it will work even on a big-endian machine. It also no longer does possibly mis-aligned large memory accesses, since all accesses are just byte-sized which should work.

网友答案:

The memcpy works OK as long as long is a 32-bit value (I'd personally use uint32_t instead). The cast will work if you know the architecture that runs the code is always going to be x86.

[Good points by others about byteorder].

If you care about byteorder, then use something like:

uint32_t width = bmp[0x12] + (bmp[0x13] << 8) + (bmp[0x14] << 16) + (bmp[0x15] << 24);

and the same for length. This assumes your bmp values are unsigned char.

网友答案:

Both approaches might be correct for Win32. But generally both are unsafe. The first variant relies on sizeof(long) == 4. Second relies on this too but requires correct alignment of data (which might be problem e.g. on ARM). Both have on common that they assume a certain endianess and will show different behavior on e.g. x86 and mips.

分享给朋友:
您可能感兴趣的文章:
随机阅读: