I have a bitmap stored as a BGRA array of bytes. This is the code I've been using to paint the bitmap:
CDC *dispDC = new CDC();
dispDC->CreateCompatibleDC(pDC);
CBitmap *dispBMP = new CBitmap();
dispBMP->CreateCompatibleBitmap(pDC, sourceImage->GetWidth(), sourceImage->GetHeight());
dispDC->SelectObject(this->dispBMP);
The actual copying of the pixels in the translatedImage
array happens with this:
dispBMP->SetBitmapBits(sourceImage->GetArea() * 4, translatedImage);
Then after some more processing I call pDC->StretchBlt
with dispDC
as the source CDC. This works fine when logged in locally because the display is also set to 32bpp.
Once I log in with Remote Desktop, the display goes to 16bpp and the image is mangled. The culprit is SetBitmapBits
; i.e. for it to work, I have to properly fill translatedImage
with the 16bpp version of what I want to show. Rather than do this myself, I searched the documentation and found SetDIBits
which sounds like it does what I want:
The SetDIBits function sets the pixels in a compatible bitmap (DDB) using the color data found in the specified DIB.
In my case, the DIB is the 32bpp RGBA array, and the DDB is dispBMP
which I create with CreateCompatibleBitmap
.
So instead of my call to SetBitmapBits
, this is what I did:
BITMAPINFO info;
ZeroMemory(&info, sizeof(BITMAPINFO));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = sourceImage->GetArea()*4;
info.bmiHeader.biWidth = sourceImage->GetWidth();
info.bmiHeader.biHeight = sourceImage->GetHeight();
info.bmiHeader.biClrUsed = 0;
int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
0, sourceImage->GetHeight(), translatedImage,
&info, DIB_PAL_COLORS);
However, r
is always zero and, naturally, I get nothing but black in my window. What is wrong with the code?
According to the documentation for SetDIBits
:
The bitmap identified by the hbmp parameter must not be selected into a device context when the application calls this function.
In your example code you select it into device context after creating it, so presumably that's why SetDIBits
is failing.
Ross Ridge was correct in pointing out the code order mistake. However, this didn't solve the problem.
The problem was in the parameters I was passing. I am new to C++ and MFC and often forget all the "operators" which can act on types to automatically convert them.
Previously I had this:
int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
0, sourceImage->GetHeight(), translatedImage,
&info, DIB_PAL_COLORS);
The correct call is this:
int r = SetDIBits(*pDC, *dispBMP,
0, sourceImage->GetHeight(), translatedImage,
&info, DIB_PAL_COLORS);
(Note I pass dereferenced pointers in the first two parameters.) Everything else was correct, including the counter-intuitive DIB_PAL_COLORS
flag for a bitmap which has not palette.
After obviously missing some key points in the documentation I reread it and then found this which has sample code showing that I was simply passing the parameters incorrectly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With