截取桌面 C# (WPF) 的屏幕截图时出现延迟
Delay while taking Screenshot of Desktop C# (WPF)
我正在做一些截屏程序。它的功能与 Windows 的截图工具相同。用户通过在屏幕上绘制矩形来定义区域并拍摄。
我遵循了这个惊人的 tutorial,比如通过覆盖整个桌面来打开新的 window。然后我在 Window 上绘制矩形并在矩形内部拍摄。如果鼠标移动正常,屏幕截图是正确的。喜欢这张图片
但是,当鼠标移动得更快时,截屏错误,如下图所示。拍摄超出了矩形区域
这里是源代码:
public partial class CapturingArea : Window
{
public BitmapSource mTakenScreenShot;
private Point mStartPoint;
private Point mEndPoint;
private Rectangle mDrawRectangle;
public CapturingArea()
{
InitializeComponent();
InitMainWindow();
Mouse.OverrideCursor = Cursors.Cross;
mStartPoint = new Point();
mEndPoint = new Point();
}
/*Close Window by pressing ESC Button*/
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Mouse.OverrideCursor = Cursors.Arrow;
this.Close();
}
}
/*When Mouse is clicked
get the current point of Mouse and Start Drawing Rectangle on the Canvas*/
private void cnDrawingArea_MouseDown(object sender, MouseButtonEventArgs e)
{
if(mDrawRectangle != null)
this.cnDrawingArea.Children.Remove(mDrawRectangle);
mStartPoint = e.GetPosition(this);
mDrawRectangle = new Rectangle
{
Stroke = Brushes.Red,
StrokeThickness = 0.5
};
Canvas.SetLeft(mDrawRectangle, mStartPoint.X);
Canvas.SetTop(mDrawRectangle, mStartPoint.Y);
this.cnDrawingArea.Children.Add(mDrawRectangle);
}
/* Continue drawing Rectangle while Mouse is moving on the Canvas Area*/
private void cnDrawingArea_MouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Released)
{
return;
}
Point tmpPoint = e.GetPosition(this.cnDrawingArea);
int xPos = (int) Math.Min(tmpPoint.X, mStartPoint.X);
int yPos = (int) Math.Min(tmpPoint.Y, mStartPoint.Y);
int recWidth = (int) Math.Max(tmpPoint.X, mStartPoint.X) - xPos;
int recHeight = (int)Math.Max(tmpPoint.Y, mStartPoint.Y) - yPos;
mDrawRectangle.Width = recWidth;
mDrawRectangle.Height = recHeight;
Canvas.SetLeft(mDrawRectangle, xPos);
Canvas.SetTop(mDrawRectangle, yPos);
}
/*Initialize Window to cover whole screen*/
private void InitMainWindow()
{
this.WindowStyle = WindowStyle.None;
this.Title = string.Empty;
this.ShowInTaskbar = false;
this.AllowsTransparency = true;
this.Background = new SolidColorBrush(Color.FromArgb(0x10, 0x10, 0x10, 0x10));
// this.Topmost = true;
this.Left = SystemParameters.VirtualScreenLeft;
this.Top = SystemParameters.VirtualScreenTop;
this.Width = SystemParameters.VirtualScreenWidth;
this.Height = SystemParameters.VirtualScreenHeight;
}
/*First calculate Starting Ending points according to
mouse move and take screenshot*/
private void CaptureScreen(int X1, int Y1, int X2, int Y2)
{
int StartXPosition = 0;
int StartYPosition = 0;
int tmpWidth = 0;
int tmpHeight = 0;
if (X1 < X2 && Y1 < Y2) /*Drawing Left to Right*/
{
StartXPosition = X1;
StartYPosition = Y1;
tmpWidth = X2 - X1;
tmpHeight = Y2 - Y1;
}
else if(X1 > X2 && Y1 < Y2) /*Drawing Top to Down*/
{
StartXPosition = X2;
StartYPosition = Y1;
tmpWidth = X1 - X2;
tmpHeight = Y2 - Y1;
}
else if(X1 > X2 && Y1 > Y2) /*Drawing Down to Top*/
{
StartXPosition = X2;
StartYPosition = Y2;
tmpWidth = X1 - X2;
tmpHeight = Y1 - Y2;
}
else if(X1 < X2 && Y1 >Y2) /*Drawing Right to Left */
{
StartXPosition = X1;
StartYPosition = Y2;
tmpWidth = X2 - X1;
tmpHeight = Y1 - Y2;
}
StartXPosition += 2;
StartYPosition += 2;
tmpWidth -= 2;
tmpHeight -= 2;
mTakenScreenShot = ScreenCapture.CaptureRegion(StartXPosition, StartYPosition, tmpWidth, tmpHeight, false);
Mouse.OverrideCursor = Cursors.Arrow;
}
/*get the screenshot and by calculating real positions of Desktop*/
private void cnDrawingArea_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
{
mEndPoint = e.GetPosition(this.cnDrawingArea);
if (mDrawRectangle != null)
this.cnDrawingArea.Children.Remove(mDrawRectangle);
Point StartDesktopPosition = this.PointToScreen(mStartPoint);
Point EndDesktopPosition = this.PointToScreen(mEndPoint);
int tempX1 = (int)StartDesktopPosition.X;
int tempY1 = (int)StartDesktopPosition.Y;
int tempX2 = (int)EndDesktopPosition.X;
int tempY2 = (int)EndDesktopPosition.Y;
CaptureScreen(tempX1, tempY1, tempX2, tempY2);
this.DialogResult = true;
this.Close();
}
}
}
右移鼠标快速截屏有什么解决办法或建议吗
谢谢。
当鼠标移动非常快时,Windows 会将鼠标移动聚合到一条消息中,以免使任何程序因大量 WM_MOUSEMOVEs 而过载。您可以通过 Mouse.GetIntermediatePoints.
在 WPF 中获取这些中间点的列表
我怀疑你的问题是鼠标在最后一次移动和左键弹起之间在屏幕上快速移动,而你错过了一大堆中间点。
试试这个作为实验,同时在左按钮向上处理程序中绘制矩形。我相信这将使矩形与屏幕截图区域相匹配。如果您随后检查中间点,您可能会看到一堆移动数据排队。
为了解决这个问题,为什么不使用最后一次鼠标移动作为 mEndPoint 而不是在左键弹起处理程序中调用 GetPosition?这应该会给你正确的行为,因为它会准确反映你当前绘制矩形的方法。然后,无论中间移动如何,您将捕获矩形坐标本身,而不是左按钮向上位置形成的新矩形。
我正在做一些截屏程序。它的功能与 Windows 的截图工具相同。用户通过在屏幕上绘制矩形来定义区域并拍摄。
我遵循了这个惊人的 tutorial,比如通过覆盖整个桌面来打开新的 window。然后我在 Window 上绘制矩形并在矩形内部拍摄。如果鼠标移动正常,屏幕截图是正确的。喜欢这张图片
但是,当鼠标移动得更快时,截屏错误,如下图所示。拍摄超出了矩形区域
这里是源代码:
public partial class CapturingArea : Window
{
public BitmapSource mTakenScreenShot;
private Point mStartPoint;
private Point mEndPoint;
private Rectangle mDrawRectangle;
public CapturingArea()
{
InitializeComponent();
InitMainWindow();
Mouse.OverrideCursor = Cursors.Cross;
mStartPoint = new Point();
mEndPoint = new Point();
}
/*Close Window by pressing ESC Button*/
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
Mouse.OverrideCursor = Cursors.Arrow;
this.Close();
}
}
/*When Mouse is clicked
get the current point of Mouse and Start Drawing Rectangle on the Canvas*/
private void cnDrawingArea_MouseDown(object sender, MouseButtonEventArgs e)
{
if(mDrawRectangle != null)
this.cnDrawingArea.Children.Remove(mDrawRectangle);
mStartPoint = e.GetPosition(this);
mDrawRectangle = new Rectangle
{
Stroke = Brushes.Red,
StrokeThickness = 0.5
};
Canvas.SetLeft(mDrawRectangle, mStartPoint.X);
Canvas.SetTop(mDrawRectangle, mStartPoint.Y);
this.cnDrawingArea.Children.Add(mDrawRectangle);
}
/* Continue drawing Rectangle while Mouse is moving on the Canvas Area*/
private void cnDrawingArea_MouseMove(object sender, MouseEventArgs e)
{
if(e.LeftButton == MouseButtonState.Released)
{
return;
}
Point tmpPoint = e.GetPosition(this.cnDrawingArea);
int xPos = (int) Math.Min(tmpPoint.X, mStartPoint.X);
int yPos = (int) Math.Min(tmpPoint.Y, mStartPoint.Y);
int recWidth = (int) Math.Max(tmpPoint.X, mStartPoint.X) - xPos;
int recHeight = (int)Math.Max(tmpPoint.Y, mStartPoint.Y) - yPos;
mDrawRectangle.Width = recWidth;
mDrawRectangle.Height = recHeight;
Canvas.SetLeft(mDrawRectangle, xPos);
Canvas.SetTop(mDrawRectangle, yPos);
}
/*Initialize Window to cover whole screen*/
private void InitMainWindow()
{
this.WindowStyle = WindowStyle.None;
this.Title = string.Empty;
this.ShowInTaskbar = false;
this.AllowsTransparency = true;
this.Background = new SolidColorBrush(Color.FromArgb(0x10, 0x10, 0x10, 0x10));
// this.Topmost = true;
this.Left = SystemParameters.VirtualScreenLeft;
this.Top = SystemParameters.VirtualScreenTop;
this.Width = SystemParameters.VirtualScreenWidth;
this.Height = SystemParameters.VirtualScreenHeight;
}
/*First calculate Starting Ending points according to
mouse move and take screenshot*/
private void CaptureScreen(int X1, int Y1, int X2, int Y2)
{
int StartXPosition = 0;
int StartYPosition = 0;
int tmpWidth = 0;
int tmpHeight = 0;
if (X1 < X2 && Y1 < Y2) /*Drawing Left to Right*/
{
StartXPosition = X1;
StartYPosition = Y1;
tmpWidth = X2 - X1;
tmpHeight = Y2 - Y1;
}
else if(X1 > X2 && Y1 < Y2) /*Drawing Top to Down*/
{
StartXPosition = X2;
StartYPosition = Y1;
tmpWidth = X1 - X2;
tmpHeight = Y2 - Y1;
}
else if(X1 > X2 && Y1 > Y2) /*Drawing Down to Top*/
{
StartXPosition = X2;
StartYPosition = Y2;
tmpWidth = X1 - X2;
tmpHeight = Y1 - Y2;
}
else if(X1 < X2 && Y1 >Y2) /*Drawing Right to Left */
{
StartXPosition = X1;
StartYPosition = Y2;
tmpWidth = X2 - X1;
tmpHeight = Y1 - Y2;
}
StartXPosition += 2;
StartYPosition += 2;
tmpWidth -= 2;
tmpHeight -= 2;
mTakenScreenShot = ScreenCapture.CaptureRegion(StartXPosition, StartYPosition, tmpWidth, tmpHeight, false);
Mouse.OverrideCursor = Cursors.Arrow;
}
/*get the screenshot and by calculating real positions of Desktop*/
private void cnDrawingArea_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
{
mEndPoint = e.GetPosition(this.cnDrawingArea);
if (mDrawRectangle != null)
this.cnDrawingArea.Children.Remove(mDrawRectangle);
Point StartDesktopPosition = this.PointToScreen(mStartPoint);
Point EndDesktopPosition = this.PointToScreen(mEndPoint);
int tempX1 = (int)StartDesktopPosition.X;
int tempY1 = (int)StartDesktopPosition.Y;
int tempX2 = (int)EndDesktopPosition.X;
int tempY2 = (int)EndDesktopPosition.Y;
CaptureScreen(tempX1, tempY1, tempX2, tempY2);
this.DialogResult = true;
this.Close();
}
}
}
右移鼠标快速截屏有什么解决办法或建议吗
谢谢。
当鼠标移动非常快时,Windows 会将鼠标移动聚合到一条消息中,以免使任何程序因大量 WM_MOUSEMOVEs 而过载。您可以通过 Mouse.GetIntermediatePoints.
在 WPF 中获取这些中间点的列表我怀疑你的问题是鼠标在最后一次移动和左键弹起之间在屏幕上快速移动,而你错过了一大堆中间点。
试试这个作为实验,同时在左按钮向上处理程序中绘制矩形。我相信这将使矩形与屏幕截图区域相匹配。如果您随后检查中间点,您可能会看到一堆移动数据排队。
为了解决这个问题,为什么不使用最后一次鼠标移动作为 mEndPoint 而不是在左键弹起处理程序中调用 GetPosition?这应该会给你正确的行为,因为它会准确反映你当前绘制矩形的方法。然后,无论中间移动如何,您将捕获矩形坐标本身,而不是左按钮向上位置形成的新矩形。