Win32 C / C ++ Чтение BMP ширины и высоты из байтового массива

0

Я прочитал BMP файл в массив байтов. Поэтому после изучения ответов на этот вопрос: массив байтов - int c++. Является ли этот способ безопасным и правильным получать ширину и высоту из заголовка информации BMP?

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

И какие проблемы может возникнуть при таком подходе?

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

Согласно файлу формата Википедии BMP, 0x12 является смещением ширины растрового изображения в пикселях, а 0x16 - смещением высоты растрового изображения в пикселях.

Оплаченный Я нашел это решение для загрузки растрового изображения из буфера памяти, но я хочу, чтобы код был простым, потому что мне нужна только ширина, высота и необработанные данные растрового изображения, и я не знаю, является ли этот ответ безопасным.

Благодарю!

  • 0
    Рассмотрите возможность использования стандартного определения BMP lyout (структура BITMAPINFOHEADER) из (если вы пишете для Windows в Visual Studio) wingdi.h: msdn.microsoft.com/en-us/library/windows/desktop/…
  • 0
    @DenisGladkiy Да, но я думаю, что мы вернемся к тому же: как мне заполнить эту структуру? Безопасно ли загружать это решение из буфера памяти ?
Показать ещё 1 комментарий
Теги:
winapi
bitmap

3 ответа

2
Лучший ответ

Оба подхода делают одно и то же, и обе имеют одну и ту же основную проблему: не будут работать, если хост-система имеет другой порядок байтов, чем использует файл BMP. Это всегда проблема с прямым доступом к значениям, превышающим один байт в двоичном формате.

Последний подход также имеет дополнительный недостаток возможного нарушения, если хост не может выполнять long доступ к результирующим адресам.

Короче говоря, оба "решения" плохи. Лучше извлекать значение по байтам и повторно указывать его:

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;
}

В приведенном выше примере используется smidgeon C99 для краткости, перенос его обратно на C89 тривиален.

Редактировать: вышеупомянутое работает над любой дугой, поскольку он больше не выполняет прямой доступ. Вместо этого он предполагает, что buffer содержит байты в формате little-endian, и я считаю, что формат BMP, основанный на x86, всегда используется. Таким образом, он будет работать даже на большой машине. Он также больше не может неправильно выровнять большие обращения к памяти, так как все обращения имеют размер байта, который должен работать.

0

Оба подхода могут быть правильными для Win32. Но в целом оба являются небезопасными. Первый вариант зависит от sizeof(long) == 4. Второй тоже полагается на это, но требует правильного выравнивания данных (что может быть проблемой, например, для ARM). Оба имеют общий характер, что они принимают определенную endianess и будут демонстрировать различное поведение, например, x86 и mips.

0

memcpy работает нормально, пока long 32-битное значение (вместо этого я использовал uint32_t). Приведение будет работать, если вы знаете, что архитектура, которая запускает код, всегда будет x86.

[Хорошие отзывы других о байтере].

Если вы заботитесь о байте, используйте что-то вроде:

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

и то же самое для длины. Это предполагает, что ваши значения bmp являются unsigned char.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню