Search code examples
c++svgmfcdirectxdirect2d

convert svg files to Bitmap using Direct2D in MFC


I want to convert svg files to Bitmap.I read that Direct2D support loading and using svg files. How to use it in MFC?

I tried code from Direct2D SVG image rendering sample. But could not render/draw on MFC window.

I want to use converted Bitmaps for various MFC Control widgets.


Solution

  • Here is a console app sample that uses Direct2D to create an MFC CBitmap from an SVG file with support for transparency. Since the CBitmap is GDI/HDC based, I've used the ID2D1DCRenderTarget interface .

    Note: error checkings are not done, I just return the HRESULT values:

    #define _AFXDLL // depends on your compilation options
    #include <WinSock2.h> // MFC...
    #include <windows.h>
    #include <afxwin.h> // CBitmap
    #include <atlbase.h>
    #include <atlcom.h> // CComPtr
    #include <d2d1.h>
    #include <d2d1_3.h> // ID2D1DeviceContext5
    
    #pragma comment(lib, "d2d1")
    
    void BuildSvgAsCBitmap(int width, int height)
    {
        // initialize Direct2D
        D2D1_FACTORY_OPTIONS options = { D2D1_DEBUG_LEVEL_INFORMATION }; // remove this in release
        CComPtr<ID2D1Factory> factory;
        auto hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, IID_ID2D1Factory, &options, (void**)&factory);
    
        // create an in-memory bitmap
        BITMAPINFO bitmapInfo = {};
        bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo.bmiHeader);
        bitmapInfo.bmiHeader.biWidth = width;
        bitmapInfo.bmiHeader.biHeight = height;
        bitmapInfo.bmiHeader.biPlanes = 1;
        bitmapInfo.bmiHeader.biBitCount = 32;
        bitmapInfo.bmiHeader.biCompression = BI_RGB;
    
        CBitmap bitmap;
        void* bits = 0;
        bitmap.Attach(CreateDIBSection(nullptr, &bitmapInfo, DIB_RGB_COLORS, &bits, nullptr, 0));
    
        // create a DC render target
        CComPtr<ID2D1DCRenderTarget> target;
        D2D1_RENDER_TARGET_PROPERTIES props = {};
        props.pixelFormat.format = DXGI_FORMAT_B8G8R8A8_UNORM;
        props.pixelFormat.alphaMode = D2D1_ALPHA_MODE_PREMULTIPLIED;
        hr = factory->CreateDCRenderTarget(&props, &target);
    
        // create a DC, select bitmap and bind DC
        CDC cdc;
        cdc.CreateCompatibleDC(nullptr);
        auto old = cdc.SelectObject(bitmap);
        RECT rc = { 0, 0, width, height };
        hr = target->BindDC(cdc.GetSafeHdc(), &rc);
    
        // this requires Windows 10 1703
        CComPtr<ID2D1DeviceContext5> dc;
        hr = target->QueryInterface(&dc);
    
        // open a stream from the .SVG file
        CComPtr<IStream> svgStream;
        hr = SHCreateStreamOnFileW(L"c:\\mypath\\myfile.svg", 0, &svgStream);
    
        // open the SVG as a document
        CComPtr<ID2D1SvgDocument> svg;
        D2D1_SIZE_F size = { (float)width, (float)height };
        hr = dc->CreateSvgDocument(svgStream, size, &svg);
    
        // draw it on the render target
        target->BeginDraw();
        dc->DrawSvgDocument(svg);
        hr = target->EndDraw();
    
        // TODO
        // do something with the CBitmap
        // TODO
    
        // cleanup, etc.
        cdc.SelectObject(old);
    }
    
    int main()
    {
        BuildSvgAsCBitmap(200, 200);
        return 0;
    }
    

    There's a more complete sample here https://gist.github.com/smourier/5b770d32043121d477a8079ef6be0995 that also demonstrates how to save the svg as a png with transparency using WIC.