1

我在尝试将网页另存为图像时遇到问题,在保存部分之前,我的应用程序中的一切似乎都运行良好。

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);
}

有任何想法吗?我只是希望在不需要对话框或用户交互的情况下保存图像,并将其保存到桌面文件夹中。

4

1 回答 1

1

将网页保存为 PNG 图像

要截取指定网页的屏幕截图,您需要执行以下步骤:

  1. 创建浏览器实例。
  2. 设置所需的浏览器大小。
  3. 使用此 Browser 实例创建一个 BrowserView(WPF 或 WinForms)
  4. 通过 URL 或 HTML 加载所需的网页,并等待其内容完全呈现。
  5. 使用 BrowserView.GetImage() 获取加载网页的 System Drawing.Image。

注意:以下示例中使用的 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。

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

于 2017-04-12T14:36:19.697 回答