一种读取24位bitmap资源的全部像素数据(加透明通道)的方法。


相关知识

BMP文件的数据按照从文件头开始的先后顺序分为四个部分:
◆ 位图文件头(bmp file header): 提供文件的格式、大小等信息
◆ 位图信息头(bitmap information):提供图像数据的尺寸、位平面数、压缩方式、颜色索引等信息
◆ 调色板(color palette):可选,如使用索引来表示图像,调色板就是索引与其对应的颜色的映射表
◆ 位图数据(bitmap data):图像数据区
24位和32位不需要调色板。

提取像素原理

24位,除去位图信息头后的剩余部分就是所需的像素信息。需注意的是,它的像素数据按照BGR排列,且数据从位图左下方开始,从左到右,从下到上存储。并且24位位图是没有透明通道的。

但我需要将其转换为RGB排列,且从上到下读取数据。另外我需要能显示透明色,也就是说,将24位位图转换为32位位图,即读取数据时增加一个透明通道(设置为0则透明)。

代码

以下是我写的实现该功能的粗糙代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
BYTE* GetImageData(CBitmap* cBitmap)
{
BITMAP bmp;
cBitmap->GetBitmap(&bmp);
HBITMAP hbm = (HBITMAP)*cBitmap;

HDC hDC = ::GetDC(NULL);

LONG width = bmp.bmWidth * 4;
LONG height = bmp.bmHeight;

//定义位图信息
BITMAPINFO bi;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = bmp.bmWidth;
bi.bmiHeader.biHeight = bmp.bmHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 32;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biSizeImage = width * height;
bi.bmiHeader.biClrUsed = 0;
bi.bmiHeader.biImportant = 0;

//获取位图数据
BYTE* lpvBits = new BYTE[width * height];
::ZeroMemory(lpvBits, width * height);
::GetDC(NULL);
::GetDIBits(hDC, hbm, 0, height, lpvBits, &bi, DIB_RGB_COLORS);

BYTE buffer = 0;
BYTE* pData=new BYTE[width * height];
int temp = 0;
for(int i= height - 1;i >= 0; --i)
{
for(int j=0;j < width; ++j)
{
if(j % 4 == 0)
{
BYTE tempBR = 0;
tempBR = lpvBits[width * i + j];//b赋给temp
lpvBits[width * i + j] = lpvBits[width * i + j + 2];//r赋给b
lpvBits[width * i + j + 2] = tempBR;//temp赋给r
}
if(j % 4 == 3)//透明通道
{
if(lpvBits[width * i + j - 3] == 255 && lpvBits[width * i + j - 2] == 255 && lpvBits[width * i + j - 1] == 255)
{
lpvBits[width * i + j] == 0;
}
else
{
lpvBits[width * i + j] == 255;
}
}
buffer = lpvBits[width * i + j];
memcpy(&pData[temp++], &buffer, 1);
}
}

if(lpvBits != 0)
{
delete lpvBits;
lpvBits = 0;
}

::ReleaseDC(NULL, hDC);

DeleteObject(cBitmap);

return pData;
}