问题
I have an app which properly captures the image of an application window if it is in the upper-left corner of the primary screen.
But if it is not, the image size is not correct (the window image height becomes stretched if it is against the right margin and down from the screen top. Application at 0,0
Imports System.Data.SqlClient
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic.Strings
Imports System
Imports System.Data
Imports System.Data.OleDb
Public Class Form1
Public Declare Function GetWindowRect Lib "user32" (ByVal HWND As Integer, ByRef lpRect As Rectangle) As Integer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub BtnCapture_Click(sender As Object, e As EventArgs) Handles BtnCapture.Click
Dim FoundApplication As Boolean = False
Dim localAll As Process() = Process.GetProcesses()
Dim rect As New Rectangle
Dim Top As Int32 = 0
Dim Left As Int32 = 0
Dim width As Int32
Dim height As Int32
Dim hwnd As IntPtr
Dim memoryImage As Bitmap
For Each x As Process In localAll
GetWindowRect(x.MainWindowHandle, rect)
If x.ProcessName.ToString = "calc" Then
width = rect.Width
height = rect.Height
Top = rect.Top
Left = rect.Left
hwnd = x.MainWindowHandle
FoundApplication = True
Exit For
End If
Next
If FoundApplication Then
' do nothing - set above
Else
' set the default to entire Primary screen if Calc not found
width = Screen.PrimaryScreen.Bounds.Width
height = Screen.PrimaryScreen.Bounds.Height
End If
Dim MyGraphics As Graphics = Graphics.FromHwnd(hwnd)
Dim s As New Size(width, height)
memoryImage = New Bitmap(width, height, myGraphics)
Dim memoryGraphics As Graphics = Graphics.FromImage(memoryImage)
memoryGraphics.CopyFromScreen(Top, Left, 0, 0, s)
Clipboard.SetImage(memoryImage)
RtbLog.AppendText(Today().ToShortDateString & " " & Now().ToShortTimeString & vbCrLf)
RtbLog.Paste()
myGraphics.Dispose()
End Sub
End Class
This simple version exhibits the behavior I am dealing with.
If the "calc" is in the upper left corner it's perfect - move it down or to the left and the image includes other parts of the screen and may cut off the image of "calc".
回答1:
Your code can be simplified in some details.
First of all, as already mentioned in the comments, your declaration of GetWindowRect() is not correct. You need to pass it a Window handle, usually in the form of an IntPtr structure, and a RECT structure.
Refer to the PInvoke website when you need to include a Windows API function call in your code. The experience of many programmers has forged :) those lines of code.
The Desktop size, here, is returned by SystemInformation.PrimaryMonitorSize.
You could also use Screen.PrimaryScreen.Bounds or SystemInformation.VirtualScreen.
Choose the one that best fits your plans.
Imports System.Diagnostics
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Runtime.InteropServices
<DllImport("user32.dll")>
Private Shared Function GetWindowRect(ByVal hWnd As IntPtr, ByRef lpRect As RECT) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure RECT
Public Left As Integer
Public Top As Integer
Public Right As Integer
Public Bottom As Integer
End Structure
Private Sub BtnCapture_Click(sender As Object, e As EventArgs) Handles BtnCapture.Click
Dim wRect As RECT = Nothing
Dim WindowArea As Rectangle = Nothing
Dim FindProcess As Process = Process.GetProcessesByName("calc").FirstOrDefault()
If FindProcess IsNot Nothing AndAlso CInt(FindProcess.MainWindowHandle) > 0 Then
If GetWindowRect(FindProcess.MainWindowHandle, wRect) Then
WindowArea = Rectangle.FromLTRB(wRect.Left, wRect.Top, wRect.Right, wRect.Bottom)
End If
End If
If WindowArea = Nothing Then WindowArea = New Rectangle(Point.Empty, SystemInformation.PrimaryMonitorSize)
Using img As Image = New Bitmap(WindowArea.Width, WindowArea.Height, PixelFormat.Format32bppArgb)
Using g As Graphics = Graphics.FromImage(img)
g.SmoothingMode = SmoothingMode.HighQuality
g.CopyFromScreen(WindowArea.Location, Point.Empty, WindowArea.Size, CopyPixelOperation.SourceCopy)
img.Save("[The Image Path]", ImageFormat.Png)
ScaleToClipboard(img, 65.0F) '65% of its original size or
End Using
End Using
'(...) Other processing
End Sub
Edit:
A method to save the original image to disk, reduce the source Image size to a specific size or to a fraction of it, then set the modified Image to the ClipBoard, ready to be pasted in some recepient.
ScaleToClipboard([Source Image], [Percent of Original] As Single)
ScaleToClipboard([Source Image], [Specific Size] As Size)
Example:ScaleToClipboard([Source Image], 72.0F)
ScaleToClipboard([Source Image], New Size(200, 125))
Private Sub ScaleToClipboard(SourceImage As Image, SizeScale As Single)
Dim NewSize As SizeF = New SizeF((SourceImage.Width \ 100) * SizeScale, (SourceImage.Height \ 100) * SizeScale)
ScaleToClipboard(SourceImage, Size.Round(NewSize))
End Sub
Private Sub ScaleToClipboard(SourceImage As Image, SizeScale As Size)
Using img As Image = New Bitmap(SourceImage, Size.Round(SizeScale))
Using g As Graphics = Graphics.FromImage(img)
g.SmoothingMode = SmoothingMode.HighQuality
g.InterpolationMode = InterpolationMode.HighQualityBicubic
g.DrawImage(SourceImage, New Rectangle(Point.Empty, SizeScale))
Clipboard.SetImage(TryCast(img.Clone(), Image))
End Using
End Using
End Sub
来源:https://stackoverflow.com/questions/51789730/image-size-when-capturing-a-screenshot-of-another-application-changes-if-applica