HBITMAP对位图数据存储的字节对齐

HBITMAP在GDI中用于存储位图数据,通过GetDIBits获取位图信息。尽管位图的内存大小可以按公式计算,但实际的bmpInfo.bmiHeader.biSizeImage可能不同,尤其是16位颜色深度且宽度为奇数的位图,会自动对齐到4字节边界。这可能是为了提高以DWORD单位进行像素操作的效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

HBITMAP是常用的GDI对象,而GetDIBits可以从一个HBITMAP对象中获得其对应的位数据。
其原型如下:
int GetDIBits(    HDC hdc , // handle to DC
hdc, // handle to DC
                            HBITMAP hbmp, // handle to bitmap
                            UINT
hbmp, // handle to bitmap
                            UINT
uStartScan, // first scan line to set
                            UINT
cScanLines, // number of scan lines to copy
                            LPVOID cScanLines, // number of scan lines to copy
                            LPVOID lpvBits, // array for bitmap bits
                            LPBITMAPINFO
lpbi, // bitmap data buffer
                            UINT lpbi, // bitmap data buffer
                            UINT uUsage // RGB or palette index );

标准的GetDIBits调用方式是两次调用:
第一次传入空的 lpvBits,此时的lpbi作为传出参数,从中可以获得lpvBits所需的内存区域大小。
    BYTE *lpvBits = NULL;
    BITMAPINFO bmpInfo = {0};
    bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);

    /*    第一次调用GetDIBits获得bmpInfo    */
    nRet = ::GetDIBits(hDC, hBitmap, 0, pBmpData->bmHeight, NULL, &bmpInfo, DIB_RGB_COLORS);
    if (nRet == 0) {
        nRet = GetLastError();
        TRACE( _T("GetDIBits for bmpInfo failed %d/n"), nRet);
        goto err;
    }

以上调用如果成功,就会在bmpInfo.bmiHeader.biSizeImage记录位数据所占的内存区大小,
此时就可以动态分配内存,然后再次调用GetDIBits获得实际的位数据:

    lpvBits= new BYTE[bmpInfo.bmiHeader.biSizeImage];
    if (NULL == pBitsBuffer) {
        nRet = -1;
        TRACE( _T("Allocate memory for lpvBits failed/n"));
        goto err;
    }

    /*    第二次调用GetDIBits获得位图数据    */
    nRet = ::GetDIBits(hDC, hBitmap, 0, pBmpData->bmHeight, lpvBits, &bmpInfo, DIB_RGB_COLORS);
    if (nRet == 0) {
        nRet = GetLastError();
        TRACE( _T("GetDIBits for lpvBits failed %d/n"), nRet);
        goto err;
    }

很多时候,因为位图的长宽和颜色深度都是已知的,因此位数据所占的内存区大小可以由公式
 width * heigth * pixelBits / 8 计算获得

那是否可以省略第一步调用呢?
答案是:最好不要

原因是 bmpInfo.bmiHeader.biSizeImage 并不一定等于 width * heigth * pixelBits / 8

经过多次测试发现,对于16位颜色深度的位图,如果其宽度为奇数,则第一次GetDIBits获得
的位数据大小为 (width+1) * heigth * pixelBits / 8

也就是说对于16位颜色深度的位图,HBITMAP对象对其进行存储时,自动将宽度调整为了偶
数,也即将每行数据对齐到4字节(一个DWORD的长度)。

暂时没有查到相关的解释,我的猜想是这是为了在进行像素操作时能直接以DWORD为单位,
这样比以WORD为单位能减少一半的操作次数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值