A Screen Capture Utility in C# and .NET with SharpDevelop

Described below is a simple screen capture utility implemented in .NET and C#. The program accepts command-line arguments that describe the portion of the screen to be captured, what to name the screenshot files, and which image format to use. Additional arguments allow the capturing of multiple images over a period of time and at a given frame rate. The usage is as follows:

ScreenshotCapturer.exe [-prefix <filePathStemToSaveTo>] [-extension <imageFileExtension>] [-bounds <captureBoundsX> <captureBoundsY> <captureBoundsWidth> <captureBoundsHeight>] [-count <numberOfScreenshotsToCapture>] [-frequency <screenshotsPerSecond>]

I originally put this application together for the purpose of converting an animation running in a web browser window to an animated .gif, so that I could post that animation to my WordPress.com blog. There are lots of programs out there that do this sort of thing already, of course. But this one does exactly what I need it to do without any additional complication. Further, now that every other Windows installer hosted on Sourceforge seems to include malware (I’m looking at you, CamStudio), this way is probably more hygenic as well.

Follow the steps given below to build the program executable. These steps presume a system running Microsoft Windows.

ScreenshotCapturer

1. If you have not already done so, download and install SharpDevelop, an open-source IDE for the .NET platform. As of this writing, the latest version is available at the URL http://www.icsharpcode.net/OpenSource/SD/Download/.

2. Start SharpDevelop.

3. In SharpDevelop, select the item “File – New – Solution” from the main menu.

4. In the New Project dialog, click the “Console Application” icon in the Templates pane, enter the name “ScreenshotCapturer” in the Name box, adjust the Location box as desired, and click the Create button.

5. Replace the automatically-generated contents of the “Program.cs” file with the following and save the file:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Windows.Forms;

namespace ScreenshotCapturer
{
	class Program
	{
		static void Main(string[] args)
		{
			// Usage:
			// ScreenshotCapturer.exe [-prefix <filePathStemToSaveTo>] [-extension <imageFileExtension>]
			// [-bounds <captureBoundsX> <captureBoundsY> <captureBoundsWidth> <captureBoundsHeight>]
			// [-count <numberOfScreenshotsToCapture>] [-frequency <screenshotsPerSecond>]

			DateTime now = DateTime.Now;
			Console.WriteLine("Program begins: " + now);

			const string dateTimeFormat = "yyyyMMdd-HHmmss-fff";

			string filePathStemToSaveTo = "Screenshot-" + now.ToString(dateTimeFormat);
			string imageFileExtension = ".png";
			Rectangle? captureBoundsNullable = null;
			int numberOfScreenshotsToCapture = 1;
			int millisecondsPerScreenshot = 0;

			try
			{
				for (var i = 0; i < args.Length; i++)
				{
					var argument = args[i];
					if (argument == "-prefix")
					{
						filePathStemToSaveTo = args[i + 1];
						i++;		
					}
					else if (argument == "-extension")
					{
						imageFileExtension = args[i + 1];
						i++;
					}
					else if (argument == "-bounds")
					{
						captureBoundsNullable = new Rectangle
						(
							Int32.Parse(args[i + 1]), Int32.Parse(args[i + 2]),
							Int32.Parse(args[i + 3]), Int32.Parse(args[i + 4])
						);
						i += 4;
					}
					else if (argument == "-count")
					{
						numberOfScreenshotsToCapture = Int32.Parse(args[i + 1]);
						i++;
					}
					else if (argument == "-frequency")
					{
						int screenshotsPerSecond = Int32.Parse(args[i + 1]);
						millisecondsPerScreenshot = 1000 / screenshotsPerSecond;
						i++;
					}
					else
					{						
						throw new Exception( "Unrecognized command-line switch:" + argument);
					}
				}
			}
			catch (Exception ex)
			{
				string errorMessage = "Error parsing command-line arguments: " + ex.Message;
				Console.WriteLine(errorMessage);
			}
				
			ScreenshotCapturer screenshotCapturer = new ScreenshotCapturer()
			{
					FilePathStemToSaveTo = filePathStemToSaveTo,
					ImageFileExtension = imageFileExtension,
					CaptureBoundsNullable = captureBoundsNullable,
					NumberOfScreenshotsToCapture = numberOfScreenshotsToCapture,
					MillisecondsPerScreenshot = millisecondsPerScreenshot,
			};
			
			screenshotCapturer.start();

			Console.WriteLine("Program ends: " + DateTime.Now);
		}
	}

