截图 - 尺寸不匹配

时间:2016-10-06 15:09:27

标签: c# wpf xaml size screenshot

我尝试编写自己的剪切工具。除了我选择的区域大小与像素大小不匹配外,它的效果非常好。

我创建了一个低不透明度的窗口并绘制一个矩形来获取大小和位置。该窗口的尺寸为300x300(后来应该是全屏),但如果我使用剪切工具截取屏幕截图,则显示的尺寸为375x375像素。因此,当我用自己的程序拍摄一个scrennshot时,我没有捕捉到我真正想要的所有功能。

最终目标是使用快捷方式(未实现)获取同一位置的多个屏幕截图,然后在特定区域执行一些OCR(未实现)并创建与OCR结果相对应的文件名。

以下是代码:

主窗口c#:

int number = 0;

    System.Windows.Point scsh_Start;
    System.Windows.Point scsh_Ende;
    System.Windows.Point OCR_Start;
    System.Windows.Point OCR_Ende;

    public MainWindow()
    {
        InitializeComponent();            
    }


    private void button_Click(object sender, RoutedEventArgs e)
    {
        int Width = (int)( Math.Abs(scsh_Start.X - scsh_Ende.X) );
        int Height = (int)( Math.Abs(scsh_Start.Y - scsh_Ende.Y) );
        using (Bitmap bmpScreenCapture = new Bitmap(Width,
                                        Height))
        {
            using (Graphics g = Graphics.FromImage(bmpScreenCapture))
            {                    
                string outputNumber = "";
                if (number < 10)
                {
                    outputNumber = "00" + number.ToString();
                }
                else if (number < 100)
                {
                    outputNumber = "0" + number.ToString();
                }
                else
                {
                    outputNumber = number.ToString();
                }
                Opacity = .0;                    
                g.CopyFromScreen((int)scsh_Start.X,
                                 (int)scsh_Start.Y,
                                 0, 0,
                                 bmpScreenCapture.Size);
                Directory.CreateDirectory("C:\\Users\\Public\\Pictures\\Sample Pictures\\ScreenSave");
                bmpScreenCapture.Save("C:\\Users\\Public\\Pictures\\Sample Pictures\\ScreenSave\\test" + outputNumber + ".png");
                Opacity = 1;
                number++;
            }
        }
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        this.WindowState = WindowState.Minimized;
        Window1 w1 = new Window1();
        w1.RaiseCustomEvent += pointsScreenshot;
        w1.ShowDialog();

    }

    private void pointsScreenshot(object sender, customEventArgs e)
    {
        if (e.Points[0] == null)
            return;
        scsh_Start = e.Points[0];
        scsh_Ende = e.Points[1];
        B_Image.IsEnabled = true;    
    }

主窗口XAML:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Button x:Name="B_Image" Content="Image" HorizontalAlignment="Left" Margin="70,31,0,0" VerticalAlignment="Top" Width="75" Click="button_Click" IsEnabled="False"/>
    <Button x:Name="B_MouseEvents" Content="Mouse" HorizontalAlignment="Left" Margin="70,76,0,0" VerticalAlignment="Top" Width="75" Click="button1_Click"/>
</Grid>

获取矩形c#的辅助窗口:

    public partial class Window1 : Window
{
    public event EventHandler<customEventArgs> RaiseCustomEvent;
    private Point p_Start = new Point();
    private Point p_End = new Point();
    private Rectangle saveRect = null;
    private MoveType move = MoveType.Draw;
    bool top = false;
    bool left = false;


    public Window1()
    {
        InitializeComponent();
        this.Topmost = true;
        this.Activate();
        ////this.WindowState = WindowState.Maximized;       

    }

    private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        p_Start = e.GetPosition(null);

        double xAct = e.GetPosition(null).X;
        double yAct = e.GetPosition(null).Y;

        if (saveRect != null)
        {
            double rectLeft = saveRect.Margin.Left;
            double rectTop = saveRect.Margin.Top;
            double rectRight = saveRect.Margin.Left + saveRect.Width;
            double rectBottom = saveRect.Margin.Top + saveRect.Height;

            if (between(xAct, rectLeft + 3, rectRight - 3) &&
                between(yAct, rectTop + 3, rectBottom - 3))
                move = MoveType.Drag;

            else if (( between(xAct, rectLeft - 3, rectLeft) || between(xAct, rectRight - 3, rectRight) ) &&
                between(yAct, rectTop, rectBottom))
            {
                move = MoveType.ResizeWidth;
                left = between(xAct, rectLeft - 3, rectLeft + 3);
            }
            else if (( between(yAct, rectTop - 3, rectTop) || between(yAct, rectBottom - 3, rectBottom) ) &&
                between(xAct, rectLeft, rectRight))
            {
                move = MoveType.ResizeHeight;
                top = between(yAct, rectTop - 3, rectTop + 3);
            }
            else
                move = MoveType.Draw;
        }
        else
            move = MoveType.Draw;
    }

    private void Window_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        move = MoveType.Draw;
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {


    }

    private void Window_MouseMove(object sender, MouseEventArgs e)
    {
        double xAct = e.GetPosition(null).X;
        double yAct = e.GetPosition(null).Y;

        #region select Cursor
        if (e.LeftButton != MouseButtonState.Pressed)
        {
            if (saveRect != null)
            {
                double rectLeft = saveRect.Margin.Left;
                double rectTop = saveRect.Margin.Top;
                double rectRight = saveRect.Margin.Left + saveRect.Width;
                double rectBottom = saveRect.Margin.Top + saveRect.Height;

                if (between(xAct, rectLeft + 3, rectRight - 3) &&
                    between(yAct, rectTop + 3, rectBottom - 3))
                    Cursor = Cursors.Hand;

                else if (( between(xAct, rectLeft - 3, rectLeft) || between(xAct, rectRight - 3, rectRight) ) &&
                    between(yAct, rectTop, rectBottom))
                    Cursor = Cursors.SizeWE;
                else if (( between(yAct, rectTop - 3, rectTop) || between(yAct, rectBottom - 3, rectBottom) ) &&
                    between(xAct, rectLeft, rectRight))
                    Cursor = Cursors.SizeNS;

                else Cursor = Cursors.Pen;
            }
            else
                Cursor = Cursors.Pen;
            return;
        }
        else
        {
            switch (move)
            {
                case MoveType.Drag:
                    Cursor = Cursors.Hand;
                    break;
                case MoveType.Draw:
                    Cursor = Cursors.Pen;
                    break;
                case MoveType.ResizeHeight:
                    Cursor = Cursors.SizeNS;
                    break;
                case MoveType.ResizeWidth:
                    Cursor = Cursors.SizeWE;
                    break;
            }
        } 
        #endregion

        if (mainGrid.Children.Count > 0)
            this.mainGrid.Children.RemoveAt(0);
        Rectangle r = new Rectangle();
        p_End = e.GetPosition(null);
        switch (move)
        {
            case MoveType.Draw:                                     
                r.Stroke = new SolidColorBrush(Colors.Aqua);
                r.Opacity = 1;
                r.Height = Math.Abs(p_End.Y - p_Start.Y);
                r.Width = Math.Abs(p_End.X - p_Start.X);
                double t_left = p_End.X > p_Start.X ? p_Start.X : p_End.X;
                double t_top = p_End.Y > p_Start.Y ? p_Start.Y : p_End.Y;
                r.VerticalAlignment = VerticalAlignment.Top;
                r.HorizontalAlignment = HorizontalAlignment.Left;
                r.Margin = new Thickness(t_left, t_top, 0, 0);
                this.mainGrid.Children.Add(r);
                saveRect = r;
                break;
            case MoveType.Drag:
                r = saveRect;
                double moveHorizontal = p_Start.X - p_End.X;
                double moveVertical = p_Start.Y - p_End.Y;
                if (r.Margin.Left - moveHorizontal < 0)
                    moveHorizontal = r.Margin.Left;
                if (r.Margin.Top - moveVertical < 0)
                    moveVertical = r.Margin.Top;
                r.Margin = new Thickness(r.Margin.Left - moveHorizontal, r.Margin.Top - moveVertical, 0, 0);
                this.mainGrid.Children.Add(r);
                saveRect = r;
                p_Start = p_End;
                break;
            case MoveType.ResizeHeight:
                r = saveRect;
                double resize = p_Start.Y - p_End.Y;
                if (top)
                {                       
                    r.Margin = new Thickness(r.Margin.Left, r.Margin.Top - resize, 0, 0);                        
                    r.Height += resize;
                }
                else
                {                       
                    r.Height -= resize;
                }
                this.mainGrid.Children.Add(r);
                saveRect = r;
                p_Start = p_End;
                break;
            case MoveType.ResizeWidth:
                r = saveRect;
                double resizeX = p_Start.X - p_End.X;
                if (left)
                {
                    r.Margin = new Thickness(r.Margin.Left - resizeX, r.Margin.Top, 0, 0);
                    r.Width += resizeX;
                }
                else
                {
                    r.Width -= resizeX;
                }
                this.mainGrid.Children.Add(r);
                saveRect = r;
                p_Start = p_End;
                break;
        }
    }

    private void Window_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
    {
        RaiseCustomEvent(this, new customEventArgs(getPoints()));
        this.Close();
    }

    public List<Point> getPoints()
    {
        List<Point> p = new List<Point>();
        this.Visibility = Visibility.Collapsed;
        if (mainGrid.Children.Count > 0)
        {
            p.Add(new Point(saveRect.Margin.Left, saveRect.Margin.Top));
            p.Add(new Point(saveRect.Width+ saveRect.Margin.Left, saveRect.Height+ saveRect.Margin.Top));
            return p;
        }

        return null;
    }

    private bool between(double actual, double min, double max)
    {
        if (( actual < min ) || ( actual > max ))
            return false;
        else return true;
    }

    private enum MoveType
    {
        Draw,
        Drag,
        ResizeHeight,
        ResizeWidth
    }

}

public class customEventArgs : EventArgs
{
    private List<Point> pts;
    public customEventArgs(List<Point> Points)
    {
        pts = Points;
    }

    public List<Point> Points
    {
        get { return pts; }
    }
}

辅助窗口XAML:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="W1" Height="300" Width="300"  WindowStyle="None" Topmost="True" BorderThickness="0" Foreground="{x:Null}" AllowsTransparency="True"  
    Left="0" Top="0"
    MouseLeftButtonDown="Window_MouseLeftButtonDown" Loaded="Window_Loaded" MouseMove="Window_MouseMove" MouseRightButtonDown="Window_MouseRightButtonDown" 
    MouseLeftButtonUp="Window_MouseLeftButtonUp" >
<Window.Background>
    <SolidColorBrush Opacity="0.3" Color="Gray"></SolidColorBrush>
</Window.Background>
<Grid Name="mainGrid">        
</Grid>

所以,这是我的问题:

  1. 为什么窗口的大小不是以像素为单位的实际大小?
  2. 如何获取我想要的值,以便我拍摄的图像包含我想要的所有功能?
  3. 感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

Pikoh的链接是正确的方向。 带我到这个How can I get the DPI in WPF?

private double getDPIScale()
    {
        PresentationSource source = PresentationSource.FromVisual(this);

        double dpiX , dpiY;
        if (source != null)
        {
            dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
            dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
            return dpiX / 96.0;
        }

        return 0;            
    }

当差异足够大(100+像素)时,我仍然关闭1或2像素(不知道为什么),但我可以忍受。

编辑:差异大约为8像素,它始终存在 - 我猜它是窗口边框或其他东西。