通过 WebBrowser 下载鼠标指针下的图像
我正在使用 WebBrowser 控件导航到 Google 图片.目的是能够右键单击任何图像并下载并填充图片框背景.
I'm navigating to Google Images using a WebBrowser control. The aim is to be able to right click on any image and download and populate a PictureBox background.
我有自己的 ContextMenuStrip
,上面有 Copy,并禁用了内置的上下文菜单.
I have my own ContextMenuStrip
with Copy on it and have disabled the built in context menu.
我遇到的问题是从 CurrentDocument.MouseMove
返回的坐标总是相对于第一张(左上角)图像.
因此,如果我想要的图像是页面上的第一个图像,则我的代码可以正常工作,但是单击任何其他图像始终会返回第一个图像的坐标.
The issue I am having is that the coordinate returned from CurrentDocument.MouseMove
are always relative to the first (top left) image.
So my code works correctly if the Image I want is the very first image on the page, however clicking on any other Images always returns the coordinates of the first image.
看起来坐标是相对于每个图像而不是页面.
It would appear that the coordinates are relative to each Image rather than the page.
Private WithEvents CurrentDocument As HtmlDocument
Dim MousePoint As Point
Dim Ele As HtmlElement
Private Sub Google_covers_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.IsWebBrowserContextMenuEnabled = False
WebBrowser1.ContextMenuStrip = ContextMenuStrip1
End Sub
Private Sub WebBrowser1_Navigated(sender As Object, e As WebBrowserNavigatedEventArgs) Handles WebBrowser1.Navigated
CurrentDocument = WebBrowser1.Document
End Sub
Private Sub CurrentDocument_MouseMove(sender As Object, e As HtmlElementEventArgs) Handles CurrentDocument.MouseMove
MousePoint = New Point(e.MousePosition.X, e.MousePosition.Y)
Me.Text = e.MousePosition.X & " | " & e.MousePosition.Y
End Sub
Private Sub ContextMenuStrip1_Opening(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles ContextMenuStrip1.Opening
Ele = CurrentDocument.GetElementFromPoint(MousePoint)
If Ele.TagName = "IMG" Then
CopyToolStripMenuItem.Visible = True
Else
CopyToolStripMenuItem.Visible = False
End If
End Sub
Private Sub CopyToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles CopyToolStripMenuItem.Click
Dim ToImg = Ele.GetAttribute("src")
mp3_row_edit.PictureBox1.BackgroundImage = New System.Drawing.Bitmap(New IO.MemoryStream(New System.Net.WebClient().DownloadData(ToImg)))
ToImg = Nothing
End Sub
此代码允许使用标准的 WebBrowser 控件导航到 Google 图片搜索页面,并通过鼠标右键单击来选择/下载图片.
This code allow to use a standard WebBrowser control to navigate to the Google Image search page and select/download an Image with a right-click of the Mouse.
要对其进行测试,请将 WebBrowser Control 和 FlowLayoutPanel 放在 Form 上,然后导航到 Google Image 搜索页面.
To test it, drop a WebBrowser Control and a FlowLayoutPanel on a Form and navigate to a Google Image search page.
注意事项:
-
WebBrowser.DocumentCompleted:每次完成主
HtmlDocument
页面中的一个子文档时,都会引发此事件.因此,它可以多次提升.我们需要检查WebBrowser.ReadyState= WebBrowserReadyState.Complete
.
请阅读有关此内容的说明:如何在 Frames/IFrames 中获取 HtmlElement 值? - Google 搜索页面中的图像可以通过两种不同的方式插入到文档中:使用
Base64Encoded
字符串 和使用经典的src=[URI]
格式.我们需要准备好两者兼得. - 鼠标点击位置可以以绝对坐标或相对坐标表示,由
e.ClientMousePosition
或e.OffsetMousePosition
.
在此处阅读有关此功能的说明:在 WebBrowser 文档中获取鼠标单击坐标 - WebBrowser 仿真模式可能很重要.我们应该使用当前机器中可用的最新兼容模式.
阅读此答案并应用所需的修改以提供最新的 Internet Explorer 模式:如何让 WebBrowser 控件显示现代内容?.
- WebBrowser.DocumentCompleted: This event is raised each time one of the Sub-Documents inside a main
HtmlDocument
page is completed. Thus, it can be raised multiple times. We need to check whether the WebBrowser.ReadyState= WebBrowserReadyState.Complete
.
Read these note about this: How to get an HtmlElement value inside Frames/IFrames? - The images in the Google search page can be inserted in the Document in 2 different manners: both using a
Base64Encoded
string and using the classicsrc=[URI]
format. We need to be ready to get both. - The mouse click position can be espressed in either absolute or relative coordinates, referenced by the
e.ClientMousePosition
ore.OffsetMousePosition
.
Read the notes about this feature here: Getting mouse click coordinates in a WebBrowser Document - The WebBrowser emulation mode can be important. We should use the most recent compatible mode available in the current machine.
Read this answer and apply the modifications needed to have the most recent Internet Explorer mode available: How can I get the WebBrowser control to show modern contents?.
请注意,事件处理程序在当前文档完成时连接,并在浏览器导航到另一个页面时删除.这可以防止对 DocumentCompleted
事件的意外调用.
Note that an event handler is wired up when the current Document is completed and is removed when the Browser navigates to another page. This prevents undesired calls to the DocumentCompleted
event.
当前文档完成后,在图像上单击鼠标右键,会创建一个新的 PictureBox 控件,该控件将添加到 FlowLayouPanel 以进行演示.
When the current Document is complete, clicking with the right button of the Mouse on an Image, creates a new PictureBox control that is added to a FlowLayouPanel for presentation.
鼠标点击处理程序中的代码(Protected Sub OnHtmlDocumentClick()
)检测当前图像是否为Base64Encoded
字符串或外部源 URI
.
在第一种情况下,它调用 Convert.FromBase64String要将字符串转换为 Byte 数组,在第二种情况下,它使用 WebClient
类将图像下载为 Byte 数组.
The code in the Mouse click handler (Protected Sub OnHtmlDocumentClick()
) detects whether the current image is a Base64Encoded
string or an external source URI
.
In the first case, it calls Convert.FromBase64String to convert the string into a Byte array, in the second case, it uses a WebClient
class to download the Image as a Byte array.
在这两种情况下,然后将数组传递给另一个方法(Private Function GetBitmapFromByteArray()
),该方法使用 Image.FromStream()
和一个用 Byte 数组初始化的 MemoryStream
.
In both cases, the array is then passed to another method (Private Function GetBitmapFromByteArray()
) that returns an Image from the array, using Image.FromStream()
and a MemoryStream
initialized with the Byte array.
此处的代码不执行空检查和类似的防故障测试.应该的,这取决于你.
The code here is not performing null checks and similar fail-proof tests. It ought to, that's up to you.
Public Class frmBrowser
Private WebBrowserDocumentEventSet As Boolean = False
Private base64Pattern As String = "base64,"
Private Sub frmBrowser_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.IsWebBrowserContextMenuEnabled = False
End Sub
Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
If WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso WebBrowserDocumentEventSet = False Then
WebBrowserDocumentEventSet = True
AddHandler WebBrowser1.Document.MouseDown, AddressOf OnHtmlDocumentClick
End If
End Sub
Protected Sub OnHtmlDocumentClick(sender As Object, e As HtmlElementEventArgs)
Dim currentImage As Image = Nothing
If Not (e.MouseButtonsPressed = MouseButtons.Right) Then Return
Dim source As String = WebBrowser1.Document.GetElementFromPoint(e.ClientMousePosition).GetAttribute("src")
If source.Contains(base64Pattern) Then
Dim base64 As String = source.Substring(source.IndexOf(base64Pattern) + base64Pattern.Length)
currentImage = GetBitmapFromByteArray(Convert.FromBase64String(base64))
Else
Using wc As WebClient = New WebClient()
currentImage = GetBitmapFromByteArray(wc.DownloadData(source))
End Using
End If
Dim p As PictureBox = New PictureBox() With {
.Image = currentImage,
.Height = Math.Min(FlowLayoutPanel1.ClientRectangle.Height, FlowLayoutPanel1.ClientRectangle.Width)
.Width = .Height,
.SizeMode = PictureBoxSizeMode.Zoom
}
FlowLayoutPanel1.Controls.Add(p)
End Sub
Private Sub WebBrowser1_Navigating(sender As Object, e As WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
If WebBrowser1.Document IsNot Nothing Then
RemoveHandler WebBrowser1.Document.MouseDown, AddressOf OnHtmlDocumentClick
WebBrowserDocumentEventSet = False
End If
End Sub
Private Function GetBitmapFromByteArray(imageBytes As Byte()) As Image
Using ms As MemoryStream = New MemoryStream(imageBytes)
Return DirectCast(Image.FromStream(ms).Clone(), Image)
End Using
End Function
End Class