To take a screenshot of a specified web page you need to follow the following steps:

  1. Create Browser instance.
  2. Set the required Browser size.
  3. Create a BrowserView (WPF or WinForms) with this Browser instance
  4. Load required web page by its URL or HTML and wait until its content is completely rendered.
  5. Get System Drawing.Image of the loaded web page using BrowserView.GetImage().

Note: the OnRepaint event used in the following sample is supported for lightweight rendering mode only. The GetImage() method works for both modes, but the component should be embedded and shown before calling this method.

Example

The following example demonstrates how to capture an image of the complete web page. In this case, you even don't need to embed browser view.

C#

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
    {
        public 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();
        }
    }

}

VB.NET

Imports System.Drawing.Imaging
Imports System.Threading
Imports System.Windows
Imports DotNetBrowser
Imports DotNetBrowser.Events
Imports DotNetBrowser.WPF

Public Class WindowMain
    Inherits Window

    Public browserView As WPFBrowserView

    Sub New()
        AddHandler Loaded, Sub()
           Width = 400
           Height = 300

           browserView = New WPFBrowserView(BrowserFactory.Create(BrowserType.LIGHTWEIGHT))
           Dim browser As 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.
           Dim resetEvent As ManualResetEvent = New ManualResetEvent(False)
           Dim listener As New FinishLoadingFrameHandler(Sub(o As Object, e As FinishLoadingEventArgs)
                                                             If e.IsMainFrame Then
                                                                 resetEvent.Set()
                                                             End If
                                                         End Sub)
           AddHandler browser.FinishLoadingFrameEvent, listener

           Try
               browser.LoadURL("teamdev.com/dotnetbrowser")
               resetEvent.WaitOne(New TimeSpan(0, 0, 45))
           Finally
               RemoveHandler browser.FinishLoadingFrameEvent, listener
           End Try

           ' #3 Set the required document size.
           Dim documentHeight As JSValue = browserView.Browser.ExecuteJavaScriptAndReturnValue(
                   "Math.max(document.body.scrollHeight, " +
                   "document.documentElement.scrollHeight, document.body.offsetHeight, " +
                   "document.documentElement.offsetHeight, document.body.clientHeight, " +
                   "document.documentElement.clientHeight);")
           Dim documentWidth As JSValue = browserView.Browser.ExecuteJavaScriptAndReturnValue(
                   "Math.max(document.body.scrollWidth, " +
                   "document.documentElement.scrollWidth, document.body.offsetWidth, " +
                   "document.documentElement.offsetWidth, document.body.clientWidth, " +
                   "document.documentElement.clientWidth);")

           Dim scrollBarSize As Integer = 25

           Dim viewWidth As Integer = CInt(documentWidth.GetNumber()) + scrollBarSize
           Dim viewHeight As Integer = CInt(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.

           Dim waitEvent As ManualResetEvent = New ManualResetEvent(False)
           Dim drawingView As DrawingView = CType(browserView.GetInnerView(), DrawingView)

           AddHandler drawingView.OnRepaint, Sub(o As Object, e As OnRepaintEventArgs)
                                                 ' Make sure that all view content has been repainted.
                                                 If e.UpdatedRect.Size.Equals(e.ClientSize) Then
                                                     waitEvent.Set()
                                                 End If
                                             End Sub

           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(
               (Sub()
                   browserView.GetImage().Save("teamdev.png", ImageFormat.Png)
               End Sub))
       End Sub
    End Sub
End Class

Module Module1
    <STAThread>
    Sub Main()
        Dim app As Application = New Application()
        Dim wnd As WindowMain = New WindowMain()
        app.Run(wnd)
        Dim browser = wnd.browserView.Browser
        wnd.browserView.Dispose()
        browser.Dispose()
    End Sub
End Module

Calculating Page Size


If you need to take the screenshot of the whole web page including scrollable hidden parts and you don’t know the web page dimensions, then you need to calculate it using the following approach:

C#

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;

VB.NET

Dim documentHeight As JSValue = browserView.Browser.ExecuteJavaScriptAndReturnValue(
       "Math.max(document.body.scrollHeight, " +
       "document.documentElement.scrollHeight, document.body.offsetHeight, " +
       "document.documentElement.offsetHeight, document.body.clientHeight, " +
       "document.documentElement.clientHeight);")
Dim documentWidth As JSValue = browserView.Browser.ExecuteJavaScriptAndReturnValue(
       "Math.max(document.body.scrollWidth, " +
       "document.documentElement.scrollWidth, document.body.offsetWidth, " +
       "document.documentElement.offsetWidth, document.body.clientWidth, " +
       "document.documentElement.clientWidth);")

Dim scrollBarSize As Integer = 25
Dim viewWidth As Integer = CInt(documentWidth.GetNumber()) + scrollBarSize
Dim viewHeight As Integer = CInt(documentHeight.GetNumber()) + scrollBarSize


In this code we use JavaScript and DOM API to get the dimensions of the loaded document.


The complete sample solution can be found in the attachments to this article. The project in this solution has NuGet dependencies, which will be resolved automatically during build.

Capturing Long Pages

If you have tried to capture a long  web page, you may have noticed that the image is cut for the very long pages. This behavior is caused by the restriction inside the Chromium itself.

Chromium renders web page’s content on the canvas with the maximum height set to 16384. If the web page’s height exceeds the maximum texture size, the part of the web page outside the Chromium canvas will not be drawn and will be filled with black color.

To workaround this restriction and capture the complete image of the web page with the height that exceeds the maximum texture size, you should specify the following switches before creating any Browser or BrowserView instances:

C#

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

VB.NET

Dim viewWidth As Integer = 1024
Dim viewHeight As Integer = 20000
Dim switches As String() = {
                "--disable-gpu", 
                "--max-texture-size=" & viewHeight}
BrowserPreferences.SetChromiumSwitches(switches)


If these switches are specified, the GPU process will be disabled and the Chromium maximum texture size will be changed from 16384 to viewHeight.

Note: The --max-texture-size switch was introduced in DotNetBrowser 1.9.