1

I have a bitmap in raw RGBA values in the following code from a library I found on the net. "svgren.

auto img = svgren::render(*dom, width, height); //uses 96 dpi by default
//At this point the 'width' and 'height' variables were filled with
//the actual width and height of the rendered image.
//Returned 'img' is a std::vector<std::uint32_t> holding array of RGBA values.

I need to know how to get this picture into a CBitmap so I can display it in an MFC Picture control. I can presize it and I know how to display a bitmap in the control. What I can't do is load the RGBA values into the bitmap. Any ideas please?

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • Use createBitmap directly: – Michael Dutton Sep 14 '16 at 12:58
  • CBitmap Chb; HBITMAP bmp = CreateBitmap(width, height, 1, 32, &*img.begin()); ASSERT_ALWAYS(bmp != NULL) Chb.Attach(bmp); //PicControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE); //PicControl.SetBitmap(Chb); mProjectorWindow.m_picControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE); mProjectorWindow.m_picControl.SetBitmap(Chb); – Michael Dutton Sep 14 '16 at 12:59
  • Related - https://stackoverflow.com/questions/4993518/arraybyte-to-hbitmap-or-cbitmap – sashoalm Sep 15 '16 at 06:21

2 Answers2

2

The CBitmap::CreateBitmap member function can construct a bitmap from a block of memory. The lpBits argument expects a pointer to byte values. Passing a pointer to an array of uint32_t values is technically undefined behavior (although it will work on all little-endian implementations of Windows).

Special care must be taken for the memory layout. This is only documented for the Windows API call CreateBitmap and not at all present in the MFC documentation:

Each scan line in the rectangle must be word1 aligned (scan lines that are not word aligned must be padded with zeros).

Based on the assumption, that the memory is properly aligned, and reinterpreting the buffer as a pointer to bytes is well defined, here's an implementation with proper resource handling:

CBitmap Chb;
Chb.CreateBitmap(width, height, 1, 32, img.data());
mProjectorWindow.m_picControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE);
Chb.Attach(mProjectorWindow.m_picControl.SetBitmap(Chb.Detach()));

The last line of code exchanges ownership of the GDI resource between the m_picControl and Chb. This ensures proper cleanup of the GDI resource previously owned by the m_picControl, and makes the m_picControl the only owner of the newly created bitmap.


1 I believe this should read dword aligned.
IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Chm gets the bitmap from CreateBitmap. But then there appears to be no connection between that and SetBitmap? I presume Chm is a member variable CBitmap? Or is it a mis-spelling for Chb? – Michael Dutton Sep 22 '16 at 00:12
1
CBitmap Chb;
HBITMAP bmp = CreateBitmap(width, height, 1, 32, &*img.begin());
ASSERT_ALWAYS(bmp != NULL)
Chb.Attach(bmp);
//PicControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE);
//PicControl.SetBitmap(Chb);
mProjectorWindow.m_picControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE);
mProjectorWindow.m_picControl.SetBitmap(Chb);
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • You should be able to use `img.data()` instead of `&*img.begin()` (assuming that's `std::vector`) – Barmak Shemirani Sep 15 '16 at 03:59
  • As was established in your [related question](http://stackoverflow.com/q/39596419/1889329), this solution sports both a GDI resource leak and a dangling pointer. – IInspectable Sep 21 '16 at 13:48