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

}

在c#和WPF中选择截图是不准确的

您需要游标。位置(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.PositionMousePosition

如果您正在使用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()来获取鼠标在屏幕上的当前位置