GetObject 和 GetBitmapBits 获取位图数据的区别

表面上看GetBitmapBits(...) 和 GetObject(...)都可以获取位图句柄中的数据,例如:

第一种方法:

     HBITMAP hbitmap = (HBITMAP)LoadImage(g_hInstance, MAKEINTRESOURCE(32710), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);

     GetObject(hbitmap, sizeof(BITMAP), &bitmap); 

第二种方法:

     bitmap.bmWidth = 23;
     bitmap.bmHeight = 23;
     bitmap.bmBitsPixel = 32;
     bitmap.bmWidthBytes = (bitmap.bmWidth * bitmap.bmBitsPixel / 8 + 3) / 4 * 4;; // 按照微软的说法,待存储图像数据每行字节数为4的倍数

     hdc = CreateCompatibleDC(hdc);
     hbitmap= CreateCompatibleBitmap(hdc, bitmap.bmWidth, bitmap.bmHeight); // 创建与设备描述表兼容的位图
     GetObject(hdc, sizeof(BITMAP), &bitmap);

    int size = bitmap.bmWidth * bitmap.bmWidthBytes;
    unsigned char * pBits = (unsigned char *)malloc(size);  //在堆上申请
    int nBytes = GetBitmapBits(hbitmap, size, pBits);

----------------------------------------------------------------------

通过比较上面两种方法,发现:

1. 第一种方法,使用起来很简单,而且API已经将数据按照4的倍数对齐,并且保存到bitmap中了,不用我们去处理这些细节,

   这种方法适用于位图数据已知的情况下调用。

2. 第二种方法,适用于双缓冲画图的情况下,获取DC的位图内存数据指针,然后直接用两个for循环遍历操作每一个像素。

3. 如果不小心将这两种方法混合使用了,那么悲剧就会不定期上演,产生悲剧的关键原因在于bitmap.bmWidthBytes这个变量

   的计算方法,对于4个通道的位图,两种方法都会正常的默契工作。但对于一般的使用LoadImage加载的位图,是3个通道的

  位图,GetObject得出的结果是安装标准方法,向上取4的倍数对齐一行像素的,而GetBitmapBits得出的结果就比较悲催了,

  至少在win7下面是这样的,比如,上面的例子中,我申请一张23x23的内存位图,安装标准计算方法,可得:

       bitmap.bmWidthBytes = (23 * 24 / 8 + 3)/ 4 * 4 = 72 个像素每行

 但实际上 int nBytes = GetBitmapBits(hbitmap, size, pBits);的返回值 nBytes = 1610 =23 * 70;即GetBitmapBits计算的结果是

 70个像素每行,与标准计算方法得出的72个像素每行,截然不同,够坑爹吧,这几天被微软挖的这个坑坑惨了。

4. bitmap.bmBits的第一个字节对应实际图片中的左下角,这一点也很坑爹,而GetBitmapBits(hbitmap, size, pBits);得到的

     pBits恰恰相反,第一个字节对应图片的左上角。看到了吧,老美就喜欢玩双重标准。

5. 使用CreateCompatibleBitmap(...)创建的位图,貌似默认是4个通道的,也即hdc都是4个通道的。

6. 最后一点,也是最重要的:MSDN上对GetBitmapBits(...)的特别说明是
   Note  This function is provided only for compatibility with 16-bit versions of Windows. Applications should use theGetDIBits function. 

   意思就是说GetBitmapBits只提供给16位版本的窗口。其他情况下,应该用GetDIBBits(...)


你可能感兴趣的:(GetObject 和 GetBitmapBits 获取位图数据的区别)