שתף באמצעות


Copy From Screen Windows Scaling

Question

Tuesday, May 19, 2015 12:27 AM

I have some code  seen below.   I don't believe I need to post more code to show what I am trying to do.    I am able to save/get a copy of the screen as long as Scaling is set to normal.  But when the Scaling is changed ex: medium - 125% Larger - 150% in Windows 7.  The picture does not look correct.   What can I do, or can someone point me in the correct direction.  I have search but have not found any solutions.   Thanks

Dim W As Integer = Screen.PrimaryScreen.Bounds.Width
        Dim H As Integer = Screen.PrimaryScreen.Bounds.Height
        Dim B As New Bitmap(W, H)
        Dim g As Graphics = Graphics.FromImage(B)
        g.CompositingQuality = CompositingQuality.HighSpeed
        g.CopyFromScreen(0, 0, 0, 0, New Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height), CopyPixelOperation.SourceCopy)

All replies (53)

Thursday, May 21, 2015 12:24 AM ✅Answered

Joe

Regarding your original question in this thread. How to deal with CopyFromScreen. It appears all the GDI functions are complicit with changes in Control Panel >>  Display Settings . . except for CopyFromScreen - - - it appears to be a framework bug.

You knew I would try it? On my system the copyfromscreen seems to work the same at 100% or 125%.  Win 7 64 bit .net 4.5.

This is 125% of this new simpler example that has one form and buttons.

