0x42, 0x4D
Первые 2 байта - B
и M
, это всего лишь заголовок файла растрового изображения, который в сумме составляет 54 байта.Это не часть первой строки.
Размер 0x7B
x 0x5A
пикселей
К концу у вас есть 0x18 0x00
, что составляет 24, для 24-битного растрового изображения, а не16-битный
Таким образом, вам нужно пропустить 54 байта и прочитать как 24-битный
int width_in_bytes = ((width * 24 + 31) / 32) * 4 * height;
for(int row = height - 1; row >= 0; row--)
{
for(int col = 0; col < width; col++)
{
int i = row * width_in_bytes + col * 3;
unsigned char blu = bitmap[54 + i + 0];
unsigned char grn = bitmap[54 + i + 1];
unsigned char red = bitmap[54 + i + 2];
int pixel = red | ((uint16_t)grn << 8) | ((uint32_t)blu << 16);
SetPixel(row, col, pixel);
}
}
Если устройство ожидает 16-битное битовое изображение, попробуйте получить 16-битное битовое изображениена первом месте.Например, при съемке экрана Windows допускает 16-битный формат.
SDL также поддерживает SDL_PIXELFORMAT_RGB565
.GDI + - это еще один вариант, если вы кодируете в Windows.
Если исходное растровое изображение является 24-разрядным, и вы хотите преобразовать его в 16-разрядный формат 565, напишите формулу на основе MCVE ниже
*24-битное растровое изображение 1026 * имеет диапазон цветов от 0 до 255, тогда как 16-битное изображение имеет диапазон цветов от 0 до 31 (0-63 для зеленого в случае формата 565).Вы должны нормализовать цвет, например, умножив значение красного на 31/255.Затем сдвиньте значения в 16-разрядное целое число.
16-разрядный формат растрового изображения предполагает 3 цвета (всего 12 байтов) до начала пикселей.Эти цвета содержат информацию о формате 565.
#include <Windows.h>
#include <stdint.h>
#include <iostream>
#include <fstream>
#include <vector>
int main()
{
HBITMAP hbitmap = (HBITMAP)LoadImage(NULL, "24bit.bmp",
IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if(!hbitmap)
return 0;
BITMAP bm;
GetObject(hbitmap, sizeof(bm), &bm);
if(bm.bmBitsPixel != 24)
{
DeleteObject(hbitmap);
std::cout << "Expecting 24-bit bitmap\n";
return 0;
}
BYTE *source = (BYTE*)bm.bmBits;
int w = bm.bmWidth;
int h = bm.bmHeight;
//calculate width in bytes (wb) for source and destination
DWORD wb_src = ((w * 24 + 31) / 32) * 4;
DWORD wb_dst = ((w * 16 + 31) / 32) * 4;
int size = wb_dst * h;
std::vector<BYTE> dest(size);
for(int r = 0; r < h; r++)
{
for(int c = 0; c < w; c++)
{
int src = r * wb_src + c * 3;
int dst = r * wb_dst + c * 2;
uint16_t blu = (uint16_t)(source[src + 0] * 31.f / 255.f);
uint16_t grn = (uint16_t)(source[src + 1] * 63.f / 255.f);
uint16_t red = (uint16_t)(source[src + 2] * 31.f / 255.f);
uint16_t res = (red) | (grn << 5) | (blu << 11);
memcpy(&dest[dst], &res, 2);
}
}
//prepare header files for 16-bit file
BITMAPINFOHEADER bi = { sizeof(bi), w, h, 1, 16, BI_BITFIELDS };
BITMAPFILEHEADER bf = { (WORD)'MB', 54 + 12 + wb_dst * h, 0, 0, 54 };
std::ofstream of("16bit.bmp", std::ios::binary);
if(of)
{
//add file header
of.write((char*)&bf, sizeof(bf));
of.write((char*)&bi, sizeof(bi));
//color table
COLORREF c1 = 31;
COLORREF c2 = 63 << 5;
COLORREF c3 = 31 << 11;
of.write((char*)&c1, 4);
of.write((char*)&c2, 4);
of.write((char*)&c3, 4);
//add pixels
of.write((char*)&dest[0], dest.size());
}
DeleteObject(hbitmap);
return 0;
}