Click here to Skip to main content
15,742,323 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm converting a custom MFC control from GDI+ to Direct2D. The control sits on a dialog which has a bitmap background. I need to capture the portion of the dialog background which sits under the control so that I can render the background in the control's OnPaint() function. Is there a way to capture the dialog background to a bitmap in Direct2D?

In GDI+ this is pretty straight forward. You just create a dc compatible with the dialog dc. Create a compatible bitmap, load it into the dc and then BitBlt the dialog dc into the compatible dc. The bitmap can then be drawn using GDI+.

I've tried doing something similar in Direct2D but it's not working. I created a ID2D1DCRenderTarget object and then bound the object to the dialog dc. I then called ID2D1DCRenderTarget::CreateCompatibleRenderTarget() which creates a ID2D1BitmapRenderTarget object. I can then call GetBitmap() on the object but it doesn't seem to return a valid bitmap that I can render onto the custom control?
Posted

1 solution

Ok, finally got this working. For anyone else who is interested, here are the steps required to capture the image from a device context and render it into a Direct2D render target. In my case I wanted to capture the image from an MFC CDialogEx dialog window that had a bitmap background.

The first steps require the use of GDI to copy a bitmap from the dialog device context to a memory device context. This can be done using CreateCompatibleDC(), CreateCompatibleBitmap() and BitBlt(). I stored the resulting bitmap in an MFC CBitmap object.

The trick now is to get the bitmap into a ID2D1Bitmap object so that we can render it to the render target. This is achieved using the Windows Imaging Component (WIC).

First, call IWICImagingFactory::CreateBitmapFromHBITMAP(), passing in the CBitmap we created earlier. This will create an IWICBitmap object. The IWICBitmap object now needs to be converted to a 32bppPBGRA pixel format. This is done using a IWICFormatConverter object. Call IWICFormatConverter::Initialize() specifying the IWICBitmap object created previously.

Finally, call ID2D1RenderTarget::CreateBitmapFromWicBitmap(), passing in the IWICFormatConverter object created above. This will create an ID2D1Bitmap object that can now be drawn in the render target.

A snippet of code is shown below:


CClientDC dcParent(GetParent());
CRect rectClient;
CRect rectWindow;
CDC dcBackground;
CBitmap *pOldBitmap = NULL;
CBitmap DialogBitmap;
HRESULT hr = E_FAIL;
CComPtr<IWICBitmap> pDialogBitmap = NULL;

m_pParentBitmap.Release();
GetWindowRect(rectWindow);
GetParent()->ScreenToClient(rectWindow);
GetClientRect(rectClient);

dcBackground.CreateCompatibleDC(&dcParent);
DialogBitmap.CreateCompatibleBitmap(&dcParent, rectClient.Width(), rectClient.Height());
pOldBitmap = dcBackground.SelectObject(&DialogBitmap);

dcBackground.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), &dcParent, rectWindow.left, rectWindow.top, SRCCOPY);
dcBackground.SelectObject(pOldBitmap);

// Note that the WICBitmapAlphaChannelOption is very important. If we don't set it to a value that is compatible
// with the render target where we intend to draw the bitmap then a black bitmap will be drawn.
hr = theApp.g_pWICFactory->CreateBitmapFromHBITMAP(DialogBitmap, NULL, WICBitmapIgnoreAlpha/*WICBitmapUsePremultipliedAlpha*/, &pDialogBitmap);
if (SUCCEEDED(hr))
{
    // Convert the dialog bitmap to a 32bppPBGRA pixel format. Before Direct2D can use an image, it must be converted
    // to the 32bppPBGRA pixel format. To convert the image format, use the CreateFormatConverter method to create
    // an IWICFormatConverter object. Once created, use the Initialize method to perform the conversion.
    CComPtr<IWICFormatConverter> pFormatConverter = NULL;
    hr = pWICFactory->CreateFormatConverter(&pFormatConverter);
    if (SUCCEEDED(hr))
    {
        // dither, pIPalette, alphaThresholdPercent, and paletteTranslate are used to mitigate color loss when converting
        // to a reduced bit-depth format. We do not need to do this so we use the following parameters:
        // dither set to WICBitmapDitherTypeNone,
        // pIPalette set to NULL,
        // alphaThresholdPercent set to 0.0f,
        // and paletteTranslate set to WICBitmapPaletteTypeCustom
        hr = pFormatConverter->Initialize(pDialogBitmap,                    // Input bitmap to convert
                                          GUID_WICPixelFormat32bppPBGRA,    // Destination pixel format
                                          WICBitmapDitherTypeNone,          // Specified dither pattern
                                          NULL,                             // Specify a particular palette
                                          0.0f,                             // Alpha threshold
                                          WICBitmapPaletteTypeCustom);      // Palette translation type.
        if (SUCCEEDED(hr))
        {
            hr = pRenderTarget->CreateBitmapFromWicBitmap(pFormatConverter, NULL, &m_pParentBitmap);
            m_bParentBackgroundCaptured = true;
        }
    }
}
 
Share this answer
 
Comments
Super Garrison 1-May-20 11:48am    
What is pRenderTarget?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900