Before I wrote below C# wrapper I've looked around for a C# code to get screenshot of a web site or url. Although there are many web services provides website screenshot service none of them are free!
I've found http://smallsharptools.com/Projects/WebPreview it works fine and author used windows forms Webbrowser control but there is a problem with it. Webbrowser control uses internet explorer to render pages and if there is any JavaScript prompt on the page you are trying to render it doesn't work. You also have no way of disabling plug-ins and JavaScript. (See http://nolovelust.com/post/Generate-website-screenshotthumbnail-with-net-webbrowser-control-on-c-aspnet-website.aspx for hack to disable JavaScript)
Next candidate was NirSoft's SiteShoter it is nice little application with command line support but it too uses internet explorer to get screenshot of websites.
I finally found CutyCapt, it uses QT Webkit to render web pages and packs everything in to a single file with command line support.
After couple of hours work I ended up a c# wrapper for CutyCapt. Works like a charm
.
- It caches Thumbnails for given hours.
- It has 3 different thumbnail sizes but you can add as many as you want.
- It can keep aspect ratio of thumbnails.
- You can even start your own website screenshot service with it

Unlike some paid website screenshot services claim about free website screenshot tools like mine
- Development & Testing Cost is 0
- It is not buggy, even if there is a bug it can be fixed as all the code is open source
- Is not time-consuming and FREE!
To get started download CutyCapt and my CutyCaptWrapper.zip (4.46 kb), put CutyCapt in to App_Data folder
There is one problem i couldn't fix with this code. If CutyCapt crashes it takes whole site down with it. Having said that, I've been using it on a production site since 2 months and didn't have any problems.
Please see Contribution to C# Website Screenshot Generator AKA Get Screenshot of Webpage With Asp.net C# for updates by Colarado State University Web team
Usage
CutyCaptWrapper ccw = new CutyCaptWrapper();
Response.Write(ccw.GetScreenShot("http://bbc.co.uk"));
Or
<img src="<%=new CutyCaptWrapper().GetScreenShot("http://bbc.co.uk")%>" alt="">
CutyCaptWrapper.cs
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;
public class CutyCaptWrapper
{
///
/// 1 - small
/// 2 - medium
/// 3 - large
///
public int ThumbNailSize { get; set; }
public bool ThumbKeepAspectRatio { get; set; }
public int ThumbExpiryTimeInHours { get; set; }
public string ScreenShotPath { get; set; }
public string CutyCaptPath { get; set; }
//public string CutyCaptWorkingDirectory { get; set; }
public string CutyCaptDefaultArguments { get; set; }
private int ThumbWidth { get; set; }
private int ThumbHeight { get; set; }
public CutyCaptWrapper()
{
//default values
ThumbNailSize = 1;
ThumbKeepAspectRatio = false;
ThumbExpiryTimeInHours = 168; //1 week
ScreenShotPath = HttpContext.Current.Server.MapPath("~/ThumbCache/"); // must be within the web root
CutyCaptPath = HttpContext.Current.Server.MapPath("~/App_Data/CutyCapt.exe"); // must be within the web root
//CutyCaptWorkingDirectory = HttpContext.Current.Server.MapPath("~/App_Data/");
CutyCaptDefaultArguments = " --max-wait=10000 --out-format=png --javascript=off --java=off --plugins=off --js-can-open-windows=off --js-can-access-clipboard=off --private-browsing=on";
}
///
/// Checks if there is a cached screenshot of the website and returns url path to thumbnail of the website in order to use ase html image element source
/// Usage example: <img src="<%=CutyCaptWrapper().GetScreenShot("http://google.com")%>" alt="">
///
public string GetScreenShot(string url)
{
if (IsURLValid(url))
{
if (!Directory.Exists(ScreenShotPath))
{
Directory.CreateDirectory(ScreenShotPath);
}
//set thumbnail sizes
SetThumbnailSize();
string ScreenShotFileName = ScreenShotPath + GetScreenShotFileName(url);
string ScreenShotThumbnailFileName = ScreenShotPath + GetScreenShotThumbnailFileName(ScreenShotFileName, ThumbWidth, ThumbHeight);
string RunArguments = " --url=" + url + " --out=" + ScreenShotFileName + CutyCaptDefaultArguments;
FileInfo ScreenShotThumbnailFileNameInfo = new FileInfo(ScreenShotThumbnailFileName);
if (!ScreenShotThumbnailFileNameInfo.Exists || ScreenShotThumbnailFileNameInfo.CreationTime < DateTime.Now.AddHours(-ThumbExpiryTimeInHours))
{
ProcessStartInfo info = new ProcessStartInfo(CutyCaptPath, RunArguments);
info.UseShellExecute = false;
info.RedirectStandardInput = true;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.CreateNoWindow = true;
//info.WorkingDirectory = CutyCaptWorkingDirectory;
using (Process scr = Process.Start(info))
{
//string output = scr.StandardOutput.ReadToEnd();
scr.WaitForExit();
ThumbnailCreate(ScreenShotFileName, ScreenShotThumbnailFileName, ThumbWidth, ThumbHeight, ThumbKeepAspectRatio);
//delete original file
File.Delete(ScreenShotFileName);
//return output;
}
}
return GetRelativeUri(ScreenShotThumbnailFileName);
}
else
{
return "Wrong URL";
}
}
private void ThumbnailCreate(string sourceFilePath, string outFilePath, int NewWidth, int MaxHeight, bool keepAspectRatio)
{
using (Image FullsizeImage = Image.FromFile(sourceFilePath))
{
int NewHeight = MaxHeight;
if (keepAspectRatio)
{
NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
}
using (Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero))
{
NewImage.Save(outFilePath, ImageFormat.Png);
}
}
}
private string GetScreenShotFileName(string url)
{
Uri uri = new Uri(url);
return uri.Host.Replace(".", "_") + uri.LocalPath.Replace("/", "_") + ".png";
}
private string GetScreenShotThumbnailFileName(string sourceFilename, int width, int height)
{
FileInfo sourceFile = new FileInfo(sourceFilename);
string shortFilename = sourceFile.Name;
string ext = Path.GetExtension(shortFilename);
string replacementEnding = String.Format("{0}x{1}", width, height) + ext;
return shortFilename.Replace(ext, replacementEnding);
}
private string GetRelativeUri(string pathToFile)
{
string rootPath = HttpContext.Current.Server.MapPath("~");
return pathToFile.Replace(rootPath, "").Replace(@"\", "/");
}
private bool IsURLValid(string url)
{
string strRegex = "^(https?://)"
+ "?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" //user@
+ @"(([0-9]{1,3}\.){3}[0-9]{1,3}" // IP- 199.194.52.184
+ "|" // allows either IP or domain
+ @"([0-9a-z_!~*'()-]+\.)*" // tertiary domain(s)- www.
+ @"([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\." // second level domain
+ "[a-z]{2,6})" // first level domain- .com or .museum
+ "(:[0-9]{1,4})?" // port number- :80
+ "((/?)|" // a slash isn't required if there is no file name
+ "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$";
Regex re = new Regex(strRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (re.IsMatch(url))
return (true);
else
return (false);
}
private void SmallThumbnail()
{
ThumbWidth = 200;
ThumbHeight = 150;
}
private void MediumThumbnail()
{
ThumbWidth = 240;
ThumbHeight = 190;
}
private void LargeThumbnail()
{
ThumbWidth = 320;
ThumbHeight = 270;
}
private void SetThumbnailSize()
{
if (ThumbNailSize == 1)
{
SmallThumbnail();
}
if (ThumbNailSize == 2)
{
MediumThumbnail();
}
if (ThumbNailSize == 3)
{
LargeThumbnail();
}
else
{
ThumbNailSize = 1;
}
}
}