Search code examples
c++windowscomatlwic

Windows Imaging Component - How to get an encoder from an HBITMAP?


I have an HBITMAP provided by a 3rd party library, and need to write it rescaled on disk as a JPEG.

I have never used WIC, so I've been following this tutorial: https://msdn.microsoft.com/en-us/library/windows/desktop/ff973956.aspx

I have created a WicBitmap from my HBITMAP.

In Listing 9 it becomes apparent that I need a decoder, but the only way to create it I have found is with IWICImagingFactory::CreateDecoderFromFilename. There is an Initialize method that receives a IStream, but I'm not sure of the correct way to use it.

Is this the correct way to save an HBITMAP to disk? If so, how can I get a decoder from my HBITMAP or WicBitmap?


Solution

  • IWICImagingFactory::CreateBitmapFromHBITMAP imports GDI bitmap into WIC as decoded bitmap for which you already need no decoder. That is, you are good to go with your encoding part and saving to disk.

    The code snippet below does gets it done in full: 800x600 bitmap from the top left desktop corner as HBITMAP and then saved into JPEG file.

    #include "stdafx.h"
    #include <wincodecsdk.h>
    #include <atlbase.h>
    
    #define __C ATLENSURE_SUCCEEDED
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        CoInitialize(NULL);
        {
            HBITMAP hBitmap;
            {
                HDC hDc = GetDC(NULL);
                hBitmap = CreateCompatibleBitmap(hDc, 800, 600);
                HDC hBitmapDc = CreateCompatibleDC(hDc);
                HGDIOBJ hPreviousBitmap = SelectObject(hBitmapDc, hBitmap);
                BitBlt(hBitmapDc, 0, 0, 800, 600, hDc, 0, 0, SRCCOPY);
                SelectObject(hBitmapDc, hPreviousBitmap);
                DeleteDC(hBitmapDc);
                ReleaseDC(NULL, hDc);
            }
            CComPtr<IWICImagingFactory> pFactory;
            __C(pFactory.CoCreateInstance(CLSID_WICImagingFactory));
            CComPtr<IWICBitmap> pBitmap;
            __C(pFactory->CreateBitmapFromHBITMAP(hBitmap, NULL, WICBitmapIgnoreAlpha, &pBitmap));
            CComPtr<IWICBitmapEncoder> pBitmapEncoder;
            __C(pFactory->CreateEncoder(GUID_ContainerFormatJpeg, NULL, &pBitmapEncoder));
            CComPtr<IWICStream> pFileStream;
            __C(pFactory->CreateStream(&pFileStream));
            __C(pFileStream->InitializeFromFilename(L"D:\\Output.jpg", GENERIC_WRITE));
            __C(pBitmapEncoder->Initialize(pFileStream, WICBitmapEncoderNoCache));
            CComPtr<IWICBitmapFrameEncode> pBitmapFrameEncode;
            CComPtr<IPropertyBag2> pPropertyBag;
            __C(pBitmapEncoder->CreateNewFrame(&pBitmapFrameEncode, &pPropertyBag));
            PROPBAG2 Property;
            ZeroMemory(&Property, sizeof Property);
            Property.pstrName = L"ImageQuality";
            CComVariant vQuality(0.85f);
            __C(pPropertyBag->Write(1, &Property, &vQuality));
            __C(pBitmapFrameEncode->Initialize(pPropertyBag));
            __C(pBitmapFrameEncode->WriteSource(pBitmap, NULL));
            __C(pBitmapFrameEncode->Commit());
            __C(pBitmapEncoder->Commit());
        }
        CoUninitialize();
        return 0;
    }