天天看点

使用GDI+ 保存HDC为位图文件

//GDI+为图片的加载、存储,屏蔽了内部编解码、压缩解压缩等的具体细节,给程序员带来了极大的方便
//目前版本的GDI+支持bmp jpeg gif tiff png等几种格式
//下面的程序基本思路是先将目标DC上的内容存到内存BITMAP
//再使用GDI+Bitmap::FromHBITMAP加载内存位图,并保存成文件
//此版本在Win32和MFC环境下测试通过
//
//使用GDI+ 保存HDC为位图文件

#include <rpc.h>
#include <rpcndr.h>
#include <unknwn.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

struct _GdiplusToken
{
  Gdiplus::GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR gdiplusToken;

  _GdiplusToken()
  {
    if(Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) != Ok)
    {
      MessageBox(NULL, _T("GdiplusStartup failed"), _T("Error"), MB_OK);
    }
  }

  ~_GdiplusToken()
  {
    Gdiplus::GdiplusShutdown(gdiplusToken);
  }  
}GdiplusToken;


int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
  UINT  num = 0;          // number of image encoders
  UINT  size = 0;         // size of the image encoder array in bytes

  ImageCodecInfo* pImageCodecInfo = NULL;

  Gdiplus::GetImageEncodersSize(&num, &size);
  if(size == 0)
    return -1;  // Failure

  pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  if(pImageCodecInfo == NULL)
    return -1;  // Failure

  Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);

  for(UINT j = 0; j < num; ++j)
  {
    if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
    {
      *pClsid = pImageCodecInfo[j].Clsid;
      free(pImageCodecInfo);
      return j;  // Success
    }    
  }

  free(pImageCodecInfo);
  return -1;  // Failure
}

BOOL SaveHDCToFile(HDC hDC, LPRECT lpRect)
{   
  BOOL bRet = FALSE;
  int nWidth = lpRect->right - lpRect->left;
  int nHeight = lpRect->bottom - lpRect->top;

  //将目标区域贴图到内存BITMAP
  HDC memDC = CreateCompatibleDC(hDC); 
  HBITMAP hBmp = CreateCompatibleBitmap(hDC, nWidth, nHeight);
  SelectObject(memDC, hBmp);
  BitBlt(memDC, lpRect->left, lpRect->top, nWidth, nHeight,
    hDC, 0, 0, SRCCOPY);

  //保存成文件
  {
    //L"image/bmp" L"image/jpeg"  L"image/gif" L"image/tiff" L"image/png"
    CLSID pngClsid;
    GetEncoderClsid(L"image/bmp", &pngClsid);//此处以BMP为例,其它格式选择对应的类型,如JPG用L"image/jpeg" 

    Gdiplus::Bitmap *pbmSrc = Gdiplus::Bitmap::FromHBITMAP(hBmp, NULL);
    if( pbmSrc->Save(L"C:\\test.bmp", &pngClsid) == Ok)
    {
      bRet = TRUE;
    }
    delete pbmSrc;
  }

  //清理工作
  SelectObject(memDC, (HBITMAP)NULL);
  DeleteDC(memDC);  
  DeleteObject(hBmp);

  return bRet;
}
           
//Win32下的测试用例
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int wmId, wmEvent;
  PAINTSTRUCT ps;
  HDC hdc;

  switch (message)
  {
  case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    // TODO: 在此添加任意绘图代码...
    TextOut(hdc, 0, 0, _T("ABCD"), 4);
    EndPaint(hWnd, &ps);
    break;
  case WM_KEYDOWN:
    {
      HDC hDC = GetDC(hWnd);
      RECT rcRect;
      GetClientRect(hWnd, &rcRect);
      SaveHDCToFile(hDC, &rcRect);
      ReleaseDC(hWnd, hDC);
      break;
    } 
  case WM_DESTROY:
    PostQuitMessage(0);
    break;
  default:
    return DefWindowProc(hWnd, message, wParam, lParam);
  }
  return 0;
}