使用桌面C#(WPF)截图时延迟

时间:2016-06-16 08:43:42

标签: c# wpf screenshot gdi

我正在做一些程序来截取屏幕截图。它的功能与Windows的Snipping Tool相同。用户通过在屏幕上绘制矩形来定义区域并进行拍摄。

我跟着这个惊人的tutorial,就像覆盖整个桌面打开新窗口一样。然后我在Window上绘制矩形并在矩形内部拍摄。如果正常移动鼠标,则会正确截取屏幕截图。喜欢这张图片

enter image description here

但是,当鼠标移动得更快时,截图不正确,如下图所示。拍摄是从矩形区域拍摄的

Shot is taken out of rectangle area

这是源代码:

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();
            }
        }
    }

当快速移动鼠标以获取正确的屏幕截图时,是否有任何解决方案或建议。

谢谢。

1 个答案:

答案 0 :(得分:2)

当鼠标移动得非常快时,Windows会将鼠标移动聚合成一条消息,以免任何带有大量WM_MOUSEMOVE的程序超载。您可以通过Mouse.GetIntermediatePoints在WPF中获取这些中间点的列表。

我怀疑你的问题是鼠标在最后一次移动和左按钮之间快速移动屏幕,你错过了一大堆中间点。

尝试将其作为实验,也可以在左键向上处理程序中绘制矩形。我相信这会使矩形与屏幕截图区域相匹配。如果您然后检查中间点,您可能会看到一堆排队的移动数据。

为了解决这个问题,为什么不使用最后一次鼠标移动作为mEndPoint而不是在左按钮向上处理程序中调用GetPosition?这应该给你正确的行为,因为它将完全反映你当前绘制矩形的方法。然后,无论中间移动如何,您将捕获矩形坐标本身,而不是由左按钮向上位置形成的新矩形。