用C# 实现屏幕抓图

效果图:

用C# 实现屏幕抓图

 源码:

http://files.cnblogs.com/xling/ScreenShot.zip

功能:

移动选区 调整大小 放大镜 通知观察者 热键

 

为什么要做这个小工具?

最近要实现一个从网页拖拽图片到应用的功能,发现不同浏览器的表现不一样,最省事的要数 FireFox ,直接拖图片,就可以得到指向本地缓存的 FileDrop 数据。IE(如果在“保护模式”下,需要写注册表),如果是直接拖图片的话,也可以得到 FileDrop, 但是如果图片在链接内,那就不一样了,还好,我写了一个BHO, 接合这个BHO ,也可以在拖拽链接内的图片的时候,获取到图片在本地缓存的地址。Chrome 就不行了,也没有进行深入的研究。

 

即然拖图片那么“辛苦”,那干脆换另外一种方式好了:屏幕截取。

这个小程序没有什么大的技术含量,就是GDI而以。以前用GDI就写过验证码,PHP、J2ME,甚到是 Objective-C 的到是写过,不过都忘完了。

 

Copy 屏幕

其实就是从Image 内得到Graphics 对象,然后用 CopyFromScreen 方法,然后绘制到 Image 内, 然后将 Form 的 BackGroundImage 设为该 Image。

View Code
1 Screen sc = Screen.PrimaryScreen;

2 this.ScreenShortImg = new Bitmap(sc.Bounds.Width , sc.Bounds.Height);

3 Graphics g = Graphics.FromImage(this.ScreenShortImg);

4 g.CopyFromScreen(Point.Empty , Point.Empty , sc.Bounds.Size);

5 g.DrawImage(this.ScreenShortImg , Point.Empty);

6 this.BackgroundImage = this.ScreenShortImg;

确定选区

确定选区中包括选择选区,移动选区,调整选区大小,过程不是太复杂。但是过程很繁琐。

在绘制圆形放大镜的时候,一开始我想用TextureBrush, 但是效果让我大吃惊。后来尝试构造一个矩形内套圆形的 Path, 将 Path 内填充黑色,然后绘制到图片上,在将图片的透明色设为黑色,效果还行,但是图中的黑色都变成透明的了。

 

最终还是用的矩形内套圆形的 Path, 不过不是填充黑色,而是得到图片的 Graphics, 将该 Path 的区域排除掉(ExcludeClip),然后在绘制图片,这样就得到一个完美的圆形图片了。

View Code
 1 imgG.Clear(Color.Transparent);

 2  

 3 #region 图片显示在圆形中

 4 var imgRect = new Rectangle(0 , 0 , this.ZoomRect.Width , this.ZoomRect.Height);

 5 using(var path = new GraphicsPath()) {

 6     path.AddRectangle(imgRect);

 7     path.AddEllipse(imgRect);

 8     using(System.Drawing.Region reg = new System.Drawing.Region(path)) {

 9         imgG.ExcludeClip(reg);

10     }

11 }

12 #endregion

13  

14 imgG.DrawImage(img2 ,

15     new Rectangle(Point.Empty , img.Size) ,

16     new Rectangle((img2.Width - img.Width) / 2 , (img2.Height - img.Height) / 2 , img.Width , img.Height) ,

17     GraphicsUnit.Pixel);

处理放大效果的时候,其实是从原图上新建一个新图,并放大尺寸,然后从新图的中间在取和原图一样大小的图片出来,赋给原图,绘制到放大镜内。这部份的代码比较多,有兴趣的话,可以参考源码。

 

Graphics.DrawImage方法的第一个参数 Image ,MSDN里解释的“不大清楚”,我一开始当成这个参数是“要绘制到”的图片,结果弄出来的图一片黑乎乎,在仔细看,才知道它是源图片,要 “取它的数据” 到 “要绘制到的图片”。

 

注册热键

注册热键,要用到 user32.dll 内的函数

View Code
 1     static class NativeMethods {

 2         [DllImport("user32")]

 3         internal static extern bool RegisterHotKey(IntPtr hWnd , int id , uint control , Keys vk);

 4 

 5         [DllImport("user32")]

 6         internal static extern bool UnregisterHotKey(IntPtr hWnd , int id);

 7 }

 8 

 9 。。。

10 。。。

11 if(!NativeMethods.RegisterHotKey(this.Handle , 100 , 0 , Keys.PrintScreen)) {

12 。。。

13 。。。

100 是热键的 ID, 0 的取值可以在网上查到:

None = 0x0,
Alt = 0x1,
Ctrl = 0x2,
Shift = 0x4,
WindowsKey = 0x8

响应热键

要重写 Form 的 WndProc 方法

View Code
1         protected override void WndProc(ref Message m) {

2             if(m.Msg == 0X312 && m.WParam.ToString() == "100") {

3                 this.Launch();

4             }

5             base.WndProc(ref m);

6         }

0x312 是快捷键消息的ID,100 是上面注册的热键的ID

最后,这个东西应该是单例的,但是我没有这样写,而是在 IoC 里将它的生命周期设为单例。

你可能感兴趣的:(C#)