c# - 截取桌面 C# (WPF) 屏幕截图时出现延迟

标签 c# wpf screenshot gdi

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

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

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

鼠标快速移动右截屏时有什么解决办法或建议吗?

谢谢。

最佳答案

当鼠标移动得非常快时,Windows 会将鼠标移动聚合到单个消息中,以免因大量 WM_MOUSEMOVE 而导致任何程序重载。您可以通过 Mouse.GetIntermediatePoints 获取 WPF 中这些中间点的列表。 .

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

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

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

关于c# - 截取桌面 C# (WPF) 屏幕截图时出现延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37854140/

相关文章:

c# - 无需数据库即可永久存储数据

c# - 多策略设计模式

c# - 在 WPF 中创建旋转文本

c# - 如何在 WPF 代码隐藏中创建 BeginStoryboard?

c# - 使用两点捕获屏幕截图

android - 在 Google Play 上发布 android 应用程序的屏幕截图大小

c# - 我怎样才能记住 super 调用父级?

WPF - 基于内容突出显示文本框

iphone - 如何在iPhone中运行视频拍摄屏幕截图

c# - 适用于 chrome、firefox 和 safari 浏览器的 Azure 浏览器推送通知