当前位置:首页 > c++ > 正文内容

使用GDI+ 保存HDC到本地图片文件

xuwenyan2个月前 (12-01)c++80

使用GDI+ 将HDC保存到本地图片文件

/*
 *GDI+支持bmp jpeg gif tiff png等几种格式  
 *下面的程序基本思路是先将目标DC上的内容存到内存BITMAP  
 *再使用GDI+Bitmap::FromHBITMAP加载内存位图,并保存成文件   
 */

#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"D:\\test.bmp", &pngClsid) == Ok)
    {
      bRet = TRUE;
    }
    delete pbmSrc;
  }

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

  return bRet;
}

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;
}


    文章作者:xuwenyan
    版权声明:本文为本站原创文章,转载请注明出处,非常感谢,如版权漏申明或您觉得任何有异议的地方欢迎与本站取得联系。

    扫描二维码推送至手机访问。

    版权声明:本文由艺文笔记发布,如需转载请注明出处。

    本文链接:https://www.xuwenyan.com/archives/2931

    分享给朋友:

    “使用GDI+ 保存HDC到本地图片文件” 的相关文章

    vs(vs2015)拖动或停靠窗口崩溃的解决方法

    vs(vs2015)拖动或停靠窗口崩溃的解决方法

    使用vs拖动窗口后想要停靠某一个区域时,ide会崩溃重启,而且会反复这样,拖动布局功能基本丧失,使用起来非常不爽。解决办法如下: vs2019(visual studio 2019) 如果vs版本是2019,那么直接升级vs即可解决问题。 vs2015(visual studio...

    C++指针*为什么靠后会比较好?

    C++指针*为什么靠后会比较好?

    大多数书中和大神的代码里,往往指针的*都是靠变量而不是靠类型的,这主要是为了不造成我们第一眼对变量类型的误解和对指针类型的误解,比如: int* p1,p2 我们一眼看上去是不是通常会觉得p1、p1都是一个int*的指针呢?因为我们通常会误把int*当作一个类型,然而无论int*还是i...

    C++如何获取控制台程序的输出内容?

    C++如何获取控制台程序的输出内容?

    很多工具程序(如ffmpeg)的进度显示往往都是以控制台字符显示的方法,我们可能需要调用这种控制台工具去完成工作,但同时又希望以友好的ui界面去显示当前的工作状态(如进度)。此时我们能想到的就是运行控制台程序,然后以某种方式去获取到控制台程序的输出,然后转换到我们的ui界面上去显示。 有多种...

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    使用GDI、MFC_GDI、GDI+绘制数组RGBA序列

    学习ffmpeg时遇到一个问题,ffmpeg解码出RGB颜色后怎么绘制到屏幕上,于是将GDI、MFC_GDI、GDI+等方式都记录一下 1:注意按windows的要求,R、G、B、A顺序要调整为B、G、R、A 。 2:GDI不支持透明通道A,透明通道A的值读进去以后没有作用。想要支持透...

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    VC的ATL工程向导同时生成一个PS工程是做什么的?可以不要吗?

    例如,我用VC2015的工程向导新建一个ATL的工程名字叫myAtl,那么VC会同时给我生成一个叫做myAtlPS的工程。这个myAtlPS工程是做什么的?什么情况下可以不需要它?什么情况下它又是必须存在的? PS工程是什么?可以不要吗? 这个PS工程叫做代理与存根(proxy&nbs...

    ATL实现windows右键菜单扩展(ContextMenu)

    ATL实现windows右键菜单扩展(ContextMenu)

    右键菜单,即用户右击shell对象时弹出的上下文菜单(context menu)。本文记录了如何创建右键菜单的基本过程,跟着步骤一步一步来,即可创建出一个右键菜单工程。第一步,新建一个ATL工程Visual Studio—>新建项目—>ATL—>使用默认配置(一直按下一步即可)。注...