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

2021-03-23 00:26

阅读:354

? ? 最近做一个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


评论


亲,登录后才可以留言!