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
c# wpf 利用截屏键实现截屏功能的更多相关文章
- VB用API模拟截屏键PrintScreen
很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...
- Android滚动截屏,ScrollView截屏
在做分享功能的时候,需要截取全屏内容,一屏展示不完的内容,一般我们会用到 ListView 或 ScrollView 一: 普通截屏的实现 获取当前Window 的 DrawingCache 的方式, ...
- C#在截屏时将截屏之前需要隐藏的控件也截入
最近我在项目中遇到一个让我十分头疼的问题,就是我在截屏时也将截屏之前隐藏的控件也截入了. 情况:我在Winform窗体有个截屏功能按钮,实现在调用WPF全屏后截屏,但在截屏WPF界面前将界面里的一个L ...
- iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏)
iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏) 2017.03.16 12:18* 字数 52 阅读 563评论 4喜欢 2 1. 截取屏幕尺寸大小的图片并保存至相册 ...
- WPF利用动画实现圆形进度条
原文:WPF利用动画实现圆形进度条 这是我的第一篇随笔,最近因为工作需要,开始学习WPF相关技术,自己想实现以下圆形进度条的效果,逛了园子发现基本都是很久以前的文章,实现方式一般都是GDI实现的,想到 ...
- WPF利用通过父控件属性来获得绑定数据源RelativeSource
WPF利用通过父控件属性来获得绑定数据源RelativeSource 有时候我们不确定作为数据源的对象叫什么名字,但知道作为绑定源与UI布局有相对的关系,如下是一段XAML代码,说明多层布局控件中 ...
- WPF利用radiobutton制作菜单按钮
原文:WPF利用radiobutton制作菜单按钮 版权声明:欢迎转载.转载请注明出处,谢谢 https://blog.csdn.net/wzcool273509239/article/details ...
- WPF利用HelixToolKit后台导入3D模型
原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/de ...
- WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象
原文:WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象 简介 本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数 ...
随机推荐
- 【Lucene4.8教程之二】索引 2014-06-16 11:30 3845人阅读 评论(0) 收藏
一.基础内容 0.官方文档说明 (1)org.apache.lucene.index provides two primary classes: IndexWriter, which creates ...
- php实现把二叉树打印成多行(谋而后动,写好算法思路,不然浪费超多时间而且还是错误代码,而且精力消耗会导致代码正确率下降以及低级错误)
php实现把二叉树打印成多行(谋而后动,写好算法思路,不然浪费超多时间而且还是错误代码,而且精力消耗会导致代码正确率下降以及低级错误) 一.总结 要点:a.层次遍历(队列) b.层次遍历中的层次(孩 ...
- centos7安装nginx的两种方法
第一种方式:通过yum安装 直接通过 yum install nginx 肯定是不行的,因为yum没有nginx,所以首先把 nginx 的源加入 yum 中 运行下面的命令: 1.将nginx放到y ...
- Annotation研究的一些学习资料
转自chanyinhelv原文Annotation研究的一些学习资料 下面是我最近对Annotation研究的一些学习资料,收集于此,供大家学习之用. 一.Annotation要素类介绍 在GeoDa ...
- 关于如何在Sublime下安装插件
安装插件的两种方式 通过Package Control安装 不能安装 手工安装 安装插件的两种方式 在sublime下安装插件有两种方式,一种是通过package control来进行安装,另一种呢就 ...
- 在向server发送请求时发生传输级错误。 (provider: 共享内存提供程序, error: 0 - 管道的还有一端上无不论什么进程。
作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/36425825 SQL Server 2008 + VS2010 用C#编写的代 ...
- NOIP模拟 poke - 贪心
题目大意: 给一副牌(\(n \le 1000000, a_i \le 1000000\)),问最多能打出多少对对子(x, x)或者顺子(x, x + 1, x + 2). 题目分析: 感觉跟斗地主很 ...
- 【u235】背单词
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 英语四级考试临近了,小Y却发现他已经把以前学的单词几乎忘光了.好在现在离考试还有一段时间,小Y决定从现 ...
- DirectX11学习笔记
一.假定每种颜色的原始点是不同,表面的这样的原始颜色将被指定为每种颜色用线性内插值传授,这个被称为高洛德着色(Gouraud Shading).也称为平滑阴影: 二.三维图元:Direct3D中.使用 ...
- cxf maven 依赖 No message body writer foud.. contenttype:application/json
最近使用cxf发布rest服务时遇到了如题的异常,最后发现是缺少依赖的问题.ps:我并没有使用spring cxf基本运行需要如下依赖 1 <dependency> <groupId ...