Send comments on this topic. | Back to Introduction - All Topics | Help Version 17.0.8.10
WIC-Enabled Codecs C++ Tutorial: Saving an Image File
See Also

This tutorial shows how to use the Windows Imaging Component (WIC) to save image files. After completing the tutorial, register any or all of the LEAD WIC-Enabled Codecs. You will then be able to save any of these image formats without recompiling the demo.

Start with the tutorial that you created in WIC-Enabled Codecs C++ Tutorial: Loading an Image File

First, you will create a Save dialog by hooking into the standard Windows Save Common Dialog.

  1. In Solution Explorer, double-click on Tutorial.rc to display the Resource View.
  2. Right-click the Dialog tree view item and choose Insert Dialog from the menu.
  3. Open the Dialog tree view item. Select the IDD_DIALOG1 item in the tree view. In the properties, change the ID to IDD_DIALOG_SAVE_TEMPLATE

  4. Double-click Combo Box from the toolbox to add a combo box to the dialog. Change the ID to IDC_COMBO_PIXEL_FORMAT

  5. Add a static text item with ID IDC_STATIC_PIXEL_FORMAT

  6. Close the Resource View, right-click Tutorial.rc and select View Code.
  7. Search for IDD_DIALOG_SAVE_TEMPLATE in  Tutorial.rc to find the dialog that you just created.  Replace it with the following:

        IDD_DIALOG_SAVE_TEMPLATE DIALOGEX 0, 0, 423, 77
        STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_SYSMENU
        FONT 8, "MS Shell Dlg", 400, 0, 0x1
        BEGIN
            LTEXT           "&Pixel Format:",IDC_STATIC,67,2,53,8
            COMBOBOX        IDC_COMBO_PIXEL_FORMAT,130,0,147,213,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
        END
        

  8. Open stdafx.h and add the following headers under the C RunTime Header Files section. The reason for adding each header is shown as a comment to the left.
      
        #include <vector>  // To maintain a dynamic array with information about each encoder
        #include <dlgs.h>  // Contains constants for accessing Save Dialog items
        
  9. Also add the following to the end of stdafx.h.
        #include "resource.h"
        

  10. In Solution Explorer, right-click the Source Files tree view item. Choose Add->New Item. Choose C++(.cpp) file. For the name, enter SaveDlg.cpp

Next, customize the standard Windows Common Save dialog. The Save as type static text box will programmatically be changed to display Encoders. In this combo box, all the available WIC-Enabled Encoders on your system will be displayed. Also, a Pixel Format combo box is added. This will display the available pixel formats for the selected encoder.

  1. Add the following code to SaveDlg.cpp:

        // SaveDlg.cpp
    
    #include "stdafx.h"
    extern HINSTANCE hInst;
    extern IWICBitmapSource  *gpiBitmapSource;
    
    IWICImagingFactory *gpiImagingFactory = NULL;
    
    class CEncoderData
    {
    public:
       CEncoderData(IWICBitmapEncoderInfo *piBitmapEncoderInfo, WCHAR *pszExtensions) 
       {
          m_piBitmapEncoderInfo = piBitmapEncoderInfo;
          m_csExtensions = pszExtensions;
          GetDefaultExtension();
       }
    
       ~CEncoderData()
       {
          RELEASE_INTERFACE(m_piBitmapEncoderInfo);
       }
    
    public:
       IWICBitmapEncoderInfo *m_piBitmapEncoderInfo;
       CString m_csExtensions;
       CString m_csDefaultExtension;
    
       void GetDefaultExtension()
       {
          WCHAR seps[] = L",";
          WCHAR *psz = NULL;
          WCHAR *next_token = NULL;
          WCHAR *token = NULL;
    
          size_t uLen = CString::StringLength(m_csExtensions) + 1;
          if (uLen > 0)
          {
             psz = new WCHAR[uLen];
             wcscpy_s(psz, uLen, m_csExtensions.GetBuffer());
             token = wcstok_s(psz, seps, &next_token);
             while (token != NULL)
             {
                if (wcslen(token) == 4)
                   m_csDefaultExtension = token;
    
                token = wcstok_s( NULL, seps, &next_token);
             }
          }
    
          if (psz == NULL)
          {
             delete psz;
             psz = NULL;
          }
       }
    };
    
    std::vector <CEncoderData *> gEncoderData;
    
    HRESULT EnumerateEncoders(CString &csFilter)
    {
       HRESULT hr = S_OK;
       IEnumUnknown *piEnumUnknown = NULL;
       gEncoderData.clear();
    
       IFS(gpiImagingFactory->CreateComponentEnumerator(WICEncoder, WICComponentEnumerateRefresh, &piEnumUnknown));
       if (SUCCEEDED(hr))
       {
          ULONG num = 0;
          IUnknown *piUnknown = NULL;
    
          piEnumUnknown->Reset();
          while ((S_OK == piEnumUnknown->Next(1, &piUnknown, &num)) && (1 == num))
          {
             CString csFriendlyName;
             IWICBitmapEncoderInfo *piBitmapEncoderInfo = NULL;
             IFS(piUnknown->QueryInterface(IID_IWICBitmapEncoderInfo, reinterpret_cast<void**>(&piBitmapEncoderInfo)));
    
             // Friendly name
             WCHAR *pszFriendlyName = NULL;
             UINT uActual = 0;
             IFS(piBitmapEncoderInfo->GetFriendlyName(0, NULL, &uActual));
    
             if (uActual > 0)
             {
                pszFriendlyName = new WCHAR[uActual+1];
                if (pszFriendlyName)
                {
                   memset(pszFriendlyName, 0, sizeof(WCHAR) * (uActual + 1));
                   IFS(piBitmapEncoderInfo->GetFriendlyName(uActual, pszFriendlyName, &uActual));
                }
             }
    
             // Extension
             WCHAR *pszExtensions = NULL;
             IFS(piBitmapEncoderInfo->GetFileExtensions(0, NULL, &uActual));
             if (uActual>0)
             {
                pszExtensions = new WCHAR[uActual+1];
                if (pszExtensions)
                {
                   memset(pszExtensions, 0, sizeof(WCHAR) * (uActual + 1));
                   IFS(piBitmapEncoderInfo->GetFileExtensions(uActual, pszExtensions, &uActual));
                }
             }
    
             CString cs;
             cs.Format(L"%s(%s)", pszFriendlyName, pszExtensions);
             csFilter = csFilter + cs + L"|" + pszExtensions + L"|";
    
    
             CEncoderData *pData = new CEncoderData(piBitmapEncoderInfo, pszExtensions);
             gEncoderData.push_back(pData);
    
             // Cleanup
             DELETE_POINTER(pszFriendlyName);
             RELEASE_INTERFACE(piBitmapEncoderInfo);
             RELEASE_INTERFACE(piUnknown);
          }
    
          // Terminate and replace the "|" character with a NULL
          csFilter.Replace(L".", L"*.");
          csFilter = csFilter + L"|";
    
          INT uLen = CString::StringLength(csFilter);
          for (INT i=0; i < uLen; i++)
          {
             if (csFilter[i] == L'|')
                csFilter.SetAt(i, L'\0');
    
             if (csFilter[i] == L',')
                csFilter.SetAt(i, L';');
          }
       }
       return hr;
    }
    
    
    //**********************************************************************************
    // PixelFormat Combo Box
    //**********************************************************************************
    class CPixelFormatData
    {
    public:
       CPixelFormatData(GUID guid) 
       {
          m_guid = guid;
       }
    
       ~CPixelFormatData()
       {
       }
       GUID m_guid;
    };
    
    
    // Cleanup for PixelFormat Combo Box
    void FreePixelFormatComboBox(HWND hDlg)
    {
       HWND hDlgItem = GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT);
       LRESULT nCount = SendMessage(hDlgItem, CB_GETCOUNT, 0, 0);
       CPixelFormatData* pData = NULL;
    
       for (LONG_PTR i=0; i < nCount; i++)
       {
          LRESULT lResult = SendMessage(hDlgItem, CB_GETITEMDATA, i, 0);
          if (lResult != CB_ERR)
          {
             pData = (CPixelFormatData*)lResult;
             if (pData)
                delete pData;
          }
       }
       SendMessage(hDlgItem, CB_RESETCONTENT, (WPARAM)0, (LPARAM)0);
    }
    
    CEncoderData *GetEncoderData(HWND hDlg)
    {
       CEncoderData *pData = NULL;
       HWND hWndParent = GetParent(hDlg);
       LRESULT nIndex = SendMessage(GetDlgItem(hWndParent, cmb1), CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
       if (nIndex >=0)
          pData = (CEncoderData *)gEncoderData[nIndex];
    
       return pData;
    }
    
    HRESULT EnumeratePixelFormat(HWND hDlg)
    {
       HRESULT hr = S_OK;
    
       FreePixelFormatComboBox(hDlg);
       CEncoderData *pData = GetEncoderData(hDlg);
       if (!pData)
          return hr;
    
    
       if (((LRESULT)pData != CB_ERR) && pData && pData->m_piBitmapEncoderInfo)
       {
          UINT uActual = 0;
          // Pixel Formats
          GUID *guids = NULL;
          IFS(pData->m_piBitmapEncoderInfo->GetPixelFormats(0, NULL, &uActual));
          if (uActual > 0)
          {
             IWICComponentInfo *piComponentInfo = NULL;
             guids = new GUID[uActual];
             IFS(pData->m_piBitmapEncoderInfo->GetPixelFormats(uActual, guids, &uActual));
             for (UINT i = 0; i < uActual; i++)
             {
                IFS(gpiImagingFactory->CreateComponentInfo(guids[i], &piComponentInfo));
    
                // Friendly name
                WCHAR *pszFriendlyName = NULL;
                UINT uActual = 0;
                IFS(piComponentInfo->GetFriendlyName(0, NULL, &uActual));
    
                if (uActual > 0)
                {
                   pszFriendlyName = new WCHAR[uActual+1];
                   if (pszFriendlyName)
                   {
                      memset(pszFriendlyName, 0, sizeof(WCHAR) * (uActual + 1));
                      IFS(piComponentInfo->GetFriendlyName(uActual, pszFriendlyName, &uActual));
                   }
                }
    
                LRESULT nIndex = SendMessage(GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT), CB_ADDSTRING, 0, (LPARAM)pszFriendlyName);
    
                CPixelFormatData *pData = new CPixelFormatData(guids[i]);
                SendMessage(GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT), CB_SETITEMDATA, nIndex, (LPARAM)pData);
             }
    
             DELETE_POINTER(guids);
             RELEASE_INTERFACE(piComponentInfo);
          }
          SendMessage(GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT), CB_SETCURSEL, 0, 0);
       }
       return hr;
    }
    
    GUID GetSelectedPixelFormat(HWND hDlg)
    {
       GUID guid = GUID_NULL;
    
       HWND hDlgItem = GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT);
       LRESULT nIndex = SendMessage(hDlgItem, CB_GETCURSEL, 0, 0);
    
       LRESULT lResult = SendMessage(hDlgItem, CB_GETITEMDATA, nIndex, 0);
       if (lResult == CB_ERR)
          return guid;
    
       CPixelFormatData *pData = (CPixelFormatData *)lResult;
       if (pData)
       {
          guid = pData->m_guid;
       }
       return guid;
    }
    
    //**********************************************************************************
    // Misc
    //**********************************************************************************
    class CMySaveDlgData
    {
    public:
       CMySaveDlgData() 
       {
          m_guidContainer = GUID_NULL;
          m_guidPixelFormat  = GUID_WICPixelFormatUndefined;
          m_nPixelFormatIndex = -1;
       }
    
       ~CMySaveDlgData()
       {
       }
    
       GUID m_guidContainer;
       GUID m_guidPixelFormat;
    
       // member variables for index of combo items
       INT m_nPixelFormatIndex;
    };
    
    
    void SetComboBoxIndex(HWND hDlg, INT nID, INT nIndex)
    {
       if (nIndex > 0)
          SendMessage(GetDlgItem(hDlg, nID),       CB_SETCURSEL, (WPARAM)nIndex,      0);
    }
    
    HRESULT InitDialog(HWND hDlg, LPARAM lParam)
    {
       HRESULT hr =S_OK;
       CMySaveDlgData *pData = NULL;
    
       if (!lParam)
          return hr;
    
       LPOPENFILENAME pOpenFileName = (LPOPENFILENAME)lParam;
       pData = (CMySaveDlgData*)pOpenFileName->lCustData;
       if (!pData)
          return hr;
    
    
       FreePixelFormatComboBox(hDlg);
    
       EnumeratePixelFormat(hDlg);
       SetComboBoxIndex(hDlg, IDC_COMBO_PIXEL_FORMAT,        pData->m_nPixelFormatIndex);
    
    
       HWND hWndParent = GetParent(hDlg);
       SetWindowText(GetDlgItem(hWndParent, stc2), L"&Encoders:");
       SetWindowText(GetDlgItem(hWndParent, IDC_STATIC_PIXEL_FORMAT), L"&Pixel Format:");
    
       return hr;
    }
    
    void FreeDialog(HWND hDlg)
    {
       FreePixelFormatComboBox(hDlg);
    }
    
    // Append appropriate extension to file name
    void AppendAppropriateExtension(HWND hDlg)
    {
       HWND hWndParent = GetParent(hDlg);
       CEncoderData *pData = GetEncoderData(hDlg);
       if (!pData)
          return;
    
       WCHAR szFileName[MAX_PATH] = {0};
       UINT uRet = GetDlgItemText(GetParent(hDlg), cmb13, szFileName, MAX_PATH);
       if (uRet > 0)
       {
          WCHAR drive[MAX_PATH] = {0};
          WCHAR dir[MAX_PATH] = {0};
          WCHAR fname[MAX_PATH] = {0};
          WCHAR ext[MAX_PATH] = {0};
    
          DWORD dwFlags = GetFileAttributes(szFileName);
    
          if (((dwFlags & FILE_ATTRIBUTE_DIRECTORY) != FILE_ATTRIBUTE_DIRECTORY) || (dwFlags == INVALID_FILE_ATTRIBUTES))
          {
             _wsplitpath_s(szFileName, drive, MAX_PATH, dir, MAX_PATH, fname, MAX_PATH, ext, MAX_PATH );
             CString cs;
             cs.Format(L"%s%s%s%s", drive, dir ,fname, pData->m_csDefaultExtension);
             SetDlgItemText(hWndParent, cmb13, cs.GetBuffer());
          }
       }
    }
    
    UINT_PTR CALLBACK MySaveHookProc(
        HWND hDlg,
        UINT message,
        WPARAM wParam,
        LPARAM lParam
    )
    {
       UNREFERENCED_PARAMETER(lParam);
       switch (message)
       {
       case WM_INITDIALOG:
          InitDialog(hDlg, lParam);
          return (INT_PTR)TRUE;
    
       case WM_DESTROY:
          FreeDialog(hDlg);
          return 0;
    
       //case WM_SIZE:
       //   ArrangeDialogItems(hDlg);
       //   return 0;
    
       case WM_NOTIFY:
          {
             LPOFNOTIFYW lpOfNotify = (LPOFNOTIFY) lParam;
             switch (lpOfNotify->hdr.code)
             {
             case CDN_TYPECHANGE:
                EnumeratePixelFormat(hDlg);
                AppendAppropriateExtension(hDlg);
                break;
    
             case CDN_FILEOK:
                {
                   CMySaveDlgData *pMySaveDlgData = (CMySaveDlgData *)lpOfNotify->lpOFN->lCustData;
                   if (pMySaveDlgData)
                   {
                      // Get container guid
                      pMySaveDlgData->m_guidContainer = GUID_NULL;
                      CEncoderData *pEncoderData = (CEncoderData *)gEncoderData[lpOfNotify->lpOFN->nFilterIndex-1];
                      pEncoderData->m_piBitmapEncoderInfo->GetContainerFormat(&pMySaveDlgData->m_guidContainer);
    
                      // Get pixel format
                      pMySaveDlgData->m_guidPixelFormat = GetSelectedPixelFormat(hDlg);
                      pMySaveDlgData->m_nPixelFormatIndex = (INT)SendMessage(GetDlgItem(hDlg, IDC_COMBO_PIXEL_FORMAT),CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
    
                      }
                }
                break;
             }
          }
          return 0; // return value ignored
    
       case WM_COMMAND:
          if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
          {
             EndDialog(hDlg, LOWORD(wParam));
             return (INT_PTR)TRUE;
          }
          break;
       }
       return 0;
    }
    
    HRESULT MySaveDialog(HWND hWnd)
    {
       HRESULT hr = S_OK;
       static OPENFILENAME ofn = {0};
       CString csFilters;
    
       WCHAR szTitle[MAX_PATH] = L"Save As...";
       WCHAR szFileTitle[MAX_PATH] = L"MyFileTitle";
       WCHAR szDefExt[4] = {0};
       WCHAR szFile[MAX_PATH] = {0};
    
       IFS(CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*) &gpiImagingFactory));
       EnumerateEncoders(csFilters);
    
       ofn.lStructSize = sizeof(OPENFILENAME); 
       ofn.hwndOwner = hWnd; 
       ofn.lpstrFilter = csFilters.GetBuffer();//szFilter; 
    
       // Find the first 'LEAD' filter
       ofn.nFilterIndex = 0;
       ofn.lpstrFile= szFile; 
       ofn.nMaxFile = sizeof(szFile)/ sizeof(*szFile); 
       ofn.lpstrFileTitle = szFileTitle; 
       ofn.nMaxFileTitle = sizeof(szFileTitle); 
       ofn.lpstrInitialDir = (LPWSTR)NULL; 
       ofn.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_PATHMUSTEXIST |  OFN_ENABLETEMPLATE | OFN_ENABLESIZING | OFN_ENABLEHOOK; 
       ofn.lpstrTitle = szTitle; 
       ofn.lpstrDefExt = szDefExt;
    
       ofn.hInstance = hInst;
       ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG_SAVE_TEMPLATE);
       ofn.lpfnHook = MySaveHookProc;
    
       static CMySaveDlgData mySaveDlgData;
       ofn.lCustData = (LPARAM)&mySaveDlgData;
    
       if (GetSaveFileName(&ofn))
       {
          HCURSOR hCursorPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
          //hr = EncoderSave(ofn.lpstrFile, &mySaveDlgData);
          SetCursor(hCursorPrev);
       }
    
       RELEASE_INTERFACE(gpiImagingFactory);
       return hr;
    }
        
  2. Open tutorial.cpp. Add a forward declaration for MySaveDialog in the Forward declarations of functions included in this code module section.
    // Forward declarations of functions included in this code module: 
    HRESULT MySaveDialog(HWND hWnd);
        

  3. Open tutorial.cpp and in WndProc add a case for ID_FILE_SAVE after the ID_FILE_OPEN case.
        case ID_FILE_SAVE:
            MySaveDialog(hWnd);
            break;
        

  4. Modify SetGlobalBitmaps  to keep a copy of the currently displayed image in the global variable gpiBitmapSource. Modify FreeGlobalBitmaps to release the gpiBitmapSource.
    BOOL FreeGlobalBitmaps()
    {
       BOOL bRet = FALSE;
       // Release any existing global bitmaps
    
       if (gpGdiPlusBitmap)
       {
          delete gpGdiPlusBitmap;
          gpGdiPlusBitmap= NULL;
          bRet = TRUE;
       }
    
       if (gpiBitmapSource)
       {
          gpiBitmapSource->Release();
          gpiBitmapSource = NULL;
          bRet = TRUE;
       }
       return bRet;
    }
    
    void SetGlobalBitmaps(IWICBitmapSource *piBitmapSource)
    {
       Bitmap *pGdiPlusBitmap = NULL;
       BYTE *pbGdiPlusBuffer = NULL;
       if (!piBitmapSource)
          return;
    
       BitmapSourceToGdiPlusBitmap(piBitmapSource, &pGdiPlusBitmap, &pbGdiPlusBuffer);
       if (pGdiPlusBitmap)
       {
          FreeGlobalBitmaps();
          gpGdiPlusBitmap= pGdiPlusBitmap;
          gpiBitmapSource = piBitmapSource;
          gpiBitmapSource->AddRef();
       }
    }
        

  5. Compile and run your program.
  6. Open an image file. The File->Save menu item should now be enabled. Choose File->Save.
    The file save dialog is displayed. An Encoders combo box with all avaiable WIC-enabled encoders is displayed. As you choose different encoders, the Pixel Format combo box is updated with the available pixel formats. The save dialog displays all the options, but does not yet save the image file.

  7. Search for the following line of code in the function MySaveDialog. It is commented out. Uncomment this line of code.
          hr = EncoderSave(ofn.lpstrFile, &mySaveDlgData);
    

  8. Add the EncoderSave function immediately before the function MySaveDialog. Also add the utility functions PaletteColorCount, CopyBitmapSourcePalette, and BitmapSourceToBitmapFrameEncode. This function creates a file using the encoder and pixel format that was selected in the save dialog.
    UINT PaletteColorCount(GUID guidPixelFormat)
    {
       UINT uPaletteColorCount = 0;
        if (GUID_WICPixelFormat1bppIndexed == guidPixelFormat)
        {
            uPaletteColorCount =  2;
        }
        else if (GUID_WICPixelFormat2bppIndexed == guidPixelFormat)
        {
            uPaletteColorCount = 4;
        }
        else if (GUID_WICPixelFormat4bppIndexed == guidPixelFormat)
        {
            uPaletteColorCount = 16;
        }
        else if (GUID_WICPixelFormat8bppIndexed == guidPixelFormat)
        {
            uPaletteColorCount = 256;
        }
    
        return uPaletteColorCount;
    }
    
    HRESULT CopyBitmapSourcePalette(IWICBitmapSource *piSource, IWICPalette **ppiPalette, UINT uPaletteColorCount)
    {
       HRESULT hr = S_OK;
       if (!piSource)
          return E_INVALIDARG;
    
       IWICPalette *piPalette = NULL;
    
       IFS(gpiImagingFactory->CreatePalette(&piPalette));
    
       // CopyPalette my fail, if the source does not have a palette
       hr = piSource->CopyPalette(piPalette);
       if (FAILED(hr))
       {
          // Try to create a palette 
          hr = S_OK;
          IFS(piPalette->InitializeFromBitmap(piSource, uPaletteColorCount, FALSE));
       }
    
       if (SUCCEEDED(hr))
       {
          if (ppiPalette)
          {
             (*ppiPalette) = piPalette;
             (*ppiPalette)->AddRef();
          }
       }
    
       RELEASE_INTERFACE(piPalette);
       return hr;
    }
    
    
    // Converts a BitmapSource to a BitmapFrame
    HRESULT BitmapSourceToBitmapFrameEncode(IWICBitmapSource *piSource, IWICBitmapFrameEncode *piBitmapFrame, GUID pixelFormat)
    {
       HRESULT hr = S_OK;
       UINT uWidth = 0;
       UINT uHeight = 0;
       IWICPalette *piPalette = NULL;
    
       
       IFS(piSource->GetSize(&uWidth, &uHeight));
       IFS(piBitmapFrame->SetSize(uWidth, uHeight));
       UINT uPaletteColorCount = PaletteColorCount(pixelFormat);
       if (uPaletteColorCount > 0)
       {
          CopyBitmapSourcePalette(piSource, &piPalette, uPaletteColorCount);
          if (piPalette)
          {
             piBitmapFrame->SetPalette(piPalette);
          }
       }
    
       WICRect rc = {0,0,uWidth, uHeight};
       IFS(piBitmapFrame->WriteSource(piSource, &rc));
       RELEASE_INTERFACE(piPalette);
       return hr;
    }
    
    HRESULT EncoderSave( LPCWSTR pszFileSave, CMySaveDlgData *pMySaveDlgData)
    {
       IWICStream *piStream = NULL;
       HRESULT hr = S_OK;
    
       IWICBitmapEncoder *piEncoder = NULL;
       IWICBitmapFrameEncode *piBitmapFrame = NULL;
       IPropertyBag2 *piPropertyBag = NULL;
       
       // ***********************************************
       // Create the appropriate encoder
       //************************************************
       IFS(gpiImagingFactory->CreateStream(&piStream));
       IFS(piStream->InitializeFromFilename(pszFileSave, GENERIC_WRITE));
       IFS(gpiImagingFactory->CreateEncoder(pMySaveDlgData->m_guidContainer, NULL, &piEncoder));
    
       IFS(piEncoder->Initialize(piStream, WICBitmapEncoderNoCache));
       IFS(piEncoder->CreateNewFrame(&piBitmapFrame, &piPropertyBag));
    
       IFS(piBitmapFrame->Initialize(piPropertyBag));
       IFS(piBitmapFrame->SetPixelFormat(&pMySaveDlgData->m_guidPixelFormat));
       IFS(BitmapSourceToBitmapFrameEncode(gpiBitmapSource, piBitmapFrame, pMySaveDlgData->m_guidPixelFormat));
    
       // ***********************************************
       // Save the file
       //************************************************
       IFS(piBitmapFrame->Commit());
       IFS(piEncoder->Commit());
    
       // ***********************************************
       // Cleanup
       //************************************************
       RELEASE_INTERFACE(piBitmapFrame);
       RELEASE_INTERFACE(piEncoder);
       RELEASE_INTERFACE(piStream);
    
       return hr;
    }
    

  9. Compile and run your program.
You are now able to save an image file using WIC. At this point, you can register different LEAD Bimap Decoders (see Registering the LEAD WIC-Enabled Codecs. Note that you will be able to save any of these new image formats without recompiling this demo!

See Also