	public class ScreenshotCapturer
	{
		public string FilePathStemToSaveTo;
		public string ImageFileExtension;
		public Rectangle? CaptureBoundsNullable;
		public int NumberOfScreenshotsToCapture;
		public int MillisecondsPerScreenshot;
	
		public void start()
		{
			Console.WriteLine("-prefix=" + this.FilePathStemToSaveTo);
			Console.WriteLine("-extension=" + this.ImageFileExtension);
			Console.WriteLine("-bounds=" + this.CaptureBoundsNullable);
			Console.WriteLine("-count=" + this.NumberOfScreenshotsToCapture);
			Console.WriteLine("-frequency=" + (1000 / this.MillisecondsPerScreenshot));

			if (this.NumberOfScreenshotsToCapture == 1)
			{
				this.copyScreenToImageFile(0);
			}
			else
			{
				for (var i = 0; i < this.NumberOfScreenshotsToCapture; i++)
				{
					this.copyScreenToImageFile(i);
					Thread.Sleep(this.MillisecondsPerScreenshot);
				}
			}	
		}

		public void copyScreenToImageFile(int? imageIndex)
		{
			// Adapted from code found at the URL
			// https://stackoverflow.com/questions/5049122/capture-the-screen-shot-using-net

			Rectangle captureBounds;

			if (this.CaptureBoundsNullable == null)
			{
				captureBounds = Screen.PrimaryScreen.Bounds;
			}
			else
			{
				captureBounds = this.CaptureBoundsNullable.Value;
			}	

			Bitmap bitmapCaptured = new Bitmap
			(
				captureBounds.Width, 
				captureBounds.Height
			);
			
			Graphics graphics = Graphics.FromImage(bitmapCaptured);
			
			graphics.CopyFromScreen
			(
				captureBounds.X, captureBounds.Y, // source
				0, 0, // destination
				bitmapCaptured.Size 
				// CopyPixelOperation.SourceCopy
			);

			string filePathToSaveTo = 
				this.FilePathStemToSaveTo 
				+ (imageIndex == null ? "" : imageIndex.Value.ToString())
				+ this.ImageFileExtension;

			Console.WriteLine("Saving " + filePathToSaveTo + "...");

			try
			{
				bitmapCaptured.Save(filePathToSaveTo);
			}
			catch (Exception)
			{
				string errorMessage = 
					"Error attemping to save file.  Ensure directory exists, and permissions are adequate.";
				Console.WriteLine(errorMessage);
			}
		}
	}
}

6. Click the “Projects” tab on the Solution Explorer pane, then expand the tree nodes until you see the “References” node. Right-click the “References” node and select the “Add Reference” item from the context menu that appears.

7. On the Add Reference dialog, on the GAC tab, scroll through the list of assemblies to locate the entries for “System.Drawing” and “Microsoft.Forms”. Select each entry and click the “Select” button to add it to the “Selected References” pane. When both assemblies have been added, click the OK button to add the references and to dismiss the dialog.

8. Back in the SharpDevelop main window, select the item “Build – Build Solution” from the main menu.

9. Locate the compiled ScreenshotCapturer.exe file in the output directory (typically located at “/bin/Debug” under the project’s main directory and copy it to any convenient location.

10. When run from the command-line, ScreenCapturer.exe will create the specified number of screenshots of the specified size and at the specified location, delaying some amount of time between each subsequent screenshot. If no arguments are specified, the program will simply take a single screenshot of the entire screen and give it a default name.

Advertisements
This entry was posted in Uncategorized and tagged , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s