Option Strict On

Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        'capture the screen image and save it as a 5x5 grid of small image files
        Dim srcWidth As Integer = Screen.PrimaryScreen.Bounds.Width
        Dim srcHeight As Integer = Screen.PrimaryScreen.Bounds.Height
        Dim numberRects As Integer = 5
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)

        'capture source screen and create list of small rect bitmaps
        Using srcBmp As New Bitmap(srcWidth, srcHeight), _
            g As Graphics = Graphics.FromImage(srcBmp)

            g.CopyFromScreen(0, 0, 0, 0, New Size(srcWidth, srcHeight), CopyPixelOperation.SourceCopy)

            'save the small rect bmps  5 x 5 grid
            Dim count As Integer
            Dim rect As Rectangle

            Using smallBmp As Bitmap = New Bitmap(w, h)
                Using sg As Graphics = Graphics.FromImage(smallBmp)
                    For x = 0 To srcWidth - w Step w
                        For y = 0 To srcHeight - h Step h
                            rect = New Rectangle(x, y, w, h)
                            'get the small rect from the source and draw on the temp smallBmp and save it
                            sg.DrawImage(srcBmp, New Rectangle(0, 0, w, h), rect, GraphicsUnit.Pixel)
                            smallBmp.Save("c:\test\" & count.ToString & ".jpg")
                            count += 1
                        Next
                    Next

                    MsgBox((count).ToString & " files saved")
                End Using
            End Using
        End Using
    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        'draw the saved small images
        'get the original bitmap size
        Dim bmp As Bitmap
        bmp = New Bitmap(New IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes("c:\test\" & "0.jpg").ToArray), False)
        Dim numberRects As Integer = 5
        Dim srcWidth As Integer = numberRects * bmp.Width
        Dim srcHeight As Integer = numberRects * bmp.Height
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)
        Dim count As Integer
        Dim rect As Rectangle

        'now draw the list of small bmps to the form
        Using destBmp As Bitmap = New Bitmap(srcWidth, srcHeight)
            Using dg As Graphics = Graphics.FromImage(destBmp)
                For x = 0 To destBmp.Width - w Step w
                    For y = 0 To destBmp.Height - h Step h
                        'read the small image
                        bmp = New Bitmap(New IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes("c:\test\" & count.ToString & ".jpg").ToArray), False)
                        'draw on the temp Bmp
                        rect = New Rectangle(x, y, w, h)
                        dg.DrawImage(bmp, rect, New Rectangle(0, 0, w, h), GraphicsUnit.Pixel)
                        'dg.DrawRectangle(New Pen(Color.Red, 3), rect)
                        count += 1
                    Next
                Next
                'copy the destBmp to the form
                If Me.BackgroundImage IsNot Nothing Then Me.BackgroundImage = Nothing
                Me.BackgroundImage = CType(destBmp.Clone, Image)
            End Using
        End Using

        bmp.Dispose()
        BackgroundImageLayout = ImageLayout.Stretch

    End Sub
End Class

Thursday, May 21, 2015 3:22 PM ✅Answered

I made this function that uses bitblt to capture the screen. Seems to work at 125% on my win7.

Can someone test it in win 8?

Option Strict On

Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

Public Class Form4

    <DllImport("gdi32.dll")> _
    Private Shared Function BitBlt(ByVal hdc As IntPtr, ByVal nXDest As Integer, ByVal nYDest As Integer, ByVal nWidth As Integer, ByVal nHeight As Integer, ByVal hdcSrc As IntPtr, ByVal nXSrc As Integer, ByVal nYSrc As Integer, ByVal dwRop As TernaryRasterOperations) As Boolean
    End Function

    ''' <summary>
    '''     Specifies a raster-operation code. These codes define how the color data for the
    '''     source rectangle is to be combined with the color data for the destination
    '''     rectangle to achieve the final color.
    ''' </summary>
    Enum TernaryRasterOperations As UInteger
        ''' <summary>dest = source</summary>
        SRCCOPY = &HCC0020
        ''' <summary>dest = source OR dest</summary>
        SRCPAINT = &HEE0086
        ''' <summary>dest = source AND dest</summary>
        SRCAND = &H8800C6
        ''' <summary>dest = source XOR dest</summary>
        SRCINVERT = &H660046
        ''' <summary>dest = source AND (NOT dest)</summary>
        SRCERASE = &H440328
        ''' <summary>dest = (NOT source)</summary>
        NOTSRCCOPY = &H330008
        ''' <summary>dest = (NOT src) AND (NOT dest)</summary>
        NOTSRCERASE = &H1100A6
        ''' <summary>dest = (source AND pattern)</summary>
        MERGECOPY = &HC000CA
        ''' <summary>dest = (NOT source) OR dest</summary>
        MERGEPAINT = &HBB0226
        ''' <summary>dest = pattern</summary>
        PATCOPY = &HF00021
        ''' <summary>dest = DPSnoo</summary>
        PATPAINT = &HFB0A09
        ''' <summary>dest = pattern XOR dest</summary>
        PATINVERT = &H5A0049
        ''' <summary>dest = (NOT dest)</summary>
        DSTINVERT = &H550009
        ''' <summary>dest = BLACK</summary>
        BLACKNESS = &H42
        ''' <summary>dest = WHITE</summary>
        WHITENESS = &HFF0062
        ''' <summary>
        ''' Capture window as seen on screen.  This includes layered windows 
        ''' such as WPF windows with AllowsTransparency="true"
        ''' </summary>
        CAPTUREBLT = &H40000000
    End Enum


    <DllImport("gdi32.dll", EntryPoint:="DeleteDC")> Private Shared Function DeleteDC(ByVal hdc As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function GetDC(ByVal hwnd As IntPtr) As IntPtr
    End Function


    Public Function CaptureScreen(ix As Int32, iy As Int32, iw As Int32, ih As Int32) As Bitmap
        Using bmp As New Bitmap(iw, ih)
            Using gr1 As Graphics = Graphics.FromImage(bmp)
                Dim dc1 As IntPtr = gr1.GetHdc()
                Dim dc2 As IntPtr = GetDC(New IntPtr(0))
                BitBlt(dc1, ix, iy, iw, ih, dc2, ix, iy, CType(13369376, TernaryRasterOperations))

                CaptureScreen = CType(bmp.Clone, Bitmap)

                gr1.ReleaseHdc(dc1)
                DeleteDC(dc2)
            End Using
        End Using
    End Function

    Private Sub Form4_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim srcWidth As Integer = Screen.PrimaryScreen.Bounds.Width
        Dim srcHeight As Integer = Screen.PrimaryScreen.Bounds.Height
        BackgroundImage = CaptureScreen(0, 0, srcWidth, srcHeight)
        BackgroundImageLayout = ImageLayout.Stretch

    End Sub
End Class

Tuesday, May 19, 2015 12:46 AM

After creating the Bitmap, try this: (untested)

      Using g = Graphics.FromHwnd(IntPtr.Zero)
         B.SetResolution(g.DpiX, g.DpiY)
      End Using

Armin


Tuesday, May 19, 2015 12:59 AM

I cant duplicate the problem? Can you show the picture that does not look correct? Or describe exactly what you mean. Do you mean the screen does not look correct or your application?

What do you do with the bitmap B after you create it to view it? Can you show that code?

I started with your code with the same results as this example that draws the screen shot on the form. This is 125% and seems ok. My old clock etc gadgets don't look right is them.

Option Strict On
Imports System.Drawing.Drawing2D

Public Class Form3
    Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Using bmp As New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height), _
            g As Graphics = Graphics.FromImage(bmp)
            g.CopyFromScreen(0, 0, 0, 0, New Size(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height), CopyPixelOperation.SourceCopy)
            Me.BackgroundImage = CType(bmp.Clone, Image)
            Me.BackgroundImageLayout = ImageLayout.Stretch
        End Using
    End Sub
End Class

Tuesday, May 19, 2015 1:24 AM

It is a remote desktop viewing / controlling program.

Now I wonder if it is not the program on the client machine.   But on the receiving end.

  


Tuesday, May 19, 2015 1:32 AM

I just tested the client machine, by writing the file there.  and it show correct there.    Has to be on the receiving end when I create the file


Tuesday, May 19, 2015 1:41 AM

I just tested the client machine, by writing the file there.  and it show correct there.    Has to be on the receiving end when I create the file

The systems have different screen size?

Looks like an image captured at 1280 x 960 and shown on a form that is running at 1600 x 860 (the size of the image you posted) and it is spreading it out into small rectangle with the black space between.

Do you draw the small rectangles that make up the entire shot or what? What is the screen you show? Your application? Show the code that creates that screen. Or is this a 3rd party tool?


Tuesday, May 19, 2015 1:50 AM

I just tested the client machine, by writing the file there.  and it show correct there.    Has to be on the receiving end when I create the file

The systems have different screen size?

Looks like an image captured at 1280 x 960 and shown on a form that is running at 1600 x 860 (the size of the image you posted) and it is spreading it out into small rectangle with the black space between.

Do you draw the small rectangles that make up the entire shot or what? What is the screen you show? Your application? Show the code that creates that screen. Or is this a 3rd party tool?

PS Which systems have the larger dpi setting? The original source or what? It only happens then, right? It is hard to follow all the possible options you could have from what you describe.


Tuesday, May 19, 2015 1:55 AM

Yes, I discovered the same problem recently. CopyFromScreen is problematic with different OS version and user display settings.

So use Me.DrawtoBitmap instead ( if you are needing to copy from clientrectanlge ). This way I found returns consistent results regardless of user settings and OS version. The bitmap that you copy to must be the same size as the form. You can then use that.

cW = Clientsize.Width : cH = Clientsize.Height

        cscrn = New Bitmap(Width, Height)
        cL = CInt((Width - cW) / 2)
        cT = Height - cH - cL
        Me.DrawToBitmap(cscrn, New Rectangle(0, 0, cscrn.Width, cscrn.Height))

cL is the offset to point(0,0) of your clientrectangle

cT is the offset to point(0,0) of your clientrectangle

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Tuesday, May 19, 2015 1:56 AM

I just tested the client machine, by writing the file there.  and it show correct there.    Has to be on the receiving end when I create the file

Looks good to me. I don't see any issues in any code.

La vida loca


Tuesday, May 19, 2015 1:57 AM

Yes I create boxes.   I am now thinking the error is in there.  The DPI is higher on the remote machine.  My resolution is higher then the remote computer.   But the box issue only occurs when the DPI is not the default.    I now think I am on the right path,  the drawing of the boxes on my machine [receiving machine], is where the error is.


Tuesday, May 19, 2015 2:32 AM

Correction : -

This statement of mine - The bitmap that you copy to must be the same size as the form. - is probably wrong.

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Tuesday, May 19, 2015 6:37 PM

Below is the code.   I believe where I have ''Issue with different DPI might be here  

is here the issue is,  Thoughts

Public Sub PktToImage(ByVal BY As Byte())
        If btnStart.Text = "Stop" Then
            F.S.Send(Sock, "@" & F.Yy & CBImageSize.SelectedIndex & F.Yy & CBSplit.Text & F.Yy & NumericUpDown_Quality.Value)
        End If
        If op = Nothing Then
        Else
            If btnStart.Text = "Stop" Then
                Dim pp As New Point(0, 0)
                pp.X = op.X
                pp.Y = op.Y
                op = Nothing
                F.S.Send(Sock, "$" & F.Yy & pp.X & F.Yy & pp.Y & F.Yy)
            End If
        End If
        Dim B As Array = fx(BY, "njq8")
        Dim Q As New IO.MemoryStream(CType(B(1), Byte()))
        Dim L As Bitmap = Image.FromStream(Q)

        'L.Save("C:\Users\username\Desktop\test\RemoteDesktop" & picturenumber & ".bmp", Imaging.ImageFormat.Bmp)
        'picturenumber = picturenumber + 1
        Dim QQ As String() = Split(BS(B(0)), ",")
        Me.Text = "Remote Desktop  " & "Size: " & siz(BY.LongLength) & " , Changes: " & QQ.Length - 2
        Dim K As Bitmap = PB_RemoteDesktop.Image.GetThumbnailImage(CType(Split(QQ(0), ".")(0), Integer), CType(Split(QQ(0), ".")(1), Integer), Nothing, Nothing)
        Dim G As Graphics = Graphics.FromImage(K)
        Dim tp As Integer = 0
        For i As Integer = 1 To QQ.Length - 2
            ''Issue with different DPI might be here
            Dim P As New Point(Split(QQ(i), ".")(0), Split(QQ(i), ".")(1))
            Dim SZ As New Size(L.Width, Split(QQ(i), ".")(2))
            G.DrawImage(L.Clone(New Rectangle(0, tp, L.Width, CType(Split(QQ(i), ".")(2), Integer)), L.PixelFormat), New Point(CType(Split(QQ(i), ".")(0), Integer), CType(Split(QQ(i), ".")(1), Integer)))
            If CBShowLines.Checked Then
                Dim r As New Rectangle(Split(QQ(i), ".")(0), Split(QQ(i), ".")(1), SZ.Width, SZ.Height)
                G.DrawRectangle(Pens.Red, r)
            End If
            tp += SZ.Height
            ''Issue with different DPI might be here
        Next
        G.Dispose()
        PB_RemoteDesktop.Image = K
    End Sub


Tuesday, May 19, 2015 7:15 PM

Joe when you post your code please use the Insert Code button at the top of the editor window.

Why dont you simply what you are doing with the string QQ? Pre format it to an integer list or something simple instead of splitting it. Then you can step through it and look at the values.

What is QQ anyway? Explain more what you are doing.

Byt looking at the result The issue is obviously with the drawimage left, top locations of each of the rectangle. Since your source is set with:

    New Rectangle(0, tp, L.Width, CType(Split(QQ(i), ".")(2), Integer)

        the above the height = CType(Split(QQ(i), ".")(2), Integer

and the destination location is:

    New Point(CType(Split(QQ(i), ".")(0), Integer), CType(Split(QQ(i), ".")(1), Integer)))

          where left = CType(Split(QQ(i), ".")(0), Integer)
                   top =  CType(Split(QQ(i), ".")(1), Integer)

so again looking at the picture my guess is the left and top from the point statement above are mislocated because and or you have the wrong width and height for the source rectangle.

You should be able to look at those values while debugging as see exactly what is wrong.

It seems to me we cant do much not knowing what QQ is and not being able to run the source and step through the values you are seeing.


Tuesday, May 19, 2015 9:14 PM

PS Are you working with an image strip or something in QQ?

I tried to simplify the rest of it some and I cant spot anything below the define of QQ. Everything above that is unknown. See if you can sort out what you keep splitting out of QQ into and array or list or structure or class even? I guess these are properties of each source rectangle?

I suspect the values in QQ of course.

I tried to simplify below the QQ. Everyone has their style but to me this is easier to follow by defining each variable source, destination, top, left, width, height etc. It also makes it a lot easier for us to follow your code.

What is CBImageSize? And where is it coming from? and on and on...

        Dim QQ As String() = Split(BS(B(0)), ",")

        'Me.Text = "Remote Desktop  " & "Size: " & siz(BY.LongLength) & " , Changes: " & QQ.Length - 2

        Dim thumbWidth As Integer = CType(Split(QQ(0), ".")(0), Integer)
        Dim thumbHeight As Integer = CType(Split(QQ(0), ".")(1), Integer)

        Using K As Bitmap = PB_RemoteDesktop.Image.GetThumbnailImage(thumbWidth, thumbHeight, Nothing, Nothing)
            Using G As Graphics = Graphics.FromImage(K)
                Dim tp As Integer = 0

                For i As Integer = 1 To QQ.Length - 2

                    ''Issue with different DPI might be here
                    'Dim P As New Point(Split(QQ(i), ".")(0), Split(QQ(i), ".")(1))

                    'G.DrawImage(L.Clone(New Rectangle(0, tp, L.Width, CType(Split(QQ(i), ".")(2), Integer)), L.PixelFormat), _
                    '            New Point(CType(Split(QQ(i), ".")(0), Integer), CType(Split(QQ(i), ".")(1), Integer)))

                    Dim srcHeight As Integer = CType(Split(QQ(i), ".")(2), Integer)
                    Dim srcRect As Rectangle = New Rectangle(0, tp, srcBmp.Width, srcHeight)
                    Dim destLeft As Integer = CType(Split(QQ(i), ".")(0), Integer)
                    Dim destTop As Integer = CType(Split(QQ(i), ".")(1), Integer)

                    G.DrawImage(srcBmp.Clone(srcRect, srcBmp.PixelFormat), destLeft, destTop)

                    'Dim SZ As New Size(srcBmp.Width, srcHeight)   'Split(QQ(i), ".")(2)
                    'tp += SZ.Height
                    tp += srcHeight

                    'If CBShowLines.Checked Then
                    '    Dim r As New Rectangle(Split(QQ(i), ".")(0), Split(QQ(i), ".")(1), SZ.Width, SZ.Height)
                    '    G.DrawRectangle(Pens.Red, r)
                    'End If

                Next

                PB_RemoteDesktop.Image = K.Clone

            End Using
        End Using

Wednesday, May 20, 2015 1:52 AM

thanks, tommytwotrain that seems to clean up some of the code.   Still having the same issue.   I wrote this part of the code a year ago, so hard to follow [Since I have change how I write some of my code now].   I will just keep working on it,  thanks


Wednesday, May 20, 2015 10:28 AM

                    G.DrawImage(srcBmp.Clone(srcRect, srcBmp.PixelFormat), destLeft, destTop)

Hi Tommy,

as we've learned from another thread, don't forget to dispose the clone. :)

Armin


Wednesday, May 20, 2015 12:54 PM

Armin,

Yes, that is right. In fact I meant to mention I don't think the clone in the drawimage that you show is required at all.

And I am still wondering how the SetResolution that you show in your first post might affect things. I have never used it and don't really understand what it does. In the docs it says it does not change the size of the image, just the dpi which I have never been sure what that is in requards to bitmaps but I know there is one. Just never had to deal with it.


Wednesday, May 20, 2015 1:28 PM

Tommy,

a while ago, I was searching long for the reason why a drawn image was too small (or large). The simple reason turned out to be the bmp had a 72 dpi resolution whereas the target hasd 96 (or something). Before, I wasn't aware of this, too. Hence my first reply - when I didn't know yet the task is more complex than just drawing a single image.

Armin


Wednesday, May 20, 2015 2:07 PM

thanks, tommytwotrain that seems to clean up some of the code.   Still having the same issue.   I wrote this part of the code a year ago, so hard to follow [Since I have change how I write some of my code now].   I will just keep working on it,  thanks

I made an example that captures the source screen, creates a list of bitmaps of the 5 x 5 small rects from the source. Then draws the small rects on another bitmap and copies to the form. Seems to work.

Much easier to follow but I realize I dont fully understand how you are sending the images. Still this makes it easier to step through and look at the size of the images as you go. It also uses the same size variables over and over rather than redefining several times.

I think I have disposed everything?

Option Strict On
Imports System.Drawing.Drawing2D

Public Class Form3
    Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim rect As Rectangle
        Dim bmpList As New List(Of Bitmap)
        Dim numberRects As Integer = 5
        Dim srcWidth As Integer = Screen.PrimaryScreen.Bounds.Width
        Dim srcHeight As Integer = Screen.PrimaryScreen.Bounds.Height
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)

        'capture source screen and create list of small rect bitmaps
        Using srcBmp As New Bitmap(srcWidth, srcHeight), _
            g As Graphics = Graphics.FromImage(srcBmp)

            g.CopyFromScreen(0, 0, 0, 0, New Size(srcWidth, srcHeight), CopyPixelOperation.SourceCopy)

            'make a list of small rect bmps  5 x 5
            Using smallBmp As Bitmap = New Bitmap(w, h)
                Using sg As Graphics = Graphics.FromImage(smallBmp)
                    For x = 0 To srcWidth - w Step w
                        For y = 0 To srcHeight - h Step h
                            rect = New Rectangle(x, y, w, h)

                            'get the small rect from the source and draw on the temp smallBmp
                            sg.DrawImage(srcBmp, New Rectangle(0, 0, w, h), rect, GraphicsUnit.Pixel)
                            bmpList.Add(CType(smallBmp.Clone, Bitmap))
                        Next
                    Next
                End Using
            End Using
        End Using

        Dim listcount As Integer

        'now draw the list of small bmps to the form
        Using destBmp As Bitmap = New Bitmap(srcWidth, srcHeight)
            Using dg As Graphics = Graphics.FromImage(destBmp)
                For x = 0 To destBmp.Width - w Step w
                    For y = 0 To destBmp.Height - h Step h
                        rect = New Rectangle(x, y, w, h)
                        'get the small rect from the source and draw on the temp smallBmp
                        dg.DrawImage(bmpList(listcount), rect, New Rectangle(0, 0, w, h), GraphicsUnit.Pixel)
                        dg.DrawRectangle(New Pen(Color.Red, 3), rect)
                        listcount += 1
                    Next
                Next
                'copy the destBmp to the form
                If Me.BackgroundImage IsNot Nothing Then Me.BackgroundImage = Nothing
                Me.BackgroundImage = CType(destBmp.Clone, Image)
                Me.BackgroundImageLayout = ImageLayout.Stretch
            End Using
        End Using

        bmpList.Clear()
        bmpList = Nothing

    End Sub

Wednesday, May 20, 2015 2:12 PM

Tommy,

a while ago, I was searching long for the reason why a drawn image was too small (or large). The simple reason turned out to be the bmp had a 72 dpi resolution whereas the target hasd 96 (or something). Before, I wasn't aware of this, too. Hence my first reply - when I didn't know yet the task is more complex than just drawing a single image.

Armin

Yes when I submit advertising to mags they always complain my screen shots are low res. Beats me how to change it. Or even what the heck that is. Is not a dot a pixel? How can one go from 96 dots to 3600 dpi using a screen shot of pixels? Some internal thing I guess.

I still wonder if the dpi has anything to do with it. So first trying to sort out all the rectangle locations to make sure that is all up and up, then we shall see if the dpi problem is still there.

I don't understand the windows dpi setting fully either as I think it only applies to text somehow as the screen capture is the same size bitmap whether 96 ort 120 dpi setting in control panel.


Wednesday, May 20, 2015 3:25 PM

Yes when I submit advertising to mags they always complain my screen shots are low res. Beats me how to change it. Or even what the heck that is. Is not a dot a pixel? How can one go from 96 dots to 3600 dpi using a screen shot of pixels? Some internal thing I guess.

I still wonder if the dpi has anything to do with it. So first trying to sort out all the rectangle locations to make sure that is all up and up, then we shall see if the dpi problem is still there.

I don't understand the windows dpi setting fully either as I think it only applies to text somehow as the screen capture is the same size bitmap whether 96 ort 120 dpi setting in control panel.

I think it's most comprehensive if you print a bitmap: The printed size of a 96x96 pixels bitmap with a 96 dpi resolution will be 1x1 inches. If you set the bmp resolution to 10 dpi (by calling Bitmap.SetResolution), then the printed size will be 9.6 x 9.6 inches.

The same applies to the screen. If you create a new bitmap, it's resolution is set to the one of the screen, which is still often 96 dpi. This is the setting in the Windows control panel which not only refers to text. My screen has a physical resolution of 101.6 pixels per inch, but I can't set it to this exact value in control panel, so I keep it at 96 dpi. Consequently, a bitmap rendered to the screen is a bit smaller than it should be, but for me it's not important. For example, in an Office application with a DIN A4 sized page displayed at 100%, the physical paper held in front of the screen is a bit larger.

Unfortunatelly I don't understand "How can one go from 96 dots to 3600 dpi using a screen shot of pixels?" EDIT: I think I understand now. Either simply set the resolution to 3600 dpi, which will result in a very small image in the end, or enlarge the image and keep the 96 dpi (or enlarge the image and set it to 3600 dpi). Don't know what "they" need*.
*

Armin


Wednesday, May 20, 2015 3:44 PM

Yes when I submit advertising to mags they always complain my screen shots are low res. Beats me how to change it. Or even what the heck that is. Is not a dot a pixel? How can one go from 96 dots to 3600 dpi using a screen shot of pixels? Some internal thing I guess.

I still wonder if the dpi has anything to do with it. So first trying to sort out all the rectangle locations to make sure that is all up and up, then we shall see if the dpi problem is still there.

I don't understand the windows dpi setting fully either as I think it only applies to text somehow as the screen capture is the same size bitmap whether 96 ort 120 dpi setting in control panel.

I think it's most comprehensive if you print a bitmap: The printed size of a 96x96 pixels bitmap with a 96 dpi resolution will be 1x1 inches. If you set the bmp resolution to 10 dpi (by calling Bitmap.SetResolution), then the printed size will be 9.6 x 9.6 inches.

The same applies to the screen. If you create a new bitmap, it's resolution is set to the one of the screen, which is still often 96 dpi. This is the setting in the Windows control panel which not only refers to text. My screen has a physical resolution of 101.6 pixels per inch, but I can't set it to this exact value in control panel, so I keep it at 96 dpi. Consequently, a bitmap rendered to the screen is a bit smaller than it should be, but for me it's not important. For example, in an Office application with a DIN A4 sized page displayed at 100%, the physical paper held in front of the screen is a bit larger.

Unfortunatelly I don't understand "How can one go from 96 dots to 3600 dpi using a screen shot of pixels?"

Armin

"Unfortunatelly I don't understand "How can one go from 96 dots to 3600 dpi using a screen shot of pixels?"

Well,

"The printed size of a 96x96 pixels bitmap with a 96 dpi resolution will be 1x1 inches. If you set the bmp resolution to 10 dpi (by calling Bitmap.SetResolution), then the printed size will be 9.6 x 9.6 inches."

To me all this did was make a new bitmap 10x bigger. The new bitmap still has the same number of original pixels, 96, but now it is drawn across 96/10 inches instead of 1. So on a 600 dpi printer it is really (96/10)/600 = 0.16 original pixels/dot on paper. So its really using the same pixel 10 times to get 600 dpi and you get a fuzzy mess on paper.

I see where your screen res of 101.6 is that many pixels and if windows is 96 dpi then it must be drawing a scaled bitmap of 96/101.6 = 0.94 pixels from the original bitmap on 1 pixels on the screen.

Again, the original bitmap pixel res did not change the screen resolution did. Just like the printer resolution is different, but the original bitmap pixels are not??? How can they change without re-drawing.

So I still dont see where you can change the bitmap res after it is captured. It sounds like the pixels are constant just some size def in the bitmap is different.

Its not real important yet as far as this thread goes. I may do some tests using 96 and 120 screen captures and see where the difference lies if any.


Wednesday, May 20, 2015 4:25 PM

Tommy,

sorry that I've edited my last reply after posting, but it doesn't matter.

Before writing more about it, I wonder why not just apply my first reply to the bitmap being painted? Doesn't it solve everything?

Armin


Wednesday, May 20, 2015 4:49 PM

Tommy,

sorry that I've edited my last reply after posting, but it doesn't matter.

Before writing more about it, I wonder why not just apply my first reply to the bitmap being painted? Doesn't it solve everything?

Armin

Yes, I am wondering the same thing.

However, as I have been saying, I cant duplicate the original problem. So there is nothing to solve IMHO.

I think the rectangles are just not being drawn at the correct locations but we cant tell since the data is in the QQ string of Joe's example code and we cant see it or how he made it.

The pixel size of the screen capture bitmap is the same whether 96 or 120 dpi. Try it.  I mean the size you get from bmpcaptured.width etc. The icons and text are bigger in the 120 dpi image, just the overall screen image is the same at both dpi resolutions.

I am trying to think of an example we can use to test with that shows something.


Wednesday, May 20, 2015 5:01 PM

PS

"EDIT: I think I understand now. Either simply set the resolution to 3600 dpi, which will result in a very small image in the end, or enlarge the image and keep the 96 dpi (or enlarge the image and set it to 3600 dpi). "

Yes that is what I mean more or less. We take a 100 pixel bitmap. We draw it unchanged 1:1 on a 600 dpi printer it will be 100/600 inches on the paper.

   drawimage(bmp, 0,0,100,100, 0, 0, 100, 100)

Or we redraw it on a graphic (the printer) and we

   drawimage(bmp, 0,0,600,600, 0, 0, 100, 100)

and this is spreading 1 pixel from the original across 6 pixels on the printer paper so the paper image is 600 pixels or 1 inch.

Or, my guess, if we set the bitmap res to 600 then we draw 1:1 but really vb redraws it 1:6  to the printer.


Wednesday, May 20, 2015 5:21 PM

PS

My guess is Joe is captureing a 1280 pixel bitmap, dividing it into rectangles w1 = 1280/5 and then redrawing on a larger res screen 1600 pixels by saying w2 = 1600/5 but that is not correct. W1 the width of the original rectangle has not changed.

So Joe gets the value of left for the second rect Left = w2 but it should be Left = w1. Thus the black areas between rectangles in Joes screen shot.

When he draws it with the correct width spacing, after all 5 rects are redrawn the total width will be 1280, same as the original, on a 1600 pixel screen and you have 320 pixels at the right side that are blank or black.

Now I know how to show it in an example...


Wednesday, May 20, 2015 6:48 PM

PS

My guess is Joe is captureing a 1280 pixel bitmap, dividing it into rectangles w1 = 1280/5 and then redrawing on a larger res screen 1600 pixels by saying w2 = 1600/5 but that is not correct. W1 the width of the original rectangle has not changed.

So Joe gets the value of left for the second rect Left = w2 but it should be Left = w1. Thus the black areas between rectangles in Joes screen shot.

When he draws it with the correct width spacing, after all 5 rects are redrawn the total width will be 1280, same as the original, on a 1600 pixel screen and you have 320 pixels at the right side that are blank or black.

Now I know how to show it in an example...

Here is a sample. The image on the left is the screen at 120dpi(125%) and on the right 96dpi (100%). This image is a full size cropped screen shot. You will have to zoom to see it full size but I think you see the point even at reduced size.

The icons and text on the left are bigger, but Rusty's bitmap is the same at both res. The screen wall paper image is the same. The captured screen is the same size in pixels.

I will be back in a while to post my example.


Wednesday, May 20, 2015 6:59 PM

Here is my latest, I just changed it so it captures the srcPic from the SourceForm and processes it in the main form1. Works the same both resolutions as seen above.

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(400, 400)
        'show captured source image actual size
        Me.BackgroundImageLayout = ImageLayout.None

        SourceForm.Show()

    End Sub

    Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
        Me.BackColor = Color.Black


        'capture the source
        Dim rect As Rectangle
        Dim bmpList As New List(Of Bitmap)
        Dim numberRects As Integer = 5

        Dim srcWidth As Integer = SourceForm.srcPic.ClientSize.Width     'Screen.PrimaryScreen.Bounds.Width
        Dim srcHeight As Integer = SourceForm.srcPic.ClientSize.Height
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)

        'capture source screen and create list of small rect bitmaps
        Using srcBmp As New Bitmap(srcWidth, srcHeight), _
            g As Graphics = Graphics.FromImage(srcBmp)

            SourceForm.srcPic.DrawToBitmap(srcBmp, New Rectangle(0, 0, srcWidth, srcHeight))

            'make a list of small rect bmps  5 x 5
            Using smallBmp As Bitmap = New Bitmap(w, h)
                Using sg As Graphics = Graphics.FromImage(smallBmp)
                    For x = 0 To srcWidth - w Step w
                        For y = 0 To srcHeight - h Step h
                            rect = New Rectangle(x, y, w, h)

                            'get the small rect from the source and draw on the temp smallBmp
                            sg.DrawImage(srcBmp, New Rectangle(0, 0, w, h), rect, GraphicsUnit.Pixel)
                            bmpList.Add(CType(smallBmp.Clone, Bitmap))
                        Next
                    Next
                End Using
            End Using
        End Using

        Dim listcount As Integer


        'w = Me.ClientSize.Width / numberRects
        'h = Me.ClientSize.Width / numberRects
        'Using destBmp As Bitmap = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Width)
        '    Using dg As Graphics = Graphics.FromImage(destBmp)

        'now draw the list of small bmps to the form
        Using destBmp As Bitmap = New Bitmap(srcWidth, srcHeight)
            Using dg As Graphics = Graphics.FromImage(destBmp)
                For x = 0 To destBmp.Width - w Step w
                    For y = 0 To destBmp.Height - h Step h
                        rect = New Rectangle(x, y, w, h)
                        'get the small rect from the source and draw on the temp smallBmp
                        dg.DrawImage(bmpList(listcount), rect, New Rectangle(0, 0, w, h), GraphicsUnit.Pixel)
                        dg.DrawRectangle(New Pen(Color.Red, 3), rect)
                        listcount += 1
                    Next
                Next
                'copy the destBmp to the form
                If Me.BackgroundImage IsNot Nothing Then Me.BackgroundImage = Nothing
                Me.BackgroundImage = CType(destBmp.Clone, Image)

            End Using
        End Using

        bmpList.Clear()
        bmpList = Nothing

    End Sub

End Class
Public Class SourceForm

    Private Sub SourceForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(310, 310)
        srcPic.Location = New Point(0, 0)
        srcPic.ClientSize = New Size(300, 300)
        srcPic.BackgroundImage = New Bitmap("c:\bitmaps\rusty.jpg")
        srcPic.BackgroundImageLayout = ImageLayout.Stretch

        'stretch the image so its 300x300
        Me.Text = "Source Screen"
        Me.BackColor = Color.Black

    End Sub
End Class

Now if you change these lines by uncommenting the commented and commenting the others so you are setting the rectangle size based on the form1 dest screen size you get the error.

        'w = Me.ClientSize.Width / numberRects
        'h = Me.ClientSize.Width / numberRects
        'Using destBmp As Bitmap = New Bitmap(Me.ClientSize.Width, Me.ClientSize.Width)
        '    Using dg As Graphics = Graphics.FromImage(destBmp)

        'now draw the list of small bmps to the form
        Using destBmp As Bitmap = New Bitmap(srcWidth, srcHeight)
            Using dg As Graphics = Graphics.FromImage(destBmp)


Wednesday, May 20, 2015 7:03 PM

PS note the form1 size is 400 x 400 while the source pic is 300 x 300.

Thus on form1 there is 100 pixels of empty black space on the right and bottom when drawn correctly (edit: as shown below).

So the source is one screen and the form1 is another at a different pixel size.


Wednesday, May 20, 2015 9:27 PM

You would think I dont have anything better to do?

I made this example which saves the small rectangle grid files to disc when you click the source form and then reads them and draws the composite on form1 when you click form1.

This way you can run the project at 125% and save the files and then restart in 100% and read the files to see the image. Or you can do it the other way. Works!

@ Armin,

Ha, I cant seem to dispose the bmplist or whatever reference back to the file because when your run the project, first click form1 to read and draw the files (you need to make them first), and then click the sourceform to save the files again after drawing them, it gives a gdi error which I bet is the file is in use? I cant figure how to get rid of it (again). But thats another subject I guess.

:)

Put this code in the form1 startup form of a new project.

Public Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(400, 400)
        'show captured source image actual size
        Me.BackgroundImageLayout = ImageLayout.None

        SourceForm.Show()

    End Sub

    Private Sub Form1_Click(sender As Object, e As EventArgs) Handles Me.Click
        Dim myDpi As Integer

        'Using g As Graphics = Me.CreateGraphics
        '    myDpi = g.DpiX
        'End Using
        'MsgBox(myDpi.ToString)

        Me.BackColor = Color.Black

        'read the files into a list of bitmaps
        Dim bmpList As New List(Of Bitmap)

        For i = 0 To 24
            Dim img As Image = Image.FromFile("c:\test\" & i.ToString & ".jpg")
            Dim bmp As New Bitmap(img)
            img.Dispose()
            img = Nothing
            bmpList.Add(CType(bmp.Clone, Bitmap))
            bmp.Dispose()
        Next

        Dim numberRects As Integer = 5
        Dim srcWidth As Integer = numberRects * bmpList(0).Width
        Dim srcHeight As Integer = numberRects * bmpList(0).Height
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)

        Dim listcount As Integer
        Dim rect As Rectangle

        'now draw the list of small bmps to the form
        Using destBmp As Bitmap = New Bitmap(srcWidth, srcHeight)
            Using dg As Graphics = Graphics.FromImage(destBmp)
                For x = 0 To destBmp.Width - w Step w
                    For y = 0 To destBmp.Height - h Step h
                        rect = New Rectangle(x, y, w, h)
                        'get the small rect from the source and draw on the temp smallBmp
                        dg.DrawImage(bmpList(listcount), rect, New Rectangle(0, 0, w, h), GraphicsUnit.Pixel)
                        'dg.DrawRectangle(New Pen(Color.Red, 3), rect)
                        listcount += 1
                    Next
                Next
                'copy the destBmp to the form
                If Me.BackgroundImage IsNot Nothing Then Me.BackgroundImage = Nothing
                Me.BackgroundImage = CType(destBmp.Clone, Image)
            End Using
        End Using

        bmpList.Clear()
        bmpList = Nothing

    End Sub
End Class

Create a second form named SourceForm and add this code.

Public Class SourceForm

    Private Sub SourceForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.ClientSize = New Size(310, 310)
        srcPic.Location = New Point(0, 0)
        srcPic.ClientSize = New Size(300, 300)
        srcPic.BackgroundImage = New Bitmap("c:\bitmaps\rusty.jpg")
        srcPic.BackgroundImageLayout = ImageLayout.Stretch

        'stretch the image so its 300x300
        Me.Text = "Click to Save Source Screen Files"
        Me.BackColor = Color.Black

    End Sub

    Private Sub srcPic_Click(sender As Object, e As EventArgs) Handles srcPic.Click

        'capture the image and save it to file
        Dim rect As Rectangle
        Dim bmpList As New List(Of Bitmap)
        Dim numberRects As Integer = 5

        Dim srcWidth As Integer = srcPic.ClientSize.Width     'Screen.PrimaryScreen.Bounds.Width
        Dim srcHeight As Integer = srcPic.ClientSize.Height
        Dim w As Integer = CInt(srcWidth / numberRects)
        Dim h As Integer = CInt(srcHeight / numberRects)

        'capture source screen and create list of small rect bitmaps
        Using srcBmp As New Bitmap(srcWidth, srcHeight), _
            g As Graphics = Graphics.FromImage(srcBmp)

            srcPic.DrawToBitmap(srcBmp, New Rectangle(0, 0, srcWidth, srcHeight))

            'save the small rect bmps  5 x 5 grid
            Dim count As Integer

            Using smallBmp As Bitmap = New Bitmap(w, h)
                Using sg As Graphics = Graphics.FromImage(smallBmp)
                    For x = 0 To srcWidth - w Step w
                        For y = 0 To srcHeight - h Step h
                            rect = New Rectangle(x, y, w, h)
                            'get the small rect from the source and draw on the temp smallBmp and save it
                            sg.DrawImage(srcBmp, New Rectangle(0, 0, w, h), rect, GraphicsUnit.Pixel)
                            smallBmp.Save("c:\test\" & count.ToString & ".jpg")
                            srcPic.Image = smallBmp.Clone
                            srcPic.Refresh()
                            count += 1
                        Next
                    Next

                    MsgBox((count).ToString & " files saved")
                End Using
            End Using
        End Using
    End Sub
End Class

Wednesday, May 20, 2015 10:04 PM

when your run the project, first click form1 to read and draw the files (you need to make them first), and then click the sourceform to save the files again after drawing them, it gives a gdi error which I bet is the file is in use? I cant figure how to get rid of it (again). But thats another subject I guess.

Hi,

open the imagefile from disk, create a new deep copy just like

Dim bmp as New Bitmap(imgFileVariableName)

and dispose the opened image from disk immediately. Then the file isnt blocked anymore on disk.

Dim img as Image = Image.FromFile(filePath)
Dim bmp as new Bitmap(img)
img.Dispose()
img = Nothing

(or put img in a using bloxk) then use the bmp.

Note that this way, always a 32bpp Bitmap is created.

Regards,

  Thorsten


Wednesday, May 20, 2015 10:20 PM

when your run the project, first click form1 to read and draw the files (you need to make them first), and then click the sourceform to save the files again after drawing them, it gives a gdi error which I bet is the file is in use? I cant figure how to get rid of it (again). But thats another subject I guess.

Hi,

open the imagefile from disk, create a new deep copy just like

Dim bmp as New Bitmap(imgFileVariableName)

and dispose the opened image from disk immediately. Then the file isnt blocked anymore on disk.

Dim img as Image = Image.FromFile(filePath)
Dim bmp as new Bitmap(img)
img.Dispose()
img = Nothing

(or put img in a using bloxk) then use the bmp.

Note that this way, always a 32bpp Bitmap is created.

Regards,

  Thorsten

Hi Thorsten!

That works. I changed my last example so you can save and draw repeatedly now.


Wednesday, May 20, 2015 10:57 PM

One other comment. One can set the form or pic background to stretch to fill the dest with the image after it is made. One could also draw it the size of the dest. Which could be what Joe was doing. Lots of ways to go with it. I am just trying to see if the difference in the screen dpi has any real size effect other than in the original image itself (ie the text and icons are bigger).


Wednesday, May 20, 2015 11:19 PM

when your run the project, first click form1 to read and draw the files (you need to make them first), and then click the sourceform to save the files again after drawing them, it gives a gdi error which I bet is the file is in use? I cant figure how to get rid of it (again). But thats another subject I guess.

Hi,

open the imagefile from disk, create a new deep copy just like

Dim bmp as New Bitmap(imgFileVariableName)

and dispose the opened image from disk immediately. Then the file isnt blocked anymore on disk.

Dim img as Image = Image.FromFile(filePath)
Dim bmp as new Bitmap(img)
img.Dispose()
img = Nothing

(or put img in a using bloxk) then use the bmp.

Note that this way, always a 32bpp Bitmap is created.

Regards,

  Thorsten

Another way to do this : -

S = <pathname>

bmp = New Bitmap(New IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes(S).ToArray), False)

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Wednesday, May 20, 2015 11:34 PM

Another way to do this : -

S = <pathname>

bmp = New Bitmap(New IO.MemoryStream(My.Computer.FileSystem.ReadAllBytes(S).ToArray), False)

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!

Yes that works too! Good one.

I wonder why? Does using a stream not keep the file reference open (or whatever it is) like the new bitmap(filepath) does?

Looks more like Joe's task this way.


Wednesday, May 20, 2015 11:42 PM

Joe

Regarding your original question in this thread. How to deal with CopyFromScreen. It appears all the GDI functions are complicit with changes in Control Panel >>  Display Settings . . except for CopyFromScreen - - - it appears to be a framework bug.

Here is my thread about the same issue : -

https://social.msdn.microsoft.com/Forums/vstudio/en-US/9848357a-c8fb-401d-8798-3e423462a56f/query-the-users-control-panel-display-setting?forum=vbgeneral

Notice Mr.Monkeyboys' code for querying the Virtual pixel dimensions versus the Factory pixel dimensions.

. . . . but unfortunately . . . . it works fine pre Windows 8  - - - but with windows 8 the query always returns the factory dimensions when you query the virtual dimensions.

I repeat what I said before - - if you need to copy only from your forms UI then use Me.DrawToBitmap.

But if you need to copy from outside your form, one work around is to add a user changeable property - - so the user sets it according to the control panel settings - -  and copyfromscreen can be scaled correctly.

Another possibility is to find out how to use the 'print screen' API call - - and read the image from the clipboard. ? ? ?

Cheers

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Thursday, May 21, 2015 12:00 AM

Regarding your original question in this thread. How to deal with CopyFromScreen. It appears all the GDI functions are complicit with changes in Control Panel >>  Display Settings . . except for CopyFromScreen - - - it appears to be a framework bug.

I can not agree with this. Whenever you create a new Bitmap, it's resolution is set to the one of the desktop. CopyFromScreen then just copies the screen without changing the resolution of the target Bitmap. I've just tried it again.

Though I still will read the link to your other thread.

Armin


Thursday, May 21, 2015 12:02 AM

I can not agree with this. Whenever you create a new Bitmap, it's resolution is set to the one of the desktop. CopyFromScreen then just copies the screen without changing the resolution of the target Bitmap. I've just tried it again.

I should add what could make a difference: Win 7 + Framework 3.5

Armin


Thursday, May 21, 2015 1:39 AM

Lots of into to go though.   A lot of ideas.   I currently have my program on .net 3.5  upgraded from 2.0.   didn't move to .net 4 yet, until I get the XP machines moved off.

THanks everyone,  will look this all over.

Just so everyone know this is for a remote assistance program.

As of now from XP - Windows 8,  and soon 10


Thursday, May 21, 2015 9:09 AM

Armin,

You may be right. I have always avoided all units of measure except for Pixel. Never used twips or dpi - - always just pixel. Something for me to look into.

Thanks

@ Tommy

I never had any trouble with windows 7 either. Only when I used Win 8 did it run into trouble.

Cheers

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Thursday, May 21, 2015 1:47 PM

Armin,

You may be right. I have always avoided all units of measure except for Pixel. Never used twips or dpi - - always just pixel. Something for me to look into.

Thanks

@ Tommy

I never had any trouble with windows 7 either. Only when I used Win 8 did it run into trouble.

Cheers

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!

Oh, I see. Windows 8.

Well, I am going to have to get that someday. Oh, wait, I decided to wait for version 10.

I think Joe said he was using win 7 as far as his first post goes. Unless I missed the 8.

I have found some funny things to do with the high res monitors, like the retina displays (apple) that seem to have double the pixels but act like the normal pixels. Also tablets that have the gravity thing to switch to landscape/portrait (ie rotates 90) etc. Maybe that is part of it? There must be something new in win 8 to deal with it?

Also, just more info, I noticed yesterday in win 7 when you use Ctrl+PrtScn to copy the screen to the clipboard on a dual monitor system it captures both screens in one image and puts it on the clipboard so that would mess up the size as well it that happens with other things.


Thursday, May 21, 2015 8:55 PM

Just want to give some info.  The QQ that I had defined in the original code, stores what images need to be changed.  I have since cleaned up the def. for that.

Still reading though all the info, that has been posted

Thanks


Friday, May 22, 2015 4:49 AM

Tommy,

Can someone test it in win 8?

I tested your code. VS2013  Win 8.1

CP dispay setting 100% - - - your code copied the whole screen

CP dispay setting 125% - - - your code copied top/left 80% of the screen

CP dispay setting 150% - - - your code copied top/left 67% of the screen

 

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!


Friday, May 22, 2015 12:13 PM

Can someone test it in win 8?

I tested your code. VS2013  Win 8.1

CP dispay setting 100% - - - your code copied the whole screen

CP dispay setting 125% - - - your code copied top/left 80% of the screen

CP dispay setting 150% - - - your code copied top/left 67% of the screen

 

Framewok 3.5, Win 10 Preview:

100%: whole screen
125%: whole screen
150%: portion of the screen

!?

However, I just see that a Clone is being created again. Why? I've modified it to return the Bitmap on which the screen shot is being drawn.

Then I've drawn the bitmap's dpi onto the screenshot. The (surprising?) result:

100%: dpi=96
125%: dpi=120
150%: dpi=96 (yes, 96 again)

Which dpi's are shown on Windows 8? (in the top-left corner of the screenshot)

   Public Function CaptureScreen(ByVal ix As Int32, ByVal iy As Int32, ByVal iw As Int32, ByVal ih As Int32) As Bitmap
      Dim bmp As New Bitmap(iw, ih)

      Using gr1 As Graphics = Graphics.FromImage(bmp)
         Dim dc1 As IntPtr = gr1.GetHdc()
         Dim dc2 As IntPtr = GetDC(New IntPtr(0))
         BitBlt(dc1, ix, iy, iw, ih, dc2, ix, iy, CType(13369376, TernaryRasterOperations))

         gr1.ReleaseHdc(dc1)
         DeleteDC(dc2)
         gr1.DrawString(bmp.HorizontalResolution & "   " & bmp.VerticalResolution, Font, Brushes.Yellow, 0, 0)
      End Using

      Return bmp

   End Function

Armin


Friday, May 22, 2015 12:14 PM

Tommy,

Can someone test it in win 8?

I tested your code. VS2013  Win 8.1

CP dispay setting 100% - - - your code copied the whole screen

CP dispay setting 125% - - - your code copied top/left 80% of the screen

CP dispay setting 150% - - - your code copied top/left 67% of the screen

 

Top Tip: Toothache? Cut paper towel to 2"square. Smear with olive oil. Sprinkle on Cayenne Pepper. Fold over few times to form small wad. Tuck in between wall of mouth and gum. Leave 1 - 2 hrs. You will thank me!

Leon,

I see. Hmmm. Thanks for testing it.

Makes me think it is the values for Screen.PrimaryScreen.Bounds.Width that are not correct?

I don't know if you are interested in doing more on this. What values do you show it giving if you break at the sub call and view the variables?

Or what if you just put in the actual size is 1028 x 760 or whatever your monitor is? I guess that is what you mean by work around it by having a user setting.

And you say if you check g.dpix somehow those are not set correctly as well (from the other thread)?

PS or what about Armin's suggestion for:

      Using g = Graphics.FromHwnd(IntPtr.Zero)
         B.SetResolution(g.DpiX, g.DpiY)
      End Using

does g.dipx give the correct value or if you insert this in my bitblt example does it do anything to the bmp bitmap and the drawing?


Friday, May 22, 2015 12:37 PM

Makes me think it is the values for Screen.PrimaryScreen.Bounds.Width that are not correct?

Good point. Didn't think ot that. Just tried it: You are right, the values are different. At a screen size of 1600x1200, the bitmap size is:

100%: 1600x1200
125%: 1600x1200
150%: 1067x800

Don't know if this is "by design".

Armin


Friday, May 22, 2015 12:39 PM

Armin,

"However, I just see that a Clone is being created again. Why? "

Because if its not there it errs on me.backgroundimage = bmp saying bmp is invalid parameter. I assume the image ref is gone when the dc is disposed? Do you have another way?

There must be a new something to use in win 8 and beyond to get these values.


Friday, May 22, 2015 12:47 PM

100%: 1600x1200

125%: 1600x1200
150%: 1067x800

Don't know if this is "by design".

The reference source (FW 4.5) says that the values are returned either from System.Windows.Forms.SystemInformation.VirtualScreen or from the GetMonitorInfo API function (user32.dll). The latter returns the numbers in "virtual-screen coordinates" (see MONITORINFOEX structure). The former calls GetSystemMetrics (passing SM_CXVIRTUALSCREEN resp. SM_CYVIRTUALSCREEN) to get the size, which is "The width of the virtual screen, in pixels." (Link).

EDIT: SystemInformation.VirtualScreen is used if there is no multi-monitor support or if the monitor is the primary monitor.

Armin


Friday, May 22, 2015 12:52 PM

"However, I just see that a Clone is being created again. Why? "

Because if its not there it errs on me.backgroundimage = bmp saying bmp is invalid parameter. I assume the image ref is gone when the dc is disposed? Do you have another way?

Probably because you dispose bmp (Using...End Using). See my modified code which doesn't dispose it. It worked.

Armin


Friday, May 22, 2015 12:56 PM

This...

Writing DPI-Aware Desktop and Win32 Application

...says that GetSystemMetrics(SM_CXVIRTUALSCREEN) returns the logical width whereas QueryDisplayConfig returns the physical width.

For simplicity, I've made another run by hard-coding the arguments for calling CaptureScreen to 1600x1200. Now, always the whole screen is captured at all three settings (100%, 125%, 150%). However, the DPI values are still 96, 120, 96.

Armin


Friday, May 22, 2015 1:08 PM

"However, I just see that a Clone is being created again. Why? "

Because if its not there it errs on me.backgroundimage = bmp saying bmp is invalid parameter. I assume the image ref is gone when the dc is disposed? Do you have another way?

Probably because you dispose bmp (Using...End Using). See my modified code which doesn't dispose it. It worked.

Armin

Oh, I see.

Well, probably don't need to get into this again. But, isnt that the same as making a clone? Since bmp is not disposed?

I guess one should add:

        If BackgroundImage IsNot Nothing Then BackgroundImage = Nothing
        BackgroundImage = CaptureScreen(0, 0, srcWidth, srcHeight)

in either case?

I am just trying to sort it out the differences in my mind.

I am looking through your links...


Friday, May 22, 2015 1:23 PM

I guess one should add:

        If BackgroundImage IsNot Nothing Then BackgroundImage = Nothing
        BackgroundImage = CaptureScreen(0, 0, srcWidth, srcHeight)

in either case?

I am just trying to sort it out the differences in my mind.

I am looking through your links...

Well, the code above is functional equal to

        BackgroundImage = Nothing
        BackgroundImage = CaptureScreen(0, 0, srcWidth, srcHeight)

which again is equal to

        BackgroundImage = CaptureScreen(0, 0, srcWidth, srcHeight)

:)

However, I don't know why to do this because it's excecuted only once anyway.

If you do change the property multiple times, you'd have to...:

   dim tmp = backgroundimage
   backgroundimage = the new backgroundimage
   tmp.dispose

You wrote: "But, isnt that the same as making a clone? Since bmp is not disposed?"

I reply: I wanted to avoid cloing only because it's a) an additional error source, b) not necessary.

Armin