【问题标题】:Perform screen-scape of Webbrowser control in thread在线程中执行 Webbrowser 控件的 screen-scape
【发布时间】:2013-09-07 16:45:26
【问题描述】:

我正在使用

中显示的技术

WebBrowser Control in a new thread

尝试获取网页的屏幕截图当WebBrowser 控件放置在WinForm 上时,我已经能够使以下代码成功运行。但是,当在线程内运行时,它会通过提供桌面的任意图像而失败。

Thread browserThread = new Thread(() =>
{
    WebBrowser br = new WebBrowser();
    br.DocumentCompleted += webBrowser1_DocumentCompleted;
    br.ProgressChanged += webBrowser1_ProgressChanged;
    br.ScriptErrorsSuppressed = true;
    br.Navigate(url);
    Application.Run();
});
browserThread.SetApartmentState(ApartmentState.STA);
browserThread.Start();

private Image TakeSnapShot(WebBrowser browser)
{
    int width;
    int height;

    width = browser.ClientRectangle.Width;
    height = browser.ClientRectangle.Height;

    Bitmap image = new Bitmap(width, height);

    using (Graphics graphics = Graphics.FromImage(image))
    {
        Point p = new Point(0, 0);
        Point upperLeftSource = browser.PointToScreen(p);
        Point upperLeftDestination = new Point(0, 0);

        Size blockRegionSize = browser.ClientRectangle.Size;
        blockRegionSize.Width = blockRegionSize.Width - 15;
        blockRegionSize.Height = blockRegionSize.Height - 15;
        graphics.CopyFromScreen(upperLeftSource, upperLeftDestination, blockRegionSize);
    }

    return image;
}

这显然是由于Graphics.CopyFromScreen() 方法而发生的,但我不知道有任何其他方法。有没有人可以建议的方法来解决这个问题?还是我创建表单、添加控件、使其可见然后屏幕抓取的唯一选择?出于显而易见的原因,我希望避免这种方法。

【问题讨论】:

    标签: c# multithreading webbrowser-control screen-scraping apartments


    【解决方案1】:

    你可以写

    private Image TakeSnapShot(WebBrowser browser)
    {
         browser.Width = browser.Document.Body.ScrollRectangle.Width;
         browser.Height= browser.Document.Body.ScrollRectangle.Height;
    
         Bitmap bitmap = new Bitmap(browser.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth, browser.Height);
    
         browser.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
    
         return bitmap;
    }
    

    完整的工作代码

    var image = await WebUtils.GetPageAsImageAsync("http://www.stackoverflow.com");
    image.Save(fname , System.Drawing.Imaging.ImageFormat.Bmp);
    

    public class WebUtils
    {
        public static Task<Image> GetPageAsImageAsync(string url)
        {
            var tcs = new TaskCompletionSource<Image>();
    
            var thread = new Thread(() =>
            {
                WebBrowser browser = new WebBrowser();
                browser.Size = new Size(1280, 768);
    
                WebBrowserDocumentCompletedEventHandler documentCompleted = null;
                documentCompleted = async (o, s) =>
                {
                    browser.DocumentCompleted -= documentCompleted;
                    await Task.Delay(2000); //Run JS a few seconds more
    
                    Bitmap bitmap = TakeSnapshot(browser);
    
                    tcs.TrySetResult(bitmap);
                    browser.Dispose();
                    Application.ExitThread();
                };
    
                browser.ScriptErrorsSuppressed = true;
                browser.DocumentCompleted += documentCompleted;
                browser.Navigate(url);
                Application.Run();
            });
    
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
    
            return tcs.Task;
        }
    
        private static Bitmap TakeSnapshot(WebBrowser browser)
        {
             browser.Width = browser.Document.Body.ScrollRectangle.Width;
             browser.Height= browser.Document.Body.ScrollRectangle.Height;
    
             Bitmap bitmap = new Bitmap(browser.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth, browser.Height);
    
             browser.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
    
             return bitmap;
        }
    }
    

    【讨论】:

    • 正是我需要的。我寻找了类似 WebBrowser.DrawToBitmap() 的东西,但它没有出现在智能感知中(并且仍然没有出现)但编译得很好。谢谢!
    • 也感谢您展示 System.Windows.Forms.SystemInformation。以前从未见过,显然非常有用。
    • 优秀。正是我需要的。
    • 没有using 语句的代码示例。 叹息。
    • @RobertHarvey 感谢 VS,它很容易解决:)
    【解决方案2】:
    using (Graphics graphics = Graphics.FromImage(image))
        {
            Point p = new Point(0, 0);
            Point upperLeftSource = browser.PointToScreen(p);
            Point upperLeftDestination = new Point(0, 0);
    
            Size blockRegionSize = browser.ClientRectangle.Size;
            blockRegionSize.Width = blockRegionSize.Width - 15;
            blockRegionSize.Height = blockRegionSize.Height - 15;
            graphics.CopyFromScreen(upperLeftSource, upperLeftDestination, blockRegionSize);
        }
    

    你真的需要using statement 吗?

    你也是return image,但是复制的图片是怎么分配给它的呢?

    【讨论】:

    • 是的,您需要一个 using,除非您有充分的理由不处置您应该处置的 IDisposable 对象。至于图像,它是通过 Graphics graphics = Graphics.FromImage(image) 线分配的。
    猜你喜欢
    • 1970-01-01
    • 2013-01-18
    • 1970-01-01
    • 2015-01-15
    • 1970-01-01
    • 2012-03-22
    • 1970-01-01
    • 2010-09-29
    • 1970-01-01
    相关资源
    最近更新 更多