当前位置:   article > 正文

wpf 控件自动截图和电脑屏幕截屏(支持网页控件、多显示器截图)_wpf 获取控件截图

wpf 获取控件截图

先看效果,后面附代码

1、自身界面截图:将截取主界面黄色框中的界面;截屏:将截取所有显示器的界面(黄色边框是为了验证截图是否精准,无偏移)

2、中间左边是个网页,右边为截图展示区

动图如下:

截图会受到系统显示设置的影响,如多个显示器,每个显示器的大小不一,每个显示器的缩放布局,以及哪个显示器为主显示器等影响。(我的电脑2显示器为主显示器,且两个显示器为左右放置上对齐,故电脑左上角的坐标为(-2560,0))

为了适应电脑的这些显示设置,请参考以下主要代码:

xaml没什么好说的(如有需要请评论留言或私信),直接上cs代码。

  • 主界面的后台代码如下:
  1. public partial class MainWindow : Window
  2. {
  3. public MainWindow()
  4. {
  5. InitializeComponent();
  6. }
  7. /// <summary>
  8. /// 单击自身界面截图按钮
  9. /// </summary>
  10. /// <param name="sender"></param>
  11. /// <param name="e"></param>
  12. private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
  13. {
  14. CreateBitmapFromVisual(this);
  15. }
  16. public void CreateBitmapFromVisual(Visual target)
  17. {
  18. if (target == null)
  19. {
  20. return;
  21. }
  22. // 获取指定控件的大小
  23. Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
  24. // var size = this.RenderSize;
  25. // 此窗体最小化或最大化之前获取的大小和窗口的位置
  26. var resort = this.RestoreBounds;
  27. resort.Width = bounds.Width;
  28. resort.Height = bounds.Height;
  29. BitmapSource caputredBmp;
  30. if (this.WindowState == WindowState.Maximized)
  31. {
  32. // 获取显示设置中主屏幕的缩放比例
  33. double dpixRatio = (double)PrimaryScreen.DpiX / (double)96;
  34. //double dpiyRatio = (double)PrimaryScreen.DpiY / (double)96;
  35. // 获取虚拟屏幕边界
  36. Rectangle rc = SystemInformation.VirtualScreen;
  37. // 坐标系转换统一,左上角坐标统一使用虚拟屏幕左上角坐标
  38. var a = this.PointFromScreen(new Point(rc.X, rc.Y));
  39. a.X *= dpixRatio;
  40. a.Y *= dpixRatio;
  41. resort.Width *= dpixRatio;
  42. resort.Height *= dpixRatio;
  43. resort.X = 0 - a.X + rc.X;
  44. resort.Y = 0 - a.Y + rc.Y;
  45. // 截图
  46. caputredBmp = CopyFromScreenSnapshotMaxWindow(resort);
  47. }
  48. else
  49. {
  50. // 去掉窗体边框的大小
  51. resort.X += 8;
  52. resort.Y += 30;
  53. // 截图
  54. caputredBmp = CopyFromScreenSnapshot(resort);
  55. }
  56. this.img.Source = caputredBmp;
  57. }
  58. private static BitmapSource CopyFromScreenSnapshot(Rect region)
  59. {
  60. var sourceRect = ToRectangle(region);
  61. Rectangle rc = SystemInformation.VirtualScreen;
  62. var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
  63. var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  64. var screenSnapshot = GetScreenSnapshot(sourceRect);
  65. using (Graphics g = Graphics.FromImage(bitmap))
  66. {
  67. sourceRect.X = 0;
  68. sourceRect.Y = 0;
  69. g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
  70. }
  71. return ToBitmapSource(bitmap);
  72. }
  73. /// <summary>
  74. /// 最大化使用该方法,由于调用前已经将坐标根据显示设置缩放比例设置过了,所以无需调用ToRectangle
  75. /// </summary>
  76. /// <param name="region"></param>
  77. /// <returns></returns>
  78. private static BitmapSource CopyFromScreenSnapshotMaxWindow(Rect region)
  79. {
  80. var sourceRect = new Rectangle((int)(region.X), (int)(region.Y), (int)(region.Width), (int)(region.Height)); ;
  81. Rectangle rc = SystemInformation.VirtualScreen;
  82. var destRect = new Rectangle(0, 0, sourceRect.Width, sourceRect.Height);
  83. var bitmap = new Bitmap(sourceRect.Width, sourceRect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  84. var screenSnapshot = GetScreenSnapshot(sourceRect);
  85. using (Graphics g = Graphics.FromImage(bitmap))
  86. {
  87. sourceRect.X = 0;
  88. sourceRect.Y = 0;
  89. g.DrawImage(screenSnapshot, destRect, sourceRect, GraphicsUnit.Pixel);
  90. }
  91. return ToBitmapSource(bitmap);
  92. }
  93. /// <summary>
  94. /// 获取屏幕快照
  95. /// </summary>
  96. /// <param name="region"></param>
  97. /// <returns></returns>
  98. public static Bitmap GetScreenSnapshot(Rectangle region)
  99. {
  100. try
  101. {
  102. Rectangle rc = SystemInformation.VirtualScreen;
  103. var bitmap = new Bitmap(rc.Width, rc.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
  104. using (Graphics memoryGrahics = Graphics.FromImage(bitmap))
  105. {
  106. memoryGrahics.CopyFromScreen((int)region.X, (int)region.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy);
  107. }
  108. return bitmap;
  109. }
  110. catch (Exception)
  111. {
  112. }
  113. return null;
  114. }
  115. public static BitmapSource ToBitmapSource(Bitmap bmp)
  116. {
  117. BitmapSource returnSource;
  118. try
  119. {
  120. returnSource = Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
  121. }
  122. catch
  123. {
  124. returnSource = null;
  125. }
  126. return returnSource;
  127. }
  128. static Rectangle ToRectangle(Rect rect)
  129. {
  130. // 获取显示设置中主屏幕的缩放比例
  131. double dpixRatio = (double)PrimaryScreen.DpiX / (double)96;
  132. return new Rectangle((int)(rect.X * dpixRatio), (int)(rect.Y * dpixRatio), (int)(rect.Width * dpixRatio), (int)(rect.Height * dpixRatio));
  133. }
  134. /// <summary>
  135. /// 单击截屏按钮
  136. /// </summary>
  137. /// <param name="sender"></param>
  138. /// <param name="e"></param>
  139. private void ButtonBase1_OnClick(object sender, RoutedEventArgs e)
  140. {
  141. // 获取虚拟屏幕的界限(包括左上角的坐标,长和高)
  142. Rectangle rc = SystemInformation.VirtualScreen;
  143. // 截全屏
  144. var caputredBmp = CopyFromScreenSnapshot(new Rect(rc.X, rc.Y, rc.Width, rc.Height));
  145. // 截图展示(img为界面截图展示的控件)
  146. this.img.Source = caputredBmp;
  147. }
  148. }
  • 辅助类PrimaryScreen代码如下:
  1. public class PrimaryScreen
  2. {
  3. #region Win32 API
  4. [DllImport("user32.dll")]
  5. static extern IntPtr GetDC(IntPtr ptr);
  6. [DllImport("gdi32.dll")]
  7. static extern int GetDeviceCaps(
  8. IntPtr hdc,
  9. // handle to DC
  10. int nIndex
  11. // index of capability
  12. );
  13. [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
  14. static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
  15. #endregion
  16. #region DeviceCaps常量
  17. const int HORZRES = 8;
  18. const int VERTRES = 10;
  19. const int LOGPIXELSX = 88;
  20. const int LOGPIXELSY = 90;
  21. const int DESKTOPVERTRES = 117;
  22. const int DESKTOPHORZRES = 118;
  23. #endregion
  24. #region 属性
  25. /// <summary>
  26. /// 获取屏幕分辨率当前物理大小
  27. /// </summary>
  28. public static Size WorkingArea
  29. {
  30. get
  31. {
  32. IntPtr hdc = GetDC(IntPtr.Zero);
  33. Size size = new Size();
  34. size.Width = GetDeviceCaps(hdc, HORZRES);
  35. size.Height = GetDeviceCaps(hdc, VERTRES);
  36. ReleaseDC(IntPtr.Zero, hdc);
  37. return size;
  38. }
  39. }
  40. /// <summary>
  41. /// 当前系统DPI_X 大小 一般为96
  42. /// </summary>
  43. public static int DpiX
  44. {
  45. get
  46. {
  47. IntPtr hdc = GetDC(IntPtr.Zero);
  48. int DpiX = GetDeviceCaps(hdc, LOGPIXELSX);
  49. ReleaseDC(IntPtr.Zero, hdc);
  50. return DpiX;
  51. }
  52. }
  53. /// <summary>
  54. /// 当前系统DPI_Y 大小 一般为96
  55. /// </summary>
  56. public static int DpiY
  57. {
  58. get
  59. {
  60. IntPtr hdc = GetDC(IntPtr.Zero);
  61. int DpiX = GetDeviceCaps(hdc, LOGPIXELSY);
  62. ReleaseDC(IntPtr.Zero, hdc);
  63. return DpiX;
  64. }
  65. }
  66. /// <summary>
  67. /// 获取真实设置的桌面分辨率大小
  68. /// </summary>
  69. public static Size DESKTOP
  70. {
  71. get
  72. {
  73. IntPtr hdc = GetDC(IntPtr.Zero);
  74. Size size = new Size();
  75. size.Width = GetDeviceCaps(hdc, DESKTOPHORZRES);
  76. size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES);
  77. ReleaseDC(IntPtr.Zero, hdc);
  78. return size;
  79. }
  80. }
  81. /// <summary>
  82. /// 获取宽度缩放百分比
  83. /// </summary>
  84. public static float ScaleX
  85. {
  86. get
  87. {
  88. IntPtr hdc = GetDC(IntPtr.Zero);
  89. int t = GetDeviceCaps(hdc, DESKTOPHORZRES);
  90. int d = GetDeviceCaps(hdc, HORZRES);
  91. float ScaleX = (float)GetDeviceCaps(hdc, DESKTOPHORZRES) / (float)GetDeviceCaps(hdc, HORZRES);
  92. ReleaseDC(IntPtr.Zero, hdc);
  93. return ScaleX;
  94. }
  95. }
  96. /// <summary>
  97. /// 获取高度缩放百分比
  98. /// </summary>
  99. public static float ScaleY
  100. {
  101. get
  102. {
  103. IntPtr hdc = GetDC(IntPtr.Zero);
  104. float ScaleY = (float)(float)GetDeviceCaps(hdc, DESKTOPVERTRES) / (float)GetDeviceCaps(hdc, VERTRES);
  105. ReleaseDC(IntPtr.Zero, hdc);
  106. return ScaleY;
  107. }
  108. }
  109. #endregion
  110. }
  • 添加应用程序清单文件app.manifest(PerMonitor当前进程设置为屏幕级 DPI 感知)
  1. <!-- 指示该应用程序可以感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
  2. 自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
  3. 选择加入。选择加入此设置的 Windows 窗体应用程序(目标设定为 .NET Framework 4.6 )还应
  4. 在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。-->
  5. <application xmlns="urn:schemas-microsoft-com:asm.v3">
  6. <windowsSettings>
  7. <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
  8. <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
  9. </windowsSettings>
  10. </application>

至此就可以实现多屏幕截图啦。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/139305
推荐阅读
相关标签
  

闽ICP备14008679号