原文: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 利用截屏键实现截屏功能的更多相关文章

  1. VB用API模拟截屏键PrintScreen

    很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...

  2. Android滚动截屏,ScrollView截屏

    在做分享功能的时候,需要截取全屏内容,一屏展示不完的内容,一般我们会用到 ListView 或 ScrollView 一: 普通截屏的实现 获取当前Window 的 DrawingCache 的方式, ...

  3. C#在截屏时将截屏之前需要隐藏的控件也截入

    最近我在项目中遇到一个让我十分头疼的问题,就是我在截屏时也将截屏之前隐藏的控件也截入了. 情况:我在Winform窗体有个截屏功能按钮,实现在调用WPF全屏后截屏,但在截屏WPF界面前将界面里的一个L ...

  4. iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏)

    iOS中的截屏(屏幕截屏及scrollView或tableView的全部截屏) 2017.03.16 12:18* 字数 52 阅读 563评论 4喜欢 2 1. 截取屏幕尺寸大小的图片并保存至相册 ...

  5. WPF利用动画实现圆形进度条

    原文:WPF利用动画实现圆形进度条 这是我的第一篇随笔,最近因为工作需要,开始学习WPF相关技术,自己想实现以下圆形进度条的效果,逛了园子发现基本都是很久以前的文章,实现方式一般都是GDI实现的,想到 ...

  6. WPF利用通过父控件属性来获得绑定数据源RelativeSource

    WPF利用通过父控件属性来获得绑定数据源RelativeSource   有时候我们不确定作为数据源的对象叫什么名字,但知道作为绑定源与UI布局有相对的关系,如下是一段XAML代码,说明多层布局控件中 ...

  7. WPF利用radiobutton制作菜单按钮

    原文:WPF利用radiobutton制作菜单按钮 版权声明:欢迎转载.转载请注明出处,谢谢 https://blog.csdn.net/wzcool273509239/article/details ...

  8. WPF利用HelixToolKit后台导入3D模型

    原文:WPF利用HelixToolKit后台导入3D模型 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/m0_37591671/article/de ...

  9. WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象

    原文:WPF利用VisualTreeHelper遍历寻找对象的子级对象或者父级对象 简介 本文将完整叙述我利用VisualTreeHelper实现题述功能的全部过程,想直接看函数实现的朋友可以跳到函数 ...

随机推荐

  1. Access Violations 访问冲突(AVs)是Windows编程时发生的最麻烦的错误?

    Access Violations<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office&qu ...

  2. php课程 5-19 php数据结构函数和常用函数有哪些

    php课程 5-19 php数据结构函数和常用函数有哪些 一.总结 一句话总结: 1.php数据结构函数有哪些(四个)? • array_pop();从最后弹出一个值,返回弹出值• array_pus ...

  3. 以Network Dataset(网络数据集)方式实现的最短路径分析

    转自原文 以Network Dataset(网络数据集)方式实现的最短路径分析 构建网络有两种方式,分别是网络数据集NetworkDataset和几何网络Geometric Network,这个网络结 ...

  4. 简洁常用权限系统的设计与实现(五):不维护节点的深度level,手动计算level,构造树

     这种方式,与第三篇中介绍的类似.不同的是,数据库中不存储节点的深度level,增加和修改时,也不用维护.而是,在程序中,实时去计算的. 至于后面的,按照level升序排序,再迭代所有的节点构造树,与 ...

  5. python 多线程拷贝单个文件

    # -*- coding: utf-8 -*- # @author: Tele # @Time : 2019/04/04 下午 12:25 # 多线程方式拷贝单个文件 import threading ...

  6. System.getProperty()获取系统的配置信息(系统变量)

    原文地址:http://www.jsjtt.com/java/Javajichu/105.html 此处记录备用. 1. 通过System.getProperty()可以获取系统的配置信息,Syste ...

  7. centos 软件安装的三种方式

    Linux下面安装软件的常见方法: 1.yum 替你下载软件 替你安装 替你解决依赖关系 点外卖 缺少的东西 外卖解决 1).方便 简单2)没有办法深入修改 yum install -y tree 2 ...

  8. python request爬取百度贴吧

    import requests import os import shutil import time class PostBarSpider(object): def __init__(self, ...

  9. KDE 邀请用户测试 Plasma Mobile 的首个专用 ISO 镜像(可以考虑做一个极客。。。)

    KDE 项目依旧在继续改进智能手机.平板电脑和其他移动设备的 Plasma Mobile 用户界面,并于近日发布了一个 ISO 镜像,邀请社区的尝鲜用户进行测试. 他们曾承诺在 2018 年年底之前, ...

  10. 多线程下使用使用 UniDAC+MSSQL 需要注意的问题(使用CoInitialize)

    ADO线程不安全,UniDAC 在使用MSSQL也是如此.其实这是微软COM问题,不怪Devart公司. 一般解决方法是在线程开始启用 CoInitialize(nil),线程结束调用 CoUnini ...