c# wpf 利用截屏键实现截屏功能

简介: 原文:c# wpf 利用截屏键实现截屏功能     最近做一个wpf程序需要截图功能,查找资料费了一些曲折,跟大家分享一下。
原文: 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

目录
相关文章
|
8天前
|
C#
【C#】 如何实现文本框历史记录提示功能
【C#】 如何实现文本框历史记录提示功能
18 0
|
4月前
|
监控 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK获取每张图像的微秒时间和FrameID功能(C#)
50 0
|
4月前
|
数据采集 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用ForceIP强制修改网口IP功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用ForceIP强制修改网口IP功能(C#)
30 0
|
4月前
|
安全 API 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用短曝光功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用短曝光功能(C#)
37 0
|
4月前
|
编解码 监控 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用Binning像素合并功能(C#)
19 0
|
4月前
|
存储 编解码 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用UserSet功能保存和载入相机的各类参数(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK使用UserSet功能保存和载入相机的各类参数(C#)
38 0
|
6月前
|
JavaScript 前端开发 Java
javascript实现像java、c#之类的sleep暂停的函数功能
javascript实现像java、c#之类的sleep暂停的函数功能
41 0
|
4月前
|
存储 数据管理 开发工具
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)
Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)
28 0
|
4月前
|
编解码 监控 开发工具
Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的图像剪切(ROI)功能(C#)
Baumer工业相机堡盟工业相机如何通过BGAPI SDK设置相机的图像剪切(ROI)功能(C#)
33 0
|
2月前
|
数据挖掘 C# 开发工具
采用C#语言开发的全套医院体检系统PEIS源码功能介绍
体检系统,是专为体检中心/医院体检科等体检机构,专门开发的全流程管理系统,通过软件实现检测仪器数据自动提取,内置多级医生工作台,细化工作将体检检查结果汇总,生成体检报告登记到计算机系统中。通过软件系统进行数据分析统计与评判以及建立体检相关的体检档案。从而实现体检流程的信息化,提高工作效率,减少手动结果录入的一些常犯错误。 在实际应用中,医院体检系统能够解决传统体检中手工操作带来的问题,如工作量大、效率低下、易漏检、重检或错检等。通过与医院信息系统(如HIS、LIS、PACS等)的连接,系统能够满足体检中心的日常工作流程,提供更好的管理、统计和查询分析功能。同时,基于网络基础的系统可以在网上传输
28 1