C# Website Screenshot Generator AKA Get Screenshot of Webpage With Asp.net C#

by nolovelust 25. April 2010 21:45

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 Smile.

  • 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 Tongue out

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

Tags: , , , ,

ASP.NET | Open Source

Comments (18) -

Peter
Peter Australia
5/26/2010 5:39:01 AM #

Thanks for this post, I was just thinking how about to use existing services of websnapr or snapshots?

Reply

nolovelust
nolovelust
5/26/2010 8:33:29 AM #

They have limitations on free service. I'd like to use code i wrote Smile

Reply

aleks
aleks Russia
6/2/2010 5:02:52 PM #

Very useful information. I look for this script all day. Thank you for this class.

Reply

Nilanga
Nilanga Sri Lanka
7/29/2010 7:54:06 AM #

Very useful information. Thanks ......

Reply

Luke
Luke Australia
1/19/2011 12:23:59 PM #

Thanks mate very useful!

Reply

Justin Toth
Justin Toth United States
5/24/2011 11:22:47 PM #

Code looks good, unfortunately it doesn't work at all. It doesn't generate the thumbnail png so it errors on the fist line in ThumbnailCreate with a FileNotFoundException.

Reply

nolovelust
nolovelust
5/24/2011 11:34:52 PM #

i use it on production  and works fone. eror is probab;y due to gaps in file path as someone suggested in comments.
Try putting path in to "" on the command line

Reply

Justin Toth
Justin Toth United States
5/25/2011 3:43:13 AM #

Quotes in the "out" path fixed it, works great even for urls that the buggy C# WebBrowser control fails on... Thanks!!

Reply

Kered
Kered United Kingdom
6/7/2011 10:03:42 AM #

Hi nice project, but how do you get this to work with the 2nd approach below ?

<img src="<%=new CutyCaptWrapper().GetScreenShot("http://bbc.co.uk")%>"; alt="">

Reply

nolovelust
nolovelust
6/7/2011 10:14:59 AM #

How do you mean? Can you be more specific.

Reply

Kered
Kered United Kingdom
6/7/2011 11:12:05 AM #

Hi, nolovelust

    1. In my App_Code I have the CutyCaptWrapper.cs
    2. In App_Data I have CutyCapt.exe
    3. I have a image on a asp.net webpage, which is below and the thumbnail will not generate

      <img src="<%=new CutyCaptWrapper().GetScreenShot("http://bbc.co.uk")%>";; alt="">

Could you point me in the right direction please

Many Thanks

Kered

Reply

Kered
Kered United Kingdom
6/7/2011 11:35:58 AM #

I have got it work now I had the path set wrong on Image

Reply

Laureano Remedi
Laureano Remedi Argentina
8/10/2011 8:29:37 PM #

Hi, I've done something similar with iecapt, this is also a command line tool developed by the same guy (Björn Höhrmann) who did cutycapt, but iecapt requires some dlls used by IE.
Do you know what are the prerequisites for cutycapt to work?

Reply

nolovelust
nolovelust
8/10/2011 9:13:13 PM #

Curry apt is standalone, I'd apt uses Internet explorer and I have had problems with it on sites with JavaScript prompts

Reply

David Tendrich
David Tendrich United States
8/16/2011 3:31:43 AM #

Hello!

I'm hitting my head against a wall trying to figure something out with CutyCapt...

For some reason my JPEGs have crazy image sizes. I'm talking 1.7 - 2.2 MB!

Since I'm trying to create an app where people who don't know about image conversion can use the images for their own websites... these file sizes make my app essentially useless.

I mean a 2.0 mb image size = crazy long loading times!

Do you know how to reduce image quality / file size without making the images extremely tiny?

Please any advice would help tremendously! Thank you so much Smile

David

Reply

nolovelust
nolovelust
8/16/2011 2:53:10 PM #

That's did you check curry apt command line at sf? It may have some quality switch, you can also reduce it with .net, search this blog for image helper class, or, you can try to email cuttycapts author, he is quite friendly and may consider adding quality switch to it if there isnt any

Reply

Brian Hodgin
Brian Hodgin United States
11/13/2011 6:47:15 AM #

Love finding this!

I altered the class slightly to allow me to grab a full screen capture to show the full page image in a new window for printing. I prefer that to a pdf mainly because you don't have to install any additional software and the printout looks EXACTLY like what the browser renders. Awesome Smile

Also, in some environments, the code will break if not fully trusted. You can specify that in the web.config like below here: msdn.microsoft.com/en-us/library/wyts434y.aspx and the code will run without a hitch in .net 2.0+ as far as I've tested.

Thanks again for the awesome work.

Reply

Haga
Haga Brazil
1/24/2012 7:02:25 PM #

Hi. First of all, that is an awesome work. But unfortunately it didn't work well for me. For some reason the image on the thumbnail folder is always blank (totally white) and on the local website it is loaded as a [x]. Do you have any thoughts about why is this happening?!  Thanks in advance!

Reply

Add comment

  Country flag

biuquote
Loading

Adverts

Welcome

Tag cloud

Month List