用gdi 实现屏幕截图功能

时间:2022-11-14 15:26:50

    最近在工作中要实现一个截图的功能,由于之前没接触过这类东西,搜索了大部分资料,终于完成了,总结下;

    首先,所谓的桌面截图其实并不是在真正的桌面上截图,只是把当前屏幕的图片复制的自己创建的对话框中,作为对话框的背景,然后在自己的对话框中截图,好了废话不多说了,说说实现了;

   1  要获取到桌面的截图,首先要获取到桌面的DC,得到桌面dc后,根据桌面dc,创建一个内存兼容的内存dc和内存位图bmp,然后把bmp选入当前内存dc,最后调用BitBlt把桌面dc复制到内存dc中(创建内存dc是为了双缓冲,防止屏幕闪烁)。

    

   HDC dcScreen;
HBITMAP m_bmpScreen;
HBITMAP hOldBitmap;
HDC m_dcMem;
dcScreen = CreateDC("DISPLAY", NULL, NULL, NULL); //创建屏幕设备dc
m_size.cx = GetDeviceCaps(dcScreen, HORZRES);
m_size.cy= GetDeviceCaps(dcScreen, VERTRES);

m_dcMem = CreateCompatibleDC(dcScreen); //创建与设备dc兼容的内存dc
m_bmpScreen = CreateCompatibleBitmap(dcScreen, m_size.cx,m_size.cy);//创建于屏幕dc兼容的位图

hOldBitmap = (HBITMAP)SelectObject(m_dcMem,m_bmpScreen);
BitBlt(m_dcMem, 0, 0,m_size.cx, m_size.cy,dcScreen, 0, 0, SRCCOPY);
2 在对话框的OnPaint函数中,把内存dc复制到对话框dc中,这样对话框就有桌面的图片了

 StretchBlt(dc,0,0,m_size.cx, m_size.cy,

m_dcMem,
0,0,m_size.cx, m_size.cy,
SRCCOPY);
3 实现截图,截图首先要随着鼠标移动,画一个矩形区域,此处也要用到双缓冲技术

  

  HDC mydc;
mydc = CreateCompatibleDC(dc);

HBITMAP bmp,oldbmp;
bmp = CreateCompatibleBitmap(dc,m_size.cx,m_size.cy);
oldbmp = (HBITMAP)SelectObject(mydc,bmp);


BitBlt(mydc,0,0,m_size.cx,m_size.cy,m_dcMem,0,0,SRCCOPY);

HPEN hPen = ::CreatePen(PS_DASHDOT, 1, RGB(255, 0, 0));
HBRUSH brush = (HBRUSH)GetStockObject(NULL_BRUSH);

HPEN oldpen = (HPEN)SelectObject(mydc,hPen);
HBRUSH oldbrush = (HBRUSH)SelectObject(mydc,brush);


MoveToEx(mydc,p_begin.x, p_begin.y,NULL);
LineTo(mydc,X, p_begin.y);
LineTo(mydc,X, Y);
LineTo(mydc,p_begin.x, Y);
LineTo (mydc,p_begin.x, p_begin.y);

p_end.x = X;
p_end.y = Y;




AnsiString str = "当前图片大小为:";
str += IntToStr((int)a);
str += "*";
str += IntToStr((int)b);



TextOut(mydc,X,Y+10,str.c_str(),strlen(str.c_str()));


StretchBlt(dc,0,0,m_size.cx, m_size.cy,
mydc,
0,0,m_size.cx, m_size.cy,
SRCCOPY);

SelectObject(mydc,oldpen);
SelectObject(mydc,oldbrush);

DeleteDC(mydc);
DeleteObject(bmp);

ReleaseDC(this->Handle, dc);
4 截图功能  仿照qq截图,要把图片内容存入剪贴板

HDC dcSave;
state = 1;
dcSave = CreateCompatibleDC(NULL);

TPoint c_point;
c_point.x = ((t_begin.x - t_end.x)>0)?t_end.x:t_begin.x;
c_point.y = ((t_begin.y - t_end.y)>0)?t_end.y:t_begin.y;


BITMAP bm;
HBITMAP bitmap;

GetObject(m_bmpScreen,sizeof(bm),&bm);
bm.bmWidth = width;
bm.bmHeight = height;
bitmap = CreateBitmapIndirect(&bm);



HBITMAP bit = (HBITMAP)SelectObject(dcSave,bitmap);

StretchBlt(dcSave,0,0, width,height,
m_dcMem,c_point.x ,c_point.y,
width, height, SRCCOPY);
SelectObject(dcSave,bit);
if(::OpenClipboard(this->Handle))
{
::EmptyClipboard();
::SetClipboardData(CF_BITMAP, bitmap);
::CloseClipboard();
}

 5  从剪贴板取数据

if(::OpenClipboard(handle))
{
bitmap = (HBITMAP)::GetClipboardData(CF_BITMAP);

::CloseClipboard();
return true;
}
6 存入本地 ,从剪贴板取得数据是HBITMAP,需要转化为TBitmap(保存本地有两种方法一种如下,两一种按照bmp的文件格式写文件)  

 Graphics::TBitmap *DrawBMP=new Graphics::TBitmap();
DrawBMP->Handle = bitmap;

DrawBMP->SaveToFile(filepath+".bmp");
delete DrawBMP;

  ps:上述工程在c++ builder2009中用,在VC++ 中函数一样,写法可能会不一样

  HBITMAP 是 bitmap的指针

  CBitmap 是是mfc中封装bitmap的类;

 BITMAP 是一个结构体,封装着bitmap的一些信息。定义了逻辑位图的高,宽,颜色格式和位值

 三者之间的转化

 

HBITMAP hBitmap;

CBitmap bitmap;

BITMAP bm;

//下面是三者之间的联系:

bitmap.Attach(hBitmap);//由HBITMAP 得到关联的CBitmap

bitmap.GetBitmap(&bm); // 由CBitmap 得到关联的BITMAP 
hBitmap=(HBITMAP)bitmap.GetSafeHandle();//由CBitmap得到相关的HBITMAP

工程地址(C++ builder ):点击打开链接

                    (MFC ): 点击打开链接