C#使用DotNetBrowser保存网页图像

时间:2017-01-08 06:35:24

标签: c# image dotnetbrowser

我在尝试将网页另存为图片时遇到问题,所有内容在我的应用程序中都能正常运行,直到保存部分。

string desktopPath = Environment.GetFolderPath(System.Environment.SpecialFolder.DesktopDirectory);
string imageFileName = desktopPath + browserView.Browser.URL.ToString();
browserView1.GetImage().Save(@imageFileName, ImageFormat.Png);

这会抛出错误

  

App.exe

中发生了未处理的“System.NullReferenceException”类型异常      

附加信息:对象引用未设置为的实例   对象

使用对话框保存它很奇怪,工作正常:

if (saveFileDialog.ShowDialog() == DialogResult.OK)
{
     string imageFileName = saveFileDialog.FileName.ToString().Replace("%.png%", "");
     browserView1.GetImage().Save(imageFileName, ImageFormat.Png);
}

有什么想法吗?我只是希望保存图像而不需要对话或用户交互,并将其保存到桌面文件夹。

1 个答案:

答案 0 :(得分:1)

将网页保存为PNG图像

要获取指定网页的屏幕截图,您需要按照以下步骤操作:

  1. 创建浏览器实例。
  2. 设置所需的浏览器大小。
  3. 使用此浏览器实例创建BrowserView(WPF或WinForms)
  4. 按网址或HTML加载所需的网页,并等待其内容完整呈现。
  5. 使用BrowserView.GetImage()获取系统绘图。加载网页的图像。
  6.   

    注意:以下示例中使用的OnRepaint事件仅支持轻量级渲染模式。 GetImage()方法适用于两种模式,但在调用此方法之前,应嵌入并显示该组件。

    示例

    以下示例演示如何捕获完整网页的图像。在这种情况下,您甚至不需要嵌入浏览器视图。

    using DotNetBrowser;
    using DotNetBrowser.Events;
    using DotNetBrowser.WPF;
    using System;
    using System.Drawing.Imaging;
    using System.Threading;
    using System.Windows;
    
    namespace HTMLToImageSample
    {
        public partial class WindowMain : Window
        {
            private WPFBrowserView browserView;
    
            public WindowMain()
            {
                this.Loaded += delegate
                {
                    Width = 400;
                    Height = 300;
    
                    browserView = new WPFBrowserView(BrowserFactory.Create(BrowserType.LIGHTWEIGHT));
                    Browser browser = browserView.Browser;
    
    
                    // #1 Set browser initial size
                    browserView.Browser.SetSize(1280, 1024);
    
                    // #2 Load web page and wait until web page is loaded completely.
                    ManualResetEvent resetEvent = new ManualResetEvent(false);
                    FinishLoadingFrameHandler listener = new FinishLoadingFrameHandler((object sender, FinishLoadingEventArgs e) =>
                    {
                        if (e.IsMainFrame)
                        {
                            resetEvent.Set();
                        }
                    });
                    browser.FinishLoadingFrameEvent += listener;
                    try
                    {
                        browser.LoadURL("teamdev.com/dotnetbrowser");
                        resetEvent.WaitOne(new TimeSpan(0, 0, 45));
                    }
                    finally
                    {
                        browser.FinishLoadingFrameEvent -= listener;
                    }
    
    
                    // #3 Set the required document size.
                    JSValue documentHeight = browserView.Browser.ExecuteJavaScriptAndReturnValue(
                            "Math.max(document.body.scrollHeight, " +
                            "document.documentElement.scrollHeight, document.body.offsetHeight, " +
                            "document.documentElement.offsetHeight, document.body.clientHeight, " +
                            "document.documentElement.clientHeight);");
                    JSValue documentWidth = browserView.Browser.ExecuteJavaScriptAndReturnValue(
                            "Math.max(document.body.scrollWidth, " +
                            "document.documentElement.scrollWidth, document.body.offsetWidth, " +
                            "document.documentElement.offsetWidth, document.body.clientWidth, " +
                            "document.documentElement.clientWidth);");
    
                    int scrollBarSize = 25;
    
                    int viewWidth = (int)documentWidth.GetNumber() + scrollBarSize;
                    int viewHeight = (int)documentHeight.GetNumber() + scrollBarSize;
    
                    // #4 Register OnRepaint to get notifications
                    // about paint events. We expect that web page will be completely rendered twice:
                    // 1. When its size is updated.
                    // 2. When HTML content is loaded and displayed.
                    ManualResetEvent waitEvent = new ManualResetEvent(false);
                    DrawingView drawingView = (DrawingView)browserView.GetInnerView();
                    drawingView.OnRepaint += delegate(object sender, OnRepaintEventArgs e)
                    {
                        // Make sure that all view content has been repainted.
                        if (e.UpdatedRect.Size.Equals(e.ClientSize))
                        {
                            waitEvent.Set();
                        }
                    };
                    browserView.Browser.SetSize(viewWidth, viewHeight);
                    // #5 Wait until Chromium renders web page content.
                    waitEvent.WaitOne();
                    // #6 Save Image of the loaded web page into a PNG file.
                    Dispatcher.BeginInvoke((Action)(() =>
                    {
                        browserView.GetImage().Save(@"teamdev.png", ImageFormat.Png);
                    }));
                };
            }
    
            [STAThread]
            public static void Main()
            {
                Application app = new Application();
    
                WindowMain wnd = new WindowMain();
    
                app.Run(wnd);
    
                var browser = wnd.browserView.Browser;
                wnd.browserView.Dispose();
                browser.Dispose();
            }
        }
    
    }
    

    计算页面大小

    如果您需要获取包含可滚动隐藏部分的整个网页的屏幕截图,而您不知道网页尺寸,则需要使用以下方法进行计算:

    JSValue documentHeight = browser.ExecuteJavaScriptAndReturnValue(
            "Math.max(document.body.scrollHeight, " +
            "document.documentElement.scrollHeight, document.body.offsetHeight, " +
            "document.documentElement.offsetHeight, document.body.clientHeight, " +
            "document.documentElement.clientHeight);");
    JSValue documentWidth = browser.executeJavaScriptAndReturnValue(
            "Math.max(document.body.scrollWidth, " +
            "document.documentElement.scrollWidth, document.body.offsetWidth, " +
            "document.documentElement.offsetWidth, document.body.clientWidth, " +
            "document.documentElement.clientWidth);");
    
    int scrollBarSize = 25;
    int viewWidth = (int) documentWidth.GetNumber() + scrollBarSize;
    int viewHeight = (int) documentHeight.GetNumber() + scrollBarSize;
    

    在此代码中,我们使用JavaScript和DOM API来获取已加载文档的尺寸。

      

    完整的示例解决方案可以在本文的附件中找到。此解决方案中的项目具有NuGet依赖项,将在构建期间自动解析。

    捕获长页

    如果您尝试捕获较长的网页,您可能已经注意到图像被剪切为很长的页面。此行为是由Chromium内部的限制引起的。 Chromium在画布上呈现网页的内容,最大高度设置为16384.如果网页的高度超过最大纹理大小,则不会绘制Chromium画布外部的网页部分,并将填充黑色。 要解决此限制并捕获高度超过最大纹理大小的网页的完整图像,您应在创建任何Browser或BrowserView实例之前指定以下开关:

    int viewWidth = 1024;
    int viewHeight = 20000;
    string[] switches = {
            "--disable-gpu",
            "--max-texture-size=" + viewHeight
    };
    BrowserPreferences.SetChromiumSwitches(switches);
    

    如果指定了这些开关,GPU进程将被禁用,Chromium最大纹理大小将从16384更改为viewHeight。

      

    注意:在DotNetBrowser 1.9中引入了--max-texture-size开关。