Reputation: 3095
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
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
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
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