Search code examples
c#wpfxamlsizescreenshot

Taking a screenshot - sizes do not match


I tried to programm a snipping tool of my own. It works quite well, except that the size of the area I select does not match the size in Pixels.

I create a window with low opacity and draw a rectangle to get the size and location. The window has 300x300 dimensions (later it should be full Screen), but if I take a screenshot with snipping tool it shows a size of 375x375 Pixels. So when I take a scrennshot with my own programm I do not catch all the features I actually wanted.

The final goal is to take multiple screenshots of the same location with a shortcut (not implemented), then do some OCR(not implemented) on specific regions and create a filename corresponding to the OCR results.

Here is the code:

Main window 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;    
    }

Main window 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>

Secondary window to get the rectangle 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; }
    }
}

secondary window 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>

So, here are my questions:

  1. Why is the size of the window not the actual size in pixels?
  2. How do I get the values I want so that the images I take include all the features I want them to an not less?

Thanks for our help.


Solution

  • The link of Pikoh was the right direction. Led me to this 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;            
        }
    

    I am still off 1 or 2 Pixel (don´t know why) when the difference is big enough (100+ Pixel) but I can live with that.

    Edit: The difference is about 8 Pixel an it is always there - i guess it is the window border or something.