title: How to save HBITMAP as JPG using Win32 Imaging API (Windows Mobile 6+)?
body: <p>I have created procedures to save window screenshot to file. It works for PNG and BMP, but not for JPG (and GIF).
  Here is code for capturing HBITMAP:</p>
  
  <pre><code>HBITMAP Signature::getScreenHBITMAP() {
  // get screen rectangle 
  RECT windowRect; 
  GetWindowRect(getMainWnd(), &amp;windowRect); 
  
  // bitmap dimensions 
  int bitmap_dx = windowRect.right - windowRect.left; 
  int bitmap_dy = windowRect.bottom - windowRect.top; 
  
  // create bitmap info header 
  BITMAPINFOHEADER infoHeader; 
  infoHeader.biSize          = sizeof(infoHeader); 
  infoHeader.biWidth         = bitmap_dx; 
  infoHeader.biHeight        = bitmap_dy; 
  infoHeader.biPlanes        = 1; 
  infoHeader.biBitCount      = 24;
  infoHeader.biCompression   = BI_RGB; 
  infoHeader.biSizeImage     = 0;
  infoHeader.biXPelsPerMeter = 0;
  infoHeader.biYPelsPerMeter = 0;
  infoHeader.biClrUsed       = 0;
  infoHeader.biClrImportant  = 0;
  
  // dibsection information 
  BITMAPINFO info; 
  info.bmiHeader = infoHeader; 
  HDC winDC = GetWindowDC(getMainWnd()); 
  HDC memDC = CreateCompatibleDC(winDC); 
  BYTE* memory = 0; 
  HBITMAP bitmap = CreateDIBSection(winDC, &amp;info, DIB_RGB_COLORS, (void**)&amp;memory, 0, 0); 
  SelectObject(memDC, bitmap); 
  // Copies screen upside down (as it is already upside down) - if need normal layout, change to BitBlt function call
  StretchBlt(memDC, 0, 0, bitmap_dx, bitmap_dy, winDC, 0, bitmap_dy, bitmap_dx, bitmap_dy * -1, SRCCOPY); 
  DeleteDC(memDC); 
  ReleaseDC(getMainWnd(), winDC); 
  
  return bitmap;
  }
  </code></pre>
  
  <p>And here is code for image saving:</p>
  
  <pre><code>HRESULT Imaging_SaveToFile(HBITMAP handle, LPTSTR filename, LPCTSTR format){
  HRESULT res;
  
  res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  if ((res == S_OK) || (res == S_FALSE)) {
      IImagingFactory* factory=NULL;
      if (CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&amp;factory) == S_OK) {
          UINT count;
          ImageCodecInfo* imageCodecInfo=NULL;
          if (factory-&gt;GetInstalledEncoders(&amp;count, &amp;imageCodecInfo) == S_OK) {
              // Get the particular encoder to use
              LPTSTR formatString;
              if (wcscmp(format, L"png") == 0) {
                  formatString = _T("image/png");
              } else if (wcscmp(format, L"jpg") == 0) {
                  formatString = _T("image/jpeg");
              } else if (wcscmp(format, L"gif") == 0) {
                  formatString = _T("image/gif");
              } else if (wcscmp(format, L"bmp") == 0) {
                  formatString = _T("image/bmp");
              } else {
                  CoUninitialize();
                  return S_FALSE;
              }
              CLSID encoderClassId;
              if (count == 0) {
                  CoUninitialize();
                  return S_FALSE;
              }
              for(int i=0; i &lt; (int)count; i++) {
                  if (wcscmp(imageCodecInfo[i].MimeType, formatString) == 0) {
                      encoderClassId= imageCodecInfo[i].Clsid;
                      free(imageCodecInfo);
                      break;
                  } else {
                      continue;
                  }
                  CoUninitialize();
                  return S_FALSE;
              } 
              IImageEncoder* imageEncoder=NULL;
              if (factory-&gt;CreateImageEncoderToFile(&amp;encoderClassId, filename, &amp;imageEncoder) == S_OK) {
                  IImageSink* imageSink = NULL;
                  res = imageEncoder-&gt;GetEncodeSink(&amp;imageSink);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
                  BITMAP bm;
                  GetObject (handle, sizeof(BITMAP), &amp;bm);
  
                  ImageInfo* imageInfo = new ImageInfo();
                  imageInfo-&gt;Width = bm.bmWidth;
                  imageInfo-&gt;Height = bm.bmHeight;
                  imageInfo-&gt;RawDataFormat = IMGFMT_MEMORYBMP; //ImageFormatMemoryBMP;
                  imageInfo-&gt;Flags |= SinkFlagsTopDown | SinkFlagsFullWidth;
                  // Get pixel format from hBitmap
                  PixelFormatID pixelFormat;
                  int numColors = 0;
                  switch (bm.bmBitsPixel) {
                      case 1: {
                          pixelFormat = PixelFormat1bppIndexed;
                          numColors = 1;
                          break;
                      }
                      case 4: {
                          pixelFormat = PixelFormat4bppIndexed;
                          numColors = 16;
                          break;
                      }
                      case 8: {
                          pixelFormat = PixelFormat8bppIndexed;
                          numColors = 256;
                          break;
                      }
                      case 24: {
                          pixelFormat = PixelFormat24bppRGB;
                          break;
                      }
                      default: {
                          pixelFormat = PixelFormat32bppARGB;
                          numColors = 3; // according to MSDN 16 and 32 bpp numColors should be 3
                          break;
                      }
                  }
                  imageInfo-&gt;PixelFormat = pixelFormat;
                  if (pixelFormat == PixelFormat32bppARGB) imageInfo-&gt;Flags |= SinkFlagsHasAlpha;
                  res = imageSink-&gt;BeginSink(imageInfo, NULL);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
                  ColorPalette* palette = NULL;
                  if (numColors &gt; 0) {
                      palette = (ColorPalette*)malloc(sizeof(ColorPalette) + (numColors - 1) * sizeof(ARGB));
                      palette-&gt;Count = numColors;
                      for (int i=0; i&lt;numColors; i++) {
                          int rgb = i*64;
                          int red = rgb &amp; 0x00FF;
                          int green = (rgb &gt;&gt; 8) &amp; 0x00FF;
                          int blue = (rgb &gt;&gt; 16) &amp; 0x00FF;
                          palette-&gt;Entries[i] = MAKEARGB(0, red, green, blue);
                      }
                  } else {
                      palette = (ColorPalette*)malloc(sizeof(ColorPalette));
                      palette-&gt;Count = 0;
                      if (pixelFormat == PixelFormat32bppARGB) palette-&gt;Flags = PALFLAG_HASALPHA;
                  }
                  res = imageSink-&gt;SetPalette(palette);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
  
                  BitmapData* bmData = new BitmapData();
                  bmData-&gt;Height = bm.bmHeight;
                  bmData-&gt;Width = bm.bmWidth;
                  bmData-&gt;Scan0 = bm.bmBits;
                  bmData-&gt;PixelFormat = pixelFormat;
  
                  UINT bitsPerLine = imageInfo-&gt;Width * bm.bmBitsPixel;
                  UINT bitAlignment = sizeof(LONG) * 8;
                  UINT bitStride = bitAlignment * (bitsPerLine / bitAlignment);   // The image buffer is always padded to LONG boundaries
                  if ((bitsPerLine % bitAlignment) != 0) bitStride += bitAlignment; // Add a bit more for the leftover values
                  bmData-&gt;Stride = (bitStride / 8);
  
                  RECT rect;
                  rect.top = 0;
                  rect.bottom = bm.bmHeight;
                  rect.left = 0;
                  rect.right = bm.bmWidth;
  
                  res = imageSink-&gt;PushPixelData(&amp;rect, bmData, TRUE);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
  
                  res = imageSink-&gt;EndSink(S_OK);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
                  imageSink-&gt;Release();
                  res = imageEncoder-&gt;TerminateEncoder();
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
              }
          }
      }
      CoUninitialize();
  } else {
      return res;
  }
  
  return res;
  }
  </code></pre>
  
  <p>I used code from <a href="http://www.koders.com/ExceptionPage.aspx?aspxerrorpath=/cpp/fid743B2B2FCDBFE91584C329A50766C1155709DA1B.aspx" rel="noreferrer" title="Koders.com">Koders.com</a> as an example and tried to follow <a href="http://msdn.microsoft.com/en-us/library/ms940063.aspx" rel="noreferrer">MSDN description of image encoding</a> when modified this example.</p>
  
  <p>Found also that others have similar issue, but with no answer:</p>
  
  <p>social.msdn.microsoft.com/Forums/en-US/windowsmobiledev/thread/1c368cc1-cc5b-419e-a7d2-2a39c90ae83d/</p>
  
  <p>groups.google.com/group/microsoft.public.windowsce.embedded.vc/browse_thread/thread/8cd67e16ac29627b/9242e82721c48ace?hl=hu&amp;pli=1</p>
  
  <p>I also found solution which uses GDI+ wrapper: </p>
  
  <p>www.ernzo.com/LibGdiplus.aspx</p>
  
  <p>www.codeproject.com/KB/windows/gdiplusandwinmobile.aspx</p>
  
  <p>But I cannot use this GDI+ lib. Also I do not need whole GDI+. Tried to create similar saving procedure like in this wrapper, but with no success.</p>
  
  <p><strong>EDIT</strong></p>
  
  <p>Here is fixed and working solution (Thanks PhilMY for answer):</p>
  
  <pre><code>HRESULT Imaging_SaveToFile(HBITMAP handle, LPTSTR filename, LPCTSTR format){
  HRESULT res;
  
  res = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  if ((res == S_OK) || (res == S_FALSE)) {
      IImagingFactory* factory=NULL;
      if (CoCreateInstance(CLSID_ImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IImagingFactory, (void**)&amp;factory) == S_OK) {
          UINT count;
          ImageCodecInfo* imageCodecInfo=NULL;
          if (factory-&gt;GetInstalledEncoders(&amp;count, &amp;imageCodecInfo) == S_OK) {
              // Get the particular encoder to use
              LPTSTR formatString;
              if (wcscmp(format, L"png") == 0) {
                  formatString = _T("image/png");
              } else if (wcscmp(format, L"jpg") == 0) {
                  formatString = _T("image/jpeg");
              } else if (wcscmp(format, L"gif") == 0) {
                  formatString = _T("image/gif");
              } else if (wcscmp(format, L"bmp") == 0) {
                  formatString = _T("image/bmp");
              } else {
                  CoUninitialize();
                  return S_FALSE;
              }
              CLSID encoderClassId;
              if (count == 0) {
                  CoUninitialize();
                  return S_FALSE;
              }
              for(int i=0; i &lt; (int)count; i++) {
                  if (wcscmp(imageCodecInfo[i].MimeType, formatString) == 0) {
                      encoderClassId= imageCodecInfo[i].Clsid;
                      free(imageCodecInfo);
                      break;
                  } else {
                      continue;
                  }
                  CoUninitialize();
                  return S_FALSE;
              } 
              IImageEncoder* imageEncoder=NULL;
              if (factory-&gt;CreateImageEncoderToFile(&amp;encoderClassId, filename, &amp;imageEncoder) == S_OK) {
                  IImageSink* imageSink = NULL;
                  res = imageEncoder-&gt;GetEncodeSink(&amp;imageSink);
  
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
  
                  BITMAP bm;
                  GetObject (handle, sizeof(BITMAP), &amp;bm);
                  PixelFormatID pixelFormat;
                  switch (bm.bmBitsPixel) {
                      case 1: {
                          pixelFormat = PixelFormat1bppIndexed;
                          break;
                      }
                      case 4: {
                          pixelFormat = PixelFormat4bppIndexed;
                          break;
                      }
                      case 8: {
                          pixelFormat = PixelFormat8bppIndexed;
                          break;
                      }
                      case 24: {
                          pixelFormat = PixelFormat24bppRGB;
                          break;
                      }
                      default: {
                          pixelFormat = PixelFormat32bppARGB;
                          break;
                      }
                  }
  
                  BitmapData* bmData = new BitmapData();
                  bmData-&gt;Height = bm.bmHeight;
                  bmData-&gt;Width = bm.bmWidth;
                  bmData-&gt;Scan0 = bm.bmBits;
                  bmData-&gt;PixelFormat = pixelFormat;
  
                  UINT bitsPerLine = bm.bmWidth * bm.bmBitsPixel;
                  UINT bitAlignment = sizeof(LONG) * 8;
                  UINT bitStride = bitAlignment * (bitsPerLine / bitAlignment);   // The image buffer is always padded to LONG boundaries
                  if ((bitsPerLine % bitAlignment) != 0) bitStride += bitAlignment; // Add a bit more for the leftover values
                  bmData-&gt;Stride = (bitStride / 8);
  
                  IBitmapImage* pBitmap;
                  factory-&gt;CreateBitmapFromBuffer(bmData, &amp;pBitmap);
                  IImage* pImage;
                  pBitmap-&gt;QueryInterface(IID_IImage, (void**)&amp;pImage); 
                  res = pImage-&gt;PushIntoSink(imageSink);
                  if (res != S_OK) {
                      CoUninitialize();
                      return res;
                  }
  
                  pBitmap-&gt;Release();
                  pImage-&gt;Release();
                  imageSink-&gt;Release();
                  imageEncoder-&gt;TerminateEncoder();
                  imageEncoder-&gt;Release();
              }
          }
      }
      CoUninitialize();
  } else {
      return res;
  }
  
  return res;
  }
  </code></pre>