happygilmore
happygilmore

Reputation: 3095

How can I take a screenshot of a website with MVC?

I am struggling to find a way to take a screenshot of a website in MVC4. I have seen two potential solutions, which neither work well for MVC.

The first is using the WebBrowser, tutorial found here, but this gives me a ActiveX control '8856f961-340a-11d0-a96b-00c04fd705a2' cannot be instantiated because the current thread is not in a single-threaded apartment error.

The other is using a 3rd party called Grabz.It, but I haven't found a way to integrate it into MVC.

Any other ideas/solutions?

Thanks.

Upvotes: 2

Views: 6741

Answers (3)

obaylis
obaylis

Reputation: 3034

You need to specify that the thread is in STA (single threaded apartment mode in order to instantiate the web browser).

public ActionResult Save()
{
    var url = "http://www.google.co.uk";

    FileContentResult result = null;
    Bitmap bitmap = null;

    var thread = new Thread(
    () =>
    {
        bitmap = ExportUrlToImage(url, 1280, 1024);
    });

    thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
    thread.Start();
    thread.Join();

    if (bitmap != null)
    {
        using (var memstream = new MemoryStream())
        {
            bitmap.Save(memstream, ImageFormat.Jpeg);
            result = this.File(memstream.GetBuffer(), "image/jpeg");
        }
    }

    return result;
}

private Bitmap ExportUrlToImage(string url, int width, int height)
{
    // Load the webpage into a WebBrowser control
    WebBrowser wb = new WebBrowser();
    wb.ScrollBarsEnabled = false;
    wb.ScriptErrorsSuppressed = true;

    wb.Navigate(url);
    while (wb.ReadyState != WebBrowserReadyState.Complete)
    {
            Application.DoEvents();
    }

    // Set the size of the WebBrowser control
    wb.Width = width;
    wb.Height = height;

    Bitmap bitmap = new Bitmap(wb.Width, wb.Height);
    wb.DrawToBitmap(bitmap, new System.Drawing.Rectangle(0, 0, wb.Width, wb.Height));
    wb.Dispose();

    return bitmap;
}

Upvotes: 1

Chris Farmer
Chris Farmer

Reputation: 25405

Given your additional details, you should be able to do this with any number of tools. CodeCaster's idea is fine, and PhantomJS also offers similar webkit-based image generation of an arbitrary url (https://github.com/ariya/phantomjs/wiki/Screen-Capture). It offers several output format options, such as PNG, JPG, GIF, and PDF.

Since PhantomJS is using WebKit, a real layout and rendering engine, it can capture a web page as a screenshot. Because PhantomJS can render anything on the web page, it can be used to convert contents not only in HTML and CSS, but also SVG and Canvas.

You would need to execute the phantomjs.exe app from your MVC app, or probably even better by some service that is running behind the scenes to process a queue of submitted urls.

Upvotes: 3

CodeCaster
CodeCaster

Reputation: 151634

Why do you want to integrate this in MVC? Is it your website's responsibility to take screenshots of other websites? I would opt to create the screenshot-taking-logic in a separate library, hosted as a Windows Service for example.

The WebBrowser control needs to run on an UI thread, which a service (like IIS) doesn't have. You can try other libraries though.

You could for example write some code around wkhtmltopdf, which renders (as the name might suggest) HTML to PDF using the WebKit engine.

Upvotes: 1

Related Questions