我正在使用 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}");
}
}
}
}
感谢大家的帮助!特别感谢 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 });
}
}
};
}
}
}