通过 WebBrowser 下载鼠标指针下的图像

Download Image under the Mouse pointer via WebBrowser

我正在使用 WebBrowser 控件导航至 Google 图片。目的是能够右键单击任何图像并下载和填充 PictureBox 背景。

我有自己的 ContextMenuStrip,上面有复制功能,并且禁用了内置的上下文菜单。

我遇到的问题是从 CurrentDocument.MouseMove 返回的坐标总是相对于第一张(左上角)图像。
因此,如果我想要的图像是页面上的第一张图像,我的代码可以正常工作,但是单击任何其他图像总是 returns 第一张图像的坐标。

坐标似乎是相对于每个图像而不是页面。

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 图片搜索页面和 select/download 带有 right-click 鼠标的图片。

要对其进行测试,请将 WebBrowser 控件和 FlowLayoutPanel 放在窗体上,然后导航到 Google 图像搜索页面。

要知道的事情:

  • 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.
    阅读有关此的注释:
  • Google 搜索页面中的图像可以通过两种不同的方式插入到文档中:既使用 Base64Encoded 字符串 又使用 classic src=[URI]格式。我们需要做好两全其美的准备。
  • 鼠标点击位置可以用绝对坐标或相对坐标表示,由e.ClientMousePosition or e.OffsetMousePosition引用。
    在此处阅读有关此功能的注释:
  • WebBrowser 仿真模式可能很重要。我们应该使用当前机器可用的最新兼容模式。
    阅读此答案并应用所需的修改以使最新的 Internet Explorer 模式可用:.

请注意,事件处理程序在当前文档完成时连接,并在浏览器导航到另一个页面时被删除。这可以防止对 DocumentCompleted 事件的意外调用。

当前文档完成后,用鼠标右键单击图像,创建一个新的 PictureBox 控件,添加到 FlowLayouPanel 中进行演示。

鼠标单击处理程序中的代码 (Protected Sub OnHtmlDocumentClick()) 检测当前图像是否为 Base64Encoded 字符串或外部源 URI.
在第一种情况下,它调用 Convert.FromBase64String 将字符串转换为字节数组,在第二种情况下,它使用 WebClient class 来将图像下载为字节数组。

在这两种情况下,数组然后被传递给另一个方法(Private Function GetBitmapFromByteArray()),returns 来自数组的图像,使用Image.FromStream() 和一个用 Byte 数组初始化的 MemoryStream

此处的代码不执行空值检查和类似的 fail-proof 测试。应该的,看你的了

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