c# wpf 利用截屏键实现截屏功能
最近做一个wpf程序需要截图功能,查找资料费了一些曲折,跟大家分享一下。
先是找到了这样一份代码:
static class ScreenCut
{
public static System.Drawing.Bitmap GetScreenSnapshot()
{
System.Drawing.Rectangle rc = System.Windows.Forms.SystemInformation.VirtualScreen;
System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.CopyFromScreen(rc.X, rc.Y, 0, 0, rc.Size, System.Drawing.CopyPixelOperation.SourceCopy);
}
return bitmap;
}
public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap bmp)
{
BitmapSource returnSource;
try
{
returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
catch
{
returnSource = null;
}
return returnSource;
}
public static BitmapSource CopyFromScreenSnapshot(BitmapSource screenSnapshot, Rect region)
{
var sourceRect = new System.Drawing.Rectangle((int)region.Left, (int)region.Top, (int)region.Width, (int)region.Height);
var destRect = new System.Drawing.Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
if (screenSnapshot != null)
{
var bitmap = new System.Drawing.Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap))
{
g.DrawImage(bitmap, destRect, sourceRect.Left, sourceRect.Top, sourceRect.Width, sourceRect.Height, System.Drawing.GraphicsUnit.Pixel);
}
return bitmap.ToBitmapSource();
}
return null;
}
}
调用时包装一下,下面的函数截下屏幕指定区域并保存:
System.Drawing.Image takePicture(Rect wnd, String saveLocation, String pictureName)
{
BitmapSource bitmapScr = ScreenCut.CopyFromScreenSnapshot(ScreenCut.ToBitmapSource(ScreenCut.GetScreenSnapshot()),wnd);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmapScr));
FileStream fileStream = new FileStream(saveLocation + "\\" + pictureName ".png", FileMode.Create, FileAccess.Write);
encoder.Save(fileStream);
fileStream.Close();
}
但实际效果保存下来的图是空的,经验证前两个函数没有问题。于是我查资料找到了另一种切割BitmapSource的方法,将第三个函数改成这样:
BitmapSource CopyFromScreenSnapshot(BitmapSource screenSnapshot, Rect region)
{
Int32Rect window = new Int32Rect(region.X, region.Y, region.Width, region.Height);
BitmapSource bitmapScr = ScreenCut.ToBitmapSource(ScreenCut.GetScreenSnapshot());
//计算Stride
int stride = bitmapScr.Format.BitsPerPixel * window.Width / 8;
//声明字节数组
byte[] data = new byte[window.Height * stride];
//调用CopyPixels
bitmapScr.CopyPixels(window, data, stride, 0);
PngBitmapEncoder encoder = new PngBitmapEncoder();
return BitmapSource.Create(window.Width, window.Height, 0, 0, PixelFormats.Bgr32, null, data, stride);
}
这样总算能截到屏了。不过后来发现在某些主题下有些程序的窗口在截下的图中是透明的。这个方法还是不够完美。
我想到了利用键盘的截屏键截图再进行剪切的方法。分为三步:1、模拟按下截屏键 2、从剪贴板获取图片 3、截取和保存图片。
对于第一点,利用SendMessage函数发送WM_KEY事件没有用,不过我找到了另一个模拟键盘输入的方法:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern void keybd_event
(
byte bVk,// 虚拟键值
byte bScan,// 硬件扫描码
uint dwFlags,// 动作标识
IntPtr dwExtraInfo// 与键盘动作关联的辅加信息
);
上面这个函数对本程序发送按钮事件,模拟截屏键的话像下面这样写,wpf需要在项目添加引用System.Windows.Forms
const int VK_SNAPSHOT = 0x2C;
public void PrintScreen()
{
keybd_event((byte)VK_SNAPSHOT, 0, 0x0, IntPtr.Zero);//down
System.Windows.Forms.Application.DoEvents();//强制窗口响应按钮事件
keybd_event((byte)VK_SNAPSHOT, 0, 0x2, IntPtr.Zero);//up
System.Windows.Forms.Application.DoEvents();
}
接下来从剪贴板获取图片,wpf需要在项目添加引用System.Windows.Forms System.Drawing
if (System.Windows.Forms.Clipboard.ContainsImage())
{
System.Drawing.Image image = System.Windows.Forms.Clipboard.GetImage();
}
然后剪切。
System.Drawing.Image cutPicture(System.Drawing.Image image, Int32Rect window)
{
PrintScreen();
if (window.X + window.Width > image.Width)
window.Width = image.Width - window.X;
if (window.Y + window.Height > image.Height)
window.Height = image.Height - window.Y;
if (image == null)
{
//新建一个bmp图片
System.Drawing.Image bitmap = new System.Drawing.Bitmap(window.Width, window.Height);
//新建一个画板
System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmap);
//设置高质量查值法
graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
//设置高质量,低速度呈现平滑程度
graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
//清空画布并以透明背景色填充
graphic.Clear(System.Drawing.Color.Transparent);
//在指定位置并且按指定大小绘制原图片的指定部分
graphic.DrawImage(image, new System.Drawing.Rectangle(0, 0, window.Width, window.Height), new System.Drawing.Rectangle(window.X, window.Y, window.Width, window.Height), System.Drawing.GraphicsUnit.Pixel);
return bitmap;
}
else
{
return null;
}
}
最后包装一下
System.Drawing.Image cutScreen(Int32Rect window)
{
PrintScreen();
Thread.Sleep(1000);
if (System.Windows.Forms.Clipboard.ContainsImage())
{
System.Drawing.Image image = cutPicture(System.Windows.Forms.Clipboard.GetImage(), Int32Rect window);
return image;
}
else
{
Console.WriteLine("clipboard doesn't contain picture");
return null;
}
}
System.Drawing.Image类有实例函数Save,保存很简单,就不细说了。
资料来源:
http://www.cnblogs.com/zhouyinhui/archive/2010/08/20/1804762.html
https://www.mgenware.com/blog/?p=285
http://blog.csdn.net/testcs_dn/article/details/39762017

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
C# 获取utc时间,以及utc datetime 互相转化
原文: C# 获取utc时间,以及utc datetime 互相转化 C# 获取utc时间,以及utc datetime 互相转化 大部分源于http://blog.sina.com.cn/s/blog_4c6e822d0102dsdz.html 刚开始学习一点C#知识,研究一下UTC时间获取,如下 DateTime dt = DateTime.UtcNow; 另: DateTime.UtcNow.ToString()输出的是0时区的事件, DateTime.Now.ToString()输出的是当前时区的时间,我们中国使用的是东八区的时间,所以差8个小时 以下是互相转换class class utc { public static int ConvertDateTimeInt(System.DateTime time) { double intResult = 0; System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1)); in...
- 下一篇
wpf C# 操作DirectUI窗口 SendMessage+MSAA
原文: wpf C# 操作DirectUI窗口 SendMessage+MSAA 最近做一个抓取qq用户资料的工具,需要获取qq窗口上的消息,以前这种任务是用句柄获取窗口中的信息,现在qq的窗口用的是DirectUI,只有窗口句柄,没有控件句柄,句柄这条路走不通了。不过较新版的qq的部分控件实现了微软的IAccessible接口(称为Microsoft Active Accessibility技术,简称MSAA),可以用另一套函数获取qq窗口的信息。不过要对窗口进行输入还是要靠句柄,上面说过,DirectUI的窗口只有一个句柄,因此模拟输入的时候不需要查找到具体的控件句柄,但要注意获取控件焦点,可能相对传统WinForm的窗口要简单点。 先介绍下和句柄操作相关的函数: usingSystem.Runtime.InteropServices; [DllImport("user32.dll", SetLastError =true)] staticexternIntPtrFindWindow(stringlpClassName,stringlpWindowName); 根据类名和...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Windows10,CentOS7,CentOS8安装Nodejs环境
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- CentOS8编译安装MySQL8.0.19
- CentOS关闭SELinux安全模块
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Red5直播服务器,属于Java语言的直播服务器