将矩形坐标转换为屏幕坐标以进行屏幕捕获[重复]

问题描述 投票:0回答:1

我正在使用 WPF 在 C# 中创建一个屏幕捕获应用程序,用户可以在屏幕上绘制一个矩形,该应用程序捕获该矩形后面的内容,类似于 Windows 截图工具。

我困惑于如何将绘制的矩形的坐标转换为屏幕坐标。下面是我到目前为止的代码。

屏幕截图仅捕获了绘制矩形的一部分

<Window x:Class="ScreenCapture.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Screen Capture" Height="800" Width="1660"
        WindowState="Maximized"
        AllowsTransparency="True" WindowStyle="None"
        PreviewKeyDown="Window_PreviewKeyDown">
    <Window.Background>
        <SolidColorBrush Opacity="0.01" Color="White"/>
    </Window.Background>
    <Canvas x:Name="canvas" Background="Transparent"
            MouseDown="canvas_MouseDown" 
            MouseUp="canvas_MouseUp">
    </Canvas>
</Window>
using System;
using System.Drawing; // For screen capturing (Bitmap, Graphics)
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ScreenCapture
{
    public partial class MainWindow : Window
    {
        private System.Windows.Shapes.Rectangle DragRectangle = null; // Specify WPF Rectangle
        private System.Windows.Point StartPoint, LastPoint;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape) { this.Close(); e.Handled = true; }
        }

        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            StartPoint = Mouse.GetPosition(canvas);
            LastPoint = StartPoint;

            // Initialize and style the rectangle
            DragRectangle = new System.Windows.Shapes.Rectangle
            {
                Width = 1,
                Height = 1,
                Stroke = System.Windows.Media.Brushes.Red,
                StrokeThickness = 1,
                Cursor = Cursors.Cross
            };

            // Add the rectangle to the canvas
            canvas.Children.Add(DragRectangle);
            Canvas.SetLeft(DragRectangle, StartPoint.X);
            Canvas.SetTop(DragRectangle, StartPoint.Y);

            // Attach the mouse move and mouse up events
            canvas.MouseMove += canvas_MouseMove;
            canvas.MouseUp += canvas_MouseUp;
            canvas.CaptureMouse();
        }

        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (DragRectangle == null) return;

            // Update LastPoint to current mouse position
            LastPoint = Mouse.GetPosition(canvas);

            // Update rectangle dimensions and position
            DragRectangle.Width = Math.Abs(LastPoint.X - StartPoint.X);
            DragRectangle.Height = Math.Abs(LastPoint.Y - StartPoint.Y);
            Canvas.SetLeft(DragRectangle, Math.Min(LastPoint.X, StartPoint.X));
            Canvas.SetTop(DragRectangle, Math.Min(LastPoint.Y, StartPoint.Y));
        }

        private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DragRectangle == null) return;

            // Release mouse capture and remove event handlers
            canvas.ReleaseMouseCapture();
            //canvas.MouseMove -= canvas_MouseMove;
            //canvas.MouseUp -= canvas_MouseUp;

            // Get coordinates for the capture area
            int x = (int)Math.Min(LastPoint.X, StartPoint.X);
            int y = (int)Math.Min(LastPoint.Y, StartPoint.Y);
            int width = (int)Math.Abs(LastPoint.X - StartPoint.X);
            int height = (int)Math.Abs(LastPoint.Y - StartPoint.Y);

            // Ensure dimensions are valid before capture
            if (width > 0 && height > 0)
            {
                CaptureScreen(x, y, width, height);
            }

            //// Clean up: remove rectangle from canvas
            //canvas.Children.Remove(DragRectangle);
            //DragRectangle = null;
            this.Close();
        }

        private void CaptureScreen(int x, int y, int width, int height)
        {
            // Convert WPF coordinates to screen coordinates
            var screenLeft = (int)(PointToScreen(new System.Windows.Point(x, y)).X);
            var screenTop = (int)(PointToScreen(new System.Windows.Point(x, y)).Y);

            using (Bitmap bitmap = new Bitmap(width, height))
            {
                using (Graphics g = Graphics.FromImage(bitmap))
                {
                    // Capture the area of the screen based on converted coordinates
                    g.CopyFromScreen(screenLeft, screenTop, 0, 0, new System.Drawing.Size(width, height));
                }

                // Save the captured image to the desktop
                string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                string filePath = System.IO.Path.Combine(desktopPath, $"Screenshot_{DateTime.Now:yyyyMMdd_HHmmss}.png");
                bitmap.Save(filePath);
                MessageBox.Show($"Screenshot saved to {filePath}");
            }
        }

    }
}
c# wpf coordinates rectangles screen-capture
1个回答
1
投票

感谢大家的帮助!特别感谢 Jim Mischel 为我指明了正确的方向。

在 WPF 中,有一个名为 PointToScreen 的方便方法帮助我解决了这个问题。此方法将相对于 WPF 元素的点转换为屏幕坐标,这正是我所需要的。

using System;
using System.Drawing; // For screen capturing (Bitmap, Graphics)
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace ScreenCapture
{
    public partial class MainWindow : Window
    {
        private System.Windows.Shapes.Rectangle DragRectangle = null; // Specify WPF Rectangle
        private System.Windows.Point StartPoint, LastPoint;

        public MainWindow()
        {
            InitializeComponent();
            Cursor = Cursors.Cross;
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape) { this.Close(); e.Handled = true; }
        }

        private void canvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            StartPoint = Mouse.GetPosition(canvas);
            LastPoint = StartPoint;

            // Initialize and style the rectangle
            DragRectangle = new System.Windows.Shapes.Rectangle
            {
                Width = 1,
                Height = 1,
                Stroke = System.Windows.Media.Brushes.Red,
                StrokeThickness = 1,
                Cursor = Cursors.Cross
            };

            // Add the rectangle to the canvas
            canvas.Children.Add(DragRectangle);
            Canvas.SetLeft(DragRectangle, StartPoint.X);
            Canvas.SetTop(DragRectangle, StartPoint.Y);

            // Attach the mouse move and mouse up events
            canvas.MouseMove += canvas_MouseMove;
            canvas.MouseUp += canvas_MouseUp;
            canvas.CaptureMouse();
        }

        private void canvas_MouseMove(object sender, MouseEventArgs e)
        {
            if (DragRectangle == null) return;

            // Update LastPoint to current mouse position
            LastPoint = Mouse.GetPosition(canvas);

            // Update rectangle dimensions and position
            DragRectangle.Width = Math.Abs(LastPoint.X - StartPoint.X);
            DragRectangle.Height = Math.Abs(LastPoint.Y - StartPoint.Y);
            Canvas.SetLeft(DragRectangle, Math.Min(LastPoint.X, StartPoint.X));
            Canvas.SetTop(DragRectangle, Math.Min(LastPoint.Y, StartPoint.Y));
        }

        private void canvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
            if (DragRectangle == null) return;
            canvas.ReleaseMouseCapture();

            CaptureScreen();

            // Clean up: remove rectangle from canvas
            canvas.Children.Remove(DragRectangle);
            DragRectangle = null;
            this.Close();
        }

        private void CaptureScreen()
        {
            // Convert StartPoint and LastPoint to screen coordinates
            var screenStart = PointToScreen(StartPoint);
            var screenEnd = PointToScreen(LastPoint);

            // Calculate the capture area dimensions and position
            int x = (int)Math.Min(screenStart.X, screenEnd.X);
            int y = (int)Math.Min(screenStart.Y, screenEnd.Y);
            int width = (int)Math.Abs(screenEnd.X - screenStart.X);
            int height = (int)Math.Abs(screenEnd.Y - screenStart.Y);


            this.Closed += (s, e) => 
            {
                // Ensure dimensions are valid before capture
                if (width > 0 && height > 0)
                {
                    using (Bitmap bitmap = new Bitmap(width, height))
                    {
                        using (Graphics g = Graphics.FromImage(bitmap))
                        {
                            // Capture the area of the screen based on converted coordinates
                            g.CopyFromScreen(x, y, 0, 0, new System.Drawing.Size(width, height));
                        }

                        // Save the captured image to the desktop
                        string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
                        string filePath = System.IO.Path.Combine(desktopPath, $"Screenshot_{DateTime.Now:yyyyMMdd_HHmmss}.png");
                        bitmap.Save(filePath);

                        System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
                        { FileName = filePath, UseShellExecute = true });
                    }
                }
            };
        }
    }
}

© www.soinside.com 2019 - 2024. All rights reserved.