cc

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  38 随笔 :: 14 文章 :: 21 评论 :: 0 Trackbacks
最近在尝试为软件增加截取屏幕的功能,为此学习了System.Drawing命名空间的Graphics、Image、Bitmap等GDI+类,这些类都很方便使用。但是它们大多都是对原有GDI API的封装,也增加了一些新的东西;不过封装得并不彻底,有些功能还是需要调用GDI API才能实现。我武断的认为Image、Bitmap、Metafile跟HBITMAP对应,Graphics跟HDC对应。

    在GDI+中,我们可以很方便的用Graphics.FromImage方法来操作Image中的内容,并将其保存回图片文件。那么,我们怎么才能保存Graphics到图片文件呢?创建一个Bitmap对象,复制Graphics g1的内容到Bitmap的Graphics g2,然后保存Bitmap对象到文件。复制过程我们必须通过PINVOKE调用BitBlt函数来实现。下面是该函数的声明:

[DllImport("gdi32.dll", CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
public static extern int BitBlt(HandleRef hDC, int x, int y, int nWidth, int nHeight, HandleRef hSrcDC, int xSrc, int ySrc, int dwRop);
参数中的各种DC可以用Graphics.GetHdc得到;最后一个参数光栅操作码很多,截取屏幕用的SRCCOPY值是0xcc0020,完整的光栅操作码可以查看MSDN的“Ternary Raster Operations”部分。

示例代码如下:

//这里假设要保存一个窗体的内容

int width=800;     //获取宽度

int height=600;     //获取高度

const int SRCCOPY=0xcc0020;     //复制图块的光栅操作码

Bitmap bmSave=new Bitmap(width,height);     //用于保存图片的位图对象

Graphics gSave=Graphics.FromImage(bmSave);     //创建该位图的Graphics对象

HandleRef hDcSave=new HandleRef(null,gSave.GetHdc());     //得到句柄

Graphics gSrc=formMain.CreateGraphics();     //创建窗体的Graphics对象

HandleRef hDcSrc=new HandleRef(null,gSrc.GetHdc());

BitBlt(hDcSave,0,0,width,height,hDcSrc,0,0,SRCCOPY);

gSrc.ReleaseHdc();

gSave.ReleaseHdc();

bmSave.Save(@"C:\test.bmp");

gSrc.Dispose();

gSave.Dispose();

bmSave.Dispose();

 

 关于Graphics.CopyFromScreen方法

     该方法在内部其实也使用BitBlt来进行图块复制,但是它只是固定的复制屏幕的内容,我们不能指定复制的源。

如果您需要截取屏幕的内容,可以使用以下代码:

int screenWidth=System.Windows.Forms.SystemInformation.VirtualScreen.Width;     //屏幕宽度

int screenHeight=System.Windows.Forms.SystemInformation.VirtualScreen.Height;     //屏幕高度

Bitmap bmSave=new Bitmap(screenWidth,screenHeight);

Graphics g=Graphics.FromImage(bmSave);

g.CopyFromScreen(0,0,0,0,new Size(screenWidth,screenHeight),CopyPixelOperation.SourceCopy);

bmSave.Save(@"C:\test.bmp");

g.Dispose();

bmSave.Dispose();

 

如果需要复制顶层窗体的可见部分,也可以使用Graphics.CopyFromScreen,但是需要用PointToScreen方法先得到屏幕坐标。

如果需要复制任意的窗体或者控件,先用Control.Handle得到控件句柄,然后再用GetDC()函数得到HDC,再用BitBlt进行图块复制。

posted on 2009-11-30 17:44 醒目西西 阅读(2177) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理