在c#和WPF中选择截图是不准确的
本文关键字:不准确 选择 WPF | 更新日期: 2023-09-27 18:13:00
我做了一个程序,从屏幕上选定的区域截取屏幕截图,但它不准确,我不知道为什么。这可能是因为鼠标坐标,但我不知道我做错了什么。也许你们中有人能弄明白。截图总是关闭的,它会捕捉屏幕上实际选择区域上方的区域,因此会"剪切"选择区域的下方部分。这是我的代码:
public partial class Selektiranje : Window
{
public double x;
public double y;
public double width;
public double height;
public bool isMouseDown = false;
public Selektiranje()
{
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
isMouseDown = true;
x = e.GetPosition(null).X; //Selekcija Screenshota
y = e.GetPosition(null).Y;
}
public void Window_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (this.isMouseDown)
{
double curx = e.GetPosition(null).X;
double cury = e.GetPosition(null).Y;
System.Windows.Shapes.Rectangle r = new , System.Windows.Shapes.Rectangle();
SolidColorBrush brush = new SolidColorBrush(Colors.White);
r.Stroke = brush;
r.Fill = brush;
r.StrokeThickness = 1;
r.Width = Math.Abs(curx - x);
r.Height = Math.Abs(cury - y);
selekt.Children.Clear();
selekt.Children.Add(r);
Canvas.SetLeft(r, x);
Canvas.SetTop(r, y);
if (e.LeftButton == MouseButtonState.Released)
{
selekt.Children.Clear();
width = e.GetPosition(null).X - x;
height = e.GetPosition(null).Y - y;
this.CaptureScreen(x, y, width, height);
this.x = this.y = 0;
this.isMouseDown = false;
this.Close();
}
}
}
public void CaptureScreen(double x, double y, double width, double height)
{
int ix, iy, iw, ih;
ix = Convert.ToInt32(x);
iy = Convert.ToInt32(y);
iw = Convert.ToInt32(width);
ih = Convert.ToInt32(height);
Bitmap slika = new Bitmap(iw, ih, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(slika);
g.CopyFromScreen(ix, iy, 0, 0,new System.Drawing.Size(iw, ih),CopyPixelOperation.SourceCopy);
public void SaveScreen(double x, double y, double width, double height)
{
int ix, iy, iw, ih;
ix = Convert.ToInt32(x);
iy = Convert.ToInt32(y);
iw = Convert.ToInt32(width);
ih = Convert.ToInt32(height);
try
{
Bitmap slika = new Bitmap(iw, ih);
Graphics gr1 = Graphics.FromImage(slika);
IntPtr dc1 = gr1.GetHdc();
IntPtr dc2 = NativeMethods.GetWindowDC(NativeMethods.GetForegroundWindow());
NativeMethods.BitBlt(dc1, ix, iy, iw, ih, dc2, ix, iy, 13369376);
gr1.ReleaseHdc(dc1);
System.Windows.Forms.SaveFileDialog dlg = new System.Windows.Forms.SaveFileDialog();
dlg.DefaultExt = "png";
dlg.Filter = "Png Files|*.png";
DialogResult res = dlg.ShowDialog();
if (res == System.Windows.Forms.DialogResult.OK)
slika.Save(dlg.FileName, ImageFormat.Png);
}
catch
{
}
}
internal class NativeMethods
{
[DllImport("user32.dll")]
public extern static IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();
[DllImport("gdi32.dll")]
public static extern UInt64 BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, System.Int32 dwRop);
}
}
}
您需要游标。位置(MSDN)在Window_MouseDown()
和Window_MouseMove()
返回鼠标绝对坐标。
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
isMouseDown = true;
x = Cursor.Position.X;
y = Cursor.Position.Y;
}
代码的一个完全工作的解决方案(为我)如下。我删除了不必要的代码,比如绘制矩形。另外,我在截图前隐藏了表单。你也可以将表单的背景色设置为一个特定的值,并将透明度键设置为相同的值或其他东西。
但基本概念仍然是:使用绝对屏幕坐标。
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Media;
using PixelFormat = System.Drawing.Imaging.PixelFormat;
using Rectangle = System.Windows.Shapes.Rectangle;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public double x;
public double y;
public double width;
public double height;
public bool isMouseDown;
public Form1()
{
InitializeComponent();
}
public void SaveScreen(double x, double y, double width, double height)
{
var ix = Convert.ToInt32(x);
var iy = Convert.ToInt32(y);
var iw = Convert.ToInt32(width);
var ih = Convert.ToInt32(height);
try
{
var slika = new Bitmap(iw, ih, PixelFormat.Format32bppArgb);
var g = Graphics.FromImage(slika);
g.CopyFromScreen(ix, iy, 0, 0, new Size(iw, ih), CopyPixelOperation.SourceCopy);
var dlg = new SaveFileDialog
{
DefaultExt = "png",
Filter = "Png Files|*.png"
};
var res = dlg.ShowDialog();
if (res == DialogResult.OK) slika.Save(dlg.FileName, ImageFormat.Png);
}
catch
{
}
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
isMouseDown = true;
x = Cursor.Position.X;
y = Cursor.Position.Y;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
width = Cursor.Position.X - x;
height = Cursor.Position.Y - y;
Hide();
Size = new Size(0, 0);
Application.DoEvents();
SaveScreen(x, y, width, height);
x = y = 0;
isMouseDown = false;
Close();
}
}
}
Graphics.CopyFromScreen
需要屏幕坐标来拍照。由于使用MouseEventArgs
的e.x和e.y,您正在传递相对于形式的坐标。你应该使用鼠标的屏幕坐标,使用相同的Cursor.Position
或MousePosition
。
如果您正在使用WPF
有许多选项可以帮助您获得屏幕坐标,其中一些选项:
选项1
您可以使用PointToScreen方法将坐标转换为屏幕坐标。
选项2
在WPF中你不能使用这些方法,最简单的方法是将System.Windows.Forms.dll
的引用添加到WPF项目中,然后使用静态的System.Windows.Forms.Control.MousePosition
。
选项3
作为另一个选项,您可以添加对System.Drawing.dll
的引用,并使用:
[System.Runtime.InteropServices.DllImport("user32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref PointStruct point);
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct PointStruct
{
public Int32 X;
public Int32 Y;
};
public static System.Drawing.Point MousePosition()
{
var mousePosition = new PointStruct();
GetCursorPos(ref mousePosition);
return new System.Drawing.Point(mousePosition.X, mousePosition.Y);
}
然后你可以使用MousePosition()
来获取鼠标在屏幕上的当前位置