none
Taking a screenshot of the form in different dpi resolutions RRS feed

  • Question

  • Hi, I'm in the situation where, I have to take a screenshot of the insides of the form itself, but whenever the resolution differs from a dpi of 96, its not the entire form that's shown, and part of what's behind, to the left of the form is shown as well.

    Dim img As New Bitmap(Width, Height)
    Using g As Graphics = Graphics.FromImage(img)
        g.CopyFromScreen(PointToScreen(Point.Empty), Point.Empty, New Size(Width, Height))
    End Using
    This is what I'm aiming for, at all resolutions

    This is what I get, when using a different resolution

    I'm not sure how I can get the dpi of the current screen of the control, for when I have 2 monitors, and monitor1 have a resolution of 100% and monitor2 have a resolution of 125%, the image works without a hitch on monitor1, but is offset and doesnt take into account, the resized form, due to the difference in resolution.

    Is it possible to do this?

    Friday, December 14, 2018 11:23 AM

Answers

All replies

  • It is all quite complicated these days.

    If you just need the total form captured you can use DrawToBitmap much easier.

    https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.drawtobitmap?redirectedfrom=MSDN&view=netframework-4.7.2#System_Windows_Forms_Control_DrawToBitmap_System_Drawing_Bitmap_System_Drawing_Rectangle_

    https://docs.microsoft.com/en-us/dotnet/framework/winforms/high-dpi-support-in-windows-forms


    'create a memory bitmap and size to the form outside outline
    Dim bmp As Bitmap = New Bitmap(Me.Width, Me.Height)
    
    'draw the form on the memory bitmap
    Me.DrawToBitmap(bmp, New Rectangle(0, 0, Me.Width, Me.Height))


    • Edited by tommytwotrain Friday, December 14, 2018 11:49 AM
    • Marked as answer by Naidos Monday, December 17, 2018 7:34 AM
    Friday, December 14, 2018 11:40 AM
  •  This is because windows forms are not dpi aware by default and do not take the scaling of the screen into account.  Properties and other available methods to get the Location and Size of a Form will not report the correct scaled size or location because of not taking the screen scale into account.

     So,  you can follow the steps I explained in This Link to set your app to be dpi aware.  If your app captures the client area properly when you use 100% scaling,  then just setting it to be dpi aware might be all you need to do.

     For an example,  I created an app and left my app as non-dpiaware and set my screen scale to 150%,  then used the code below to capture the client area of the form and save it to the desktop when the F1 key is pressed. You can see in the first image that the location and size is too small and did not capture the form correctly at all.  You will also notice the smaller text is a little blurry too.

      
    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Me.KeyPreview = True
        End Sub
    
        Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
            If e.KeyCode = Keys.F1 Then CaptureClientArea()
        End Sub
    
        Private Sub CaptureClientArea()
            Dim pts As Point = Me.PointToClient(Me.Location)
            Using bm As New Bitmap(Me.ClientSize.Width, Me.ClientSize.Height), g As Graphics = Graphics.FromImage(bm)
                g.CopyFromScreen(New Point(Me.Left + Math.Abs(pts.X), Me.Top + Math.Abs(pts.Y)), Point.Empty, Me.ClientSize)
                bm.Save(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) & "\Client Image.png", Imaging.ImageFormat.Png)
            End Using
        End Sub
    End Clas

     

     

     After setting the app to be dpiaware,  you can see in the image below that it was captured correctly.  You will also see that the text looks much more clear too,  an added benefit of setting the app to be dpi aware.


    If you say it can`t be done then i`ll try it

    • Edited by IronRazerz Saturday, December 15, 2018 6:35 PM
    • Proposed as answer by tommytwotrain Monday, December 17, 2018 9:33 AM
    Saturday, December 15, 2018 6:34 PM
  • Hi IronRazerz, I tried adding

    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
          <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True</dpiAware>
        </windowsSettings>
      </application>

    to the app.manifest, where I added the support for Windows 10, and added the applicationconfigurationSection to the app.config file

    <System.Windows.Forms.ApplicationConfigurationSection>
        <add key="DpiAwareness" value="PerMonitorV2" />
        <add key="EnableWindowsFormsHighDpiAutoResizing" value="True" />
      </System.Windows.Forms.ApplicationConfigurationSection>

    And tried with the code you used in the CaptureClientArea sub method, but when I scaled up again, it still went slightly to the side, and didnt capture what it should :/

    Monday, December 17, 2018 7:20 AM
  • Hi Tommytwotrain,

    It really is, and am used to having to find convoluted ways, to make things work, which is why, that after setting the manifest and the configuration, and it still didn't work, when I used graphics to draw the screen, where the application was. I had doubts that just 2 simple lines would work, and accomplish what I spent hours to try and accomplish, and after trying them, it works.

    I am honestly baffled, yet not surprised, somehow :)

    I'm not entirely sure why this works, while none of the rest I tried worked out, but I really appreciate it, thank you :)

    Monday, December 17, 2018 7:34 AM
  • Hi Tommytwotrain,

    It really is, and am used to having to find convoluted ways, to make things work, which is why, that after setting the manifest and the configuration, and it still didn't work, when I used graphics to draw the screen, where the application was. I had doubts that just 2 simple lines would work, and accomplish what I spent hours to try and accomplish, and after trying them, it works.

    I am honestly baffled, yet not surprised, somehow :)

    I'm not entirely sure why this works, while none of the rest I tried worked out, but I really appreciate it, thank you :)


    Nadious,

    Yeah. Well there are just so many different versions of things...

    At the end of this thread are screen shots from text scaling of 100, 125, and 150 percent. You can see that at 125 the text has changed but the form has not, much... then at 150 the form and the text has changed. But now with different versions of windows and monitor settings etc it is just not clear what happens when.

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/43e698ec-a57f-4cc8-aa25-1ea0fafda057/screen-size?forum=vbgeneral


    https://social.msdn.microsoft.com/Forums/vstudio/en-US/6acc3b21-23a4-4a00-90b4-968a43e1ccc8/capture-screen-with-high-dpi?forum=vbgeneral

    Setting dpi aware helps some with some things. But with gdi+ drawing it does not.

    However to be honest I am not sure exactly what happens anymore especially with win 10 and "art" update last year that added clear type and etc.

    I dont use any of it for my CAD program. I scale everything myself based on the size of the clientrectangle in pixels that I am drawing in. I use nothing auto-scale. And I test my app in all resolutions. I also leave room around all text and controls to shrink and grow 25 percent.

    In the capture form case the drawtobitmap works in pixels. Period. It starts in pixels and ends in pixels. Since nothing is scaled or converted it works out fine. It is a bitmap. Not vector text. The text has already been drawn. All we do is capture the drawing bitmap in pixels.

    Finally, I don't claim to understand it all and I am certainly tired of trying to explain it not that I know how.

    :)

    Monday, December 17, 2018 9:25 AM