5

I'm loading a DIBSection from a file with the following:

HBITMAP bmpIn = (HBITMAP) LoadImage(NULL, _T("c:\\Temp\\Temp.bmp"), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);

Empirically I've discovered the following differences between the loaded bitmap and the bitmaps that I've used in the past, but I can't find any documentation stating that there should be a difference.

  • The lines are ordered in memory top down rather than bottom up. I've verified that the .bmp file itself is ordered bottom up.
  • The row padding is to a multiple of 2 bytes rather than 4.

I've also discovered a documented difference when you use CreateDIBSection to create a DIBSection from scratch.

  • The DIBSECTION.dsHandle and BITMAP.bmBits values returned by GetObject will be NULL.

Where's the documentation for the first two differences, and am I missing anything? This is with Windows 7 but I can't imagine it would be different for other versions of Windows.

Edit: Some additional details. Here's a hex dump of temp.bmp; it's a 7x7 image with a white stripe down the right side and blue values incrementing along the left (0x10,0x20,etc.). You can see that the bottom line (00,00,70) is first and that there's 3 bytes of padding.

00: 42 4d de 00 00 00 00 00 00 00 36 00 00 00 28 00
10: 00 00 07 00 00 00 07 00 00 00 01 00 18 00 00 00
20: 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00
30: 00 00 00 00 00 00 70 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 60 00
50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
60: ff ff ff 00 00 00 50 00 00 00 00 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 40 00
80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: ff ff ff 00 00 00 30 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00 20 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0: ff ff ff 00 00 00 10 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 00 00 00 00 ff ff ff 00 00 00

Here's a sample program to read the .bmp file and write out the contents. I've removed error checking for brevity.

int _tmain(int argc, _TCHAR* argv[])
{
   HBITMAP bmpIn = (HBITMAP) LoadImage(NULL, argv[1], IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_LOADFROMFILE);
   FILE * out = _tfopen(argv[2], _T("wb"));
   DIBSECTION obj = {0};
   GetObject(bmpIn, sizeof(obj), &obj);
   cout << "dsBm.bmHeight = " << obj.dsBm.bmHeight << endl;
   cout << "dsBmih.biHeight = " << obj.dsBmih.biHeight << endl;
   cout << "sizeof(DIBSECTION) = " << sizeof(DIBSECTION) << endl;
   fwrite(&obj, sizeof(DIBSECTION), 1, out);
   int stride = (((obj.dsBmih.biWidth * obj.dsBmih.biBitCount) + 15) / 16) * 2;
   int bytecount = abs(obj.dsBmih.biHeight) * stride;
   vector<BYTE> bits(bytecount);
   GetBitmapBits(bmpIn, bytecount, &bits[0]);
   fwrite(&bits[0], 1, bytecount, out);
   fclose(out);
   return 0;
}

And here's the output from the above program along with a hex dump of the file produced:

dsBm.bmHeight = 7
dsBmih.biHeight = 7
sizeof(DIBSECTION) = 84
00: 00 00 00 00 07 00 00 00 07 00 00 00 18 00 00 00
10: 01 00 18 00 00 00 11 00 28 00 00 00 07 00 00 00
20: 07 00 00 00 01 00 18 00 00 00 00 00 a8 00 00 00
30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
50: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00
60: 00 00 00 00 00 00 ff ff ff 00 20 00 00 00 00 00
70: 00 00 00 00 00 00 00 00 00 00 00 00 ff ff ff 00
80: 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
90: 00 00 ff ff ff 00 40 00 00 00 00 00 00 00 00 00
a0: 00 00 00 00 00 00 00 00 ff ff ff 00 50 00 00 00
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff ff
c0: ff 00 60 00 00 00 00 00 00 00 00 00 00 00 00 00
d0: 00 00 00 00 ff ff ff 00 70 00 00 00 00 00 00 00
e0: 00 00 00 00 00 00 00 00 00 00 ff ff ff 00
Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • see [this link](http://msdn.microsoft.com/en-us/library/dd183382(v=vs.85).aspx) for some more info. – Nerdtron Dec 02 '11 at 05:50
  • @Nerdtron, that link directly contradicts my observations - it declares that a top-down DIB will have a negative height but in this case it does not. – Mark Ransom Dec 02 '11 at 06:04
  • so you're getting back a top-down DIB with a positive height? after you call LoadImage what are you doing with the HBITMAP to empirically discover this? I'm guessing there's some detail you're missing, not that the API is actually returning the wrong data. Just curious which APIs you're calling after loading. – Nerdtron Dec 02 '11 at 12:47
  • @Nerdtron, I used GetObject and GetBitmapBits and wrote the results straight back out to a file with my own code. I also examined the memory in the debugger to double-check. – Mark Ransom Dec 02 '11 at 14:28
  • 1
    The documentation for GetBitmapBits ([here](http://msdn.microsoft.com/en-us/library/dd144850(v=vs.85).aspx)) says that it, "copies the bitmap bits of a specified device-dependent bitmap into a buffer". Here, you've loaded up a device-independent-bitmap. So it could be there's a conversion going on because callers of GetBitmapBits are expecting something top-down. I'm just guessing because I've always called GetDIBits. Note that the documentation I linked to says you shouldn't be calling it anyway you should call GetDIBits. I bet if you called GetDIBits instead you'd get what you expect. – Nerdtron Dec 02 '11 at 15:46
  • @Nerdtron, GetDIBits is the one that does a conversion, from DDB to DIB. It requires a HDC for the conversion and in my case I don't have one - I'm reading from a file and writing back to a file, never once passing the result to GDI. – Mark Ransom Dec 02 '11 at 16:10
  • You're loading a DIB and calling GetObject to get the info about that DIB, but then you're calling an API which says it copies from a DDB. So its possible they're not going to match up. Comparing the info from GetObject for a DIB with what comes back from GetBitmapBits for a DIB might be an apples to oranges comparison. I'd suggest calling GetDIBits instead and see what happens. Since you loaded the bitmap as a DIB and have a handle to it, I'm guessing there's really not any conversion going on. You can probably just pass in the screen DC. – Nerdtron Dec 02 '11 at 18:29
  • give that a try - call GetDIBits passing in the screen DC and see what you get. I bet the bitmap info will be consistent with the ordering of the rows of pixels. – Nerdtron Dec 02 '11 at 18:30
  • @Nerdtron, you were correct that GetDIBits returns the proper ordering and padding, so thanks for that. Post it as an answer and I'll accept it. My own fault I guess for using a function clearly marked "This function is provided only for compatibility with 16-bit versions of Windows" - I suppose DIB sections didn't exist in 16-bit Windows. – Mark Ransom Dec 02 '11 at 22:18

1 Answers1

3

Call GetDIBits instead of GetBitmapBits. The docs for GetBitmapBits (here) indicate that this is returning data for a device-dependent bitmap, whereas you have a device-independent bitmap. They also indicate that this call shouldn't be used and is just there for 16-bit compatibility. So, using GetDIBits should do the trick.

Nerdtron
  • 1,486
  • 19
  • 32