效果图:
源码:
http://files.cnblogs.com/xling/ScreenShot.zip
移动选区 调整大小 放大镜 通知观察者 热键
最近要实现一个从网页拖拽图片到应用的功能,发现不同浏览器的表现不一样,最省事的要数 FireFox ,直接拖图片,就可以得到指向本地缓存的 FileDrop 数据。IE(如果在“保护模式”下,需要写注册表),如果是直接拖图片的话,也可以得到 FileDrop, 但是如果图片在链接内,那就不一样了,还好,我写了一个BHO, 接合这个BHO ,也可以在拖拽链接内的图片的时候,获取到图片在本地缓存的地址。Chrome 就不行了,也没有进行深入的研究。
即然拖图片那么“辛苦”,那干脆换另外一种方式好了:屏幕截取。
这个小程序没有什么大的技术含量,就是GDI而以。以前用GDI就写过验证码,PHP、J2ME,甚到是 Objective-C 的到是写过,不过都忘完了。
其实就是从Image 内得到Graphics 对象,然后用 CopyFromScreen 方法,然后绘制到 Image 内, 然后将 Form 的 BackGroundImage 设为该 Image。
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),然后在绘制图片,这样就得到一个完美的圆形图片了。
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 内的函数
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 方法
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 里将它的生命周期设为单例。