- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
图像采集源除了显示控件(上一篇《.NET 控件转图片》有介绍从界面控件转图片),更多的是窗口以及屏幕.
窗口截图最常用的方法是GDI,直接上Demo吧:
1 private void GdiCaptureButton_OnClick(object sender, RoutedEventArgs e) 2 { 3 var bitmap = CaptureScreen(); 4 CaptureImage.Source = ConvertBitmapToBitmapSource(bitmap); 5 } 6 /// <summary> 7 /// 截图屏幕 8 /// </summary> 9 /// <returns></returns> 10 public static Bitmap CaptureScreen() 11 { 12 IntPtr desktopWindow = GetDesktopWindow(); 13 //获取窗口位置大小 14 GetWindowRect(desktopWindow, out var lpRect); 15 return CaptureByGdi(desktopWindow, 0d, 0d, lpRect.Width, lpRect.Height); 16 } 17 private BitmapSource ConvertBitmapToBitmapSource(Bitmap bitmap) 18 { 19 using MemoryStream memoryStream = new MemoryStream(); 20 // 将 System.Drawing.Bitmap 保存到内存流中 21 bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png); 22 // 重置内存流的指针到开头 23 memoryStream.Seek(0, SeekOrigin.Begin); 24 25 // 创建 BitmapImage 对象并从内存流中加载图像 26 BitmapImage bitmapImage = new BitmapImage(); 27 bitmapImage.BeginInit(); 28 bitmapImage.StreamSource = memoryStream; 29 bitmapImage.CacheOption = BitmapCacheOption.OnLoad; 30 bitmapImage.EndInit(); 31 // 确保内存流不会被回收 32 bitmapImage.Freeze(); 33 return bitmapImage; 34 } 35 /// <summary> 36 /// 截图窗口/屏幕 37 /// </summary> 38 /// <param name="windowIntPtr">窗口句柄(窗口或者桌面)</param> 39 /// <param name="left">水平坐标</param> 40 /// <param name="top">竖直坐标</param> 41 /// <param name="width">宽度</param> 42 /// <param name="height">高度</param> 43 /// <returns></returns> 44 private static Bitmap CaptureByGdi(IntPtr windowIntPtr, double left, double top, double width, double height) 45 { 46 IntPtr windowDc = GetWindowDC(windowIntPtr); 47 IntPtr compatibleDc = CreateCompatibleDC(windowDc); 48 IntPtr compatibleBitmap = CreateCompatibleBitmap(windowDc, (int)width, (int)height); 49 IntPtr bitmapObj = SelectObject(compatibleDc, compatibleBitmap); 50 BitBlt(compatibleDc, 0, 0, (int)width, (int)height, windowDc, (int)left, (int)top, CopyPixelOperation.SourceCopy); 51 Bitmap bitmap = System.Drawing.Image.FromHbitmap(compatibleBitmap); 52 //释放 53 SelectObject(compatibleDc, bitmapObj); 54 DeleteObject(compatibleBitmap); 55 DeleteDC(compatibleDc); 56 ReleaseDC(windowIntPtr, windowDc); 57 return bitmap; 58 }
根据user32.dll下拿到的桌面信息-句柄获取桌面窗口的设备上下文,再以设备上下文分别创建内存设备上下文、设备位图句柄 。
1 BOOL BitBlt( 2 HDC hdcDest, // 目标设备上下文 3 int nXDest, // 目标起始x坐标 4 int nYDest, // 目标起始y坐标 5 int nWidth, // 宽度(像素) 6 int nHeight, // 高度(像素) 7 HDC hdcSrc, // 源设备上下文 8 int nXSrc, // 源起始x坐标 9 int nYSrc, // 源起始y坐标 10 DWORD dwRop // 操作码(如CopyPixelOperation.SourceCopy) 11 );
图像位块传输BitBlt是最关键的函数,Gdi提供用于在设备上下文之间进行位图块的传输,从原设备上下文复现位图到创建的设备上下文 。
另外,与Bitblt差不多的还有StretchBlt,StretchBlt也是复制图像,但可以同时对图像进行拉伸或者缩小,需要缩略图可以用这个方法 。
然后以设备位图句柄输出一个位图System.Drawing.Bitmap,使用到的User32、Gdi32函数:
1 /// <summary> 2 /// 获取桌面窗口 3 /// </summary> 4 /// <returns></returns> 5 [DllImport("user32.dll")] 6 public static extern IntPtr GetDesktopWindow(); 7 /// <summary> 8 /// 获取整个窗口的矩形区域 9 /// </summary> 10 /// <returns></returns> 11 [DllImport("user32.dll", SetLastError = true)] 12 public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); 13 /// <summary> 14 /// 检索整个窗口的设备上下文 15 /// </summary> 16 /// <param name="hWnd">具有要检索的设备上下文的窗口的句柄</param> 17 /// <returns></returns> 18 [DllImport("user32.dll", SetLastError = true)] 19 public static extern IntPtr GetWindowDC(IntPtr hWnd); 20 /// <summary> 21 /// 创建与指定设备兼容的内存设备上下文 22 /// </summary> 23 /// <param name="hdc">现有 DC 的句柄</param> 24 /// <returns>如果函数成功,则返回值是内存 DC 的句柄,否则返回Null</returns> 25 [DllImport("gdi32.dll")] 26 public static extern IntPtr CreateCompatibleDC([In] IntPtr hdc); 27 /// <summary> 28 /// 将对象选择到指定的设备上下文中 29 /// </summary> 30 /// <param name="hdc">DC 的句柄</param> 31 /// <param name="gdiObj">要选择的对象句柄</param> 32 /// <returns>如果函数成功,则返回值是兼容位图 (DDB) 的句柄,否则返回Null</returns> 33 [DllImport("gdi32.dll")] 34 public static extern IntPtr SelectObject([In] IntPtr hdc, [In] IntPtr gdiObj); 35 /// <summary> 36 /// 创建与与指定设备上下文关联的设备的位图 37 /// </summary> 38 /// <param name="hdc">设备上下文的句柄</param> 39 /// <param name="nWidth">位图宽度(以像素为单位)</param> 40 /// <param name="nHeight">位图高度(以像素为单位)</param> 41 /// <returns></returns> 42 [DllImport("gdi32.dll")] 43 public static extern IntPtr CreateCompatibleBitmap([In] IntPtr hdc, int nWidth, int nHeight); 44 /// <summary> 45 /// 执行与从指定源设备上下文到目标设备上下文中的像素矩形对应的颜色数据的位块传输 46 /// </summary> 47 /// <param name="hdcDest">目标设备上下文的句柄</param> 48 /// <param name="xDest">目标矩形左上角的 x 坐标(逻辑单位)</param> 49 /// <param name="yDest">目标矩形左上角的 y 坐标(逻辑单位)</param> 50 /// <param name="wDest">源矩形和目标矩形的宽度(逻辑单位)</param> 51 /// <param name="hDest">源矩形和目标矩形的高度(逻辑单位)</param> 52 /// <param name="hdcSource">源设备上下文的句柄</param> 53 /// <param name="xSrc">源矩形左上角的 x 坐标(逻辑单位)</param> 54 /// <param name="ySrc">源矩形左上角的 y 坐标(逻辑单位)</param> 55 /// <param name="rop">定义如何将源矩形的颜色数据与目标矩形的颜色数据相结合</param> 56 /// <returns></returns> 57 [DllImport("gdi32.dll")] 58 public static extern bool BitBlt(IntPtr hdcDest, 59 int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, 60 int xSrc, int ySrc, CopyPixelOperation rop); 61 /// <summary> 62 /// 删除逻辑笔、画笔、字体、位图、区域或调色板,释放与对象关联的所有系统资源。 63 /// 删除对象后,指定的句柄将不再有效。 64 /// </summary> 65 /// <param name="hObject"></param> 66 /// <returns></returns> 67 [DllImport("gdi32.dll")] 68 public static extern bool DeleteObject(IntPtr hObject); 69 /// <summary> 70 /// 删除指定的设备上下文 71 /// </summary> 72 /// <param name="hdc">设备上下文的句设备上下文的句</param> 73 /// <returns></returns> 74 [DllImport("gdi32.dll")] 75 public static extern bool DeleteDC([In] IntPtr hdc); 76 /// <summary> 77 /// 释放设备上下文 (DC),释放它以供其他应用程序使用 78 /// </summary> 79 /// <param name="hWnd"></param> 80 /// <param name="hdc"></param> 81 /// <returns></returns> 82 [DllImport("user32.dll", SetLastError = true)] 83 public static extern bool ReleaseDC(IntPtr hWnd, IntPtr hdc); 84 85 /// <summary> 86 /// 定义一个矩形区域。 87 /// </summary> 88 [StructLayout(LayoutKind.Sequential)] 89 public struct RECT 90 { 91 /// <summary> 92 /// 矩形左侧的X坐标。 93 /// </summary> 94 public int Left; 95 96 /// <summary> 97 /// 矩形顶部的Y坐标。 98 /// </summary> 99 public int Top; 100 101 /// <summary> 102 /// 矩形右侧的X坐标。 103 /// </summary> 104 public int Right; 105 106 /// <summary> 107 /// 矩形底部的Y坐标。 108 /// </summary> 109 public int Bottom; 110 111 /// <summary> 112 /// 获取矩形的宽度。 113 /// </summary> 114 public int Width => Right - Left; 115 116 /// <summary> 117 /// 获取矩形的高度。 118 /// </summary> 119 public int Height => Bottom - Top; 120 121 /// <summary> 122 /// 初始化一个新的矩形。 123 /// </summary> 124 /// <param name="left">矩形左侧的X坐标。</param> 125 /// <param name="top">矩形顶部的Y坐标。</param> 126 /// <param name="right">矩形右侧的X坐标。</param> 127 /// <param name="bottom">矩形底部的Y坐标。</param> 128 public RECT(int left, int top, int right, int bottom) 129 { 130 Left = left; 131 Top = top; 132 Right = right; 133 Bottom = bottom; 134 } 135 }
还有一种比较简单的方法Graphics.CopyFromScreen,看看调用DEMO:
1 private void GraphicsCaptureButton_OnClick(object sender, RoutedEventArgs e) 2 { 3 var image = CaptureScreen1(); 4 CaptureImage.Source = ConvertBitmapToBitmapSource(image); 5 } 6 /// <summary> 7 /// 截图屏幕 8 /// </summary> 9 /// <returns></returns> 10 public static Bitmap CaptureScreen1() 11 { 12 IntPtr desktopWindow = GetDesktopWindow(); 13 //获取窗口位置大小 14 GetWindowRect(desktopWindow, out var lpRect); 15 return CaptureScreenByGraphics(0, 0, lpRect.Width, lpRect.Height); 16 } 17 /// <summary> 18 /// 截图屏幕 19 /// </summary> 20 /// <param name="x">x坐标</param> 21 /// <param name="y">y坐标</param> 22 /// <param name="width">截取的宽度</param> 23 /// <param name="height">截取的高度</param> 24 /// <returns></returns> 25 public static Bitmap CaptureScreenByGraphics(int x, int y, int width, int height) 26 { 27 var bitmap = new Bitmap(width, height); 28 using var graphics = Graphics.FromImage(bitmap); 29 graphics.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height), CopyPixelOperation.SourceCopy); 30 return bitmap; 31 }
Graphics.CopyFromScreen调用简单了很多,与GDI有什么区别?
Graphics.CopyFromScreen内部也是通过GDI.BitBlt来完成屏幕捕获的,封装了下提供更高级别、易胜的API.
测试了下,第一种方法Gdi32性能比Graphics.CopyFromScreen性能略微好一点,冷启动时更明显点,试了2次耗时大概少个10多ms.
kybs00/CaptureImageDemo (github.com) 。
最后此篇关于.NET窗口/屏幕截图的文章就讲到这里了,如果你想了解更多关于.NET窗口/屏幕截图的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
创建使用.NET框架的asp.net页面时,访问该页面的客户端是否需要在其计算机上安装.NET框架? IE。用户访问www.fakesite.com/default.aspx,如果他们没有安装框架,他
我阅读了很多不同的博客和 StackOverflow 问题,试图找到我的问题的答案,但最后我找不到任何东西,所以我想自己问这个问题。 我正在构建一个应用程序,其中有一个长时间运行的工作线程,它执行一些
已锁定。这个问题及其答案是locked因为这个问题是题外话,但却具有历史意义。目前不接受新的答案或互动。 我一直想知道为什么微软为这样一个伟大的平台选择了一个如此奇怪的、对搜索引擎不友好的名称。他们就
.Net Framework .Net .NET Standard的区别 1、.NET Framework 在未来.NET Framework或许成为过去时,目前还是有很多地方在使用的。这一套
如果有选择的话,您会走哪条路? ASP.NET Webforms + ASP.NET AJAX 或 ASP.NET MVC + JavaScript Framework of your Choice
我有一个 Web 服务,它通过专用连接通过 https 使用第三方 Web 服务,我应用了 ServicePointManager.ServerCertificateValidationCallbac
为什么我应该选择ASP.NET Web Application (.NET Framework)而不是ASP.NET Core Web Application (.NET Framework)? 我在
我在网络上没有找到任何关于包含 .NET Standard、.NET Core 和 .NET Framework 项目的 .NET 解决方案的公认命名约定。 就我而言,我们在 .NET 框架项目中有以
.NET Compact 是 .NET 的完美子集吗? 假设我考虑了屏幕大小和其他限制并避免了 .NET Compact 不支持的类和方法,或者 .NET Compact 是一个不同且不兼容的 GUI
我已经阅读了所有我能找到的关于 connectionManagement 中的 maxconnection 设置的文章:即 http://support.microsoft.com/kb/821268
我现在正在使用asp.net mvc,想知道使用内置的Json或 Json.Net哪个是更好的选择,但我不确定一个人是否比另一个人有优势。 另外,如果我确实选择沿用Json.Net的路线,那么我应该选
在 Visual Studio 中,您至少可以创建三种不同类型的类库: 类库(.NET Framework) 类库(.NET 标准) 类库(.NET Core) 虽然第一个是我们多年来一直使用的,但我
.NET 和 ASP.NET 之间有什么区别?它们有什么关系? 最佳答案 ASP.Net 基于 .Net 框架构建,提供有关 Web 开发的附加功能。 你可以去看看wikipedia article
在安装更高版本(3.0)之前,我需要安装.net框架1.1和2.0吗?或者单独安装 3.0 框架就足够了,并为在早期框架版本上编写的软件提供支持?谢谢 ,丽然 最佳答案 不,您不必安装以前的框架。 我
我正在开发一个项目,人们可以“更新”类别,例如更改类别的名称。我收到以下消息 This is called after clicking update 按钮 with the SQL statemen
.NET 类 System.Net.CookieContainer 线程安全吗? --更新:交 key 答复-- 是否有任何方法可以确保异步请求期间修改的变量(即 HttpWebRequest.Coo
我正在使用 JScript.NET 在我编写的 C# WinForms 应用程序中编写脚本。它工作得很好,但我只是尝试在脚本中放置一些异常处理,但我无法弄清楚如何判断我的 C# 代码抛出了哪种类型的异
我需要你的帮助, 比如我有一个小数类型的变量,我想这样取整。 例如 3.0 = 3 3.1 = 4 3.2 = 4 3.3 = 4 3.4 = 4 3.5 = 4 3.6 = 4 3.7 = 4 3.
我使用过这样的代码:http://msdn.microsoft.com/en-us/library/dw70f090.aspx在 ASP.NET 中工作之前访问数据库(2-3 年前)。我没有意识到我正
自 ConfigurationManager .NET Standard 中不存在,检索正在执行的程序集的应用程序设置的最佳方法是什么,无论是 web.config或 appSettings.{env
我是一名优秀的程序员,十分优秀!