Click here to Skip to main content
15,881,248 members
Articles / Multimedia / GDI+

Screen Capturing

Rate me:
Please Sign up or sign in to vote.
4.77/5 (46 votes)
24 Mar 20062 min read 261.2K   3.2K   224  
Capture screen contents without using any Win32 API calls, just using .NET (2.0) classes.
/*----------------------------------------------------------------------------------------

	A-Soft Ingenieurbüro

	Copyright © 1994 - 2007. All Rights reserved.

	Related Copyrights :

			Microsoft .NET Windows Forms V2.0 library.
			Copyright (C) 2004...2006 Microsoft Corporation,
			All rights reserved.


	FILE		:	ScreenCapture.cs

	PROJECT		:	A-Soft Library
	SUB			:	Standard Library
 
	SYSTEM		:	Windows-XP, (Windows 2000), C# (.NET 2.0, Visual Studio.NET 2005)

	AUTHOR		:	Joachim Holzhauer
	
	DESCRIPTION	:	This class implements the capturing of a screen (form, complete desktop etc.)
 
	VERSION		:	1.0 - 2006.01.31

----------------------------------------------------------------------------------------*/

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Windows.Forms;
using System.IO;

using ASFTBase;

namespace ASFTBase.Graphic
{
	public delegate Bitmap CaptureHandleDelegateHandler( IntPtr handle );

	/// <summary>
	/// This class implements the capturing of a screen (form, complete desktop etc.).
	/// The captured image(s) can be saved into a file in different formats, 
	/// and it can be printed.
	/// 
	/// </summary>
	public class ScreenCapture
	{
		/// <summary>
		/// Define the ype of screen capture.
		/// </summary>
		public enum CaptureType
		{
			/// <summary>
			/// Capture the complete virtual screen (on multi monitor applications all screens).
			/// </summary>
			VirtualScreen,

			/// <summary>
			/// Capture the complete primary screen, including the taskbar.
			/// </summary>
			PrimaryScreen,

			/// <summary>
			/// Capture only the working area of the primary screen, this excludes the taskbar.
			/// </summary>
			WorkingArea,

			/// <summary>
			/// On a multi monitor system capture all screens in different images.
			/// </summary>
			AllScreens
		};

		/// <summary>
		/// The actual image used in printing
		/// </summary>
		private Bitmap image;

		/// <summary>
		/// These are all captured images.
		/// </summary>
		private Bitmap[] images = null;

		/// <summary>
		/// Used for printing the captured object
		/// </summary>
		private PrintDocument doc = new PrintDocument();

		/// <summary>
		/// Handler for the different graphic formats
		/// </summary>
		private ImageFormatHandler formatHandler = null;

		/// <summary>
		/// Define a format handler
		/// </summary>
		public ImageFormatHandler FormatHandler
		{
			set { formatHandler = value; }
		}

		/// <summary>
		/// Creator
		/// </summary>
		public ScreenCapture()
		{
			doc.PrintPage += new PrintPageEventHandler( printPage );
			formatHandler = new ImageFormatHandler();
		}

		/// <summary>
		/// Creator, set format handler
		/// </summary>
		/// <param name="formatHandler">The format handler instance</param>
		public ScreenCapture( ImageFormatHandler formatHandler )
		{
			doc.PrintPage += new PrintPageEventHandler( printPage );

			this.formatHandler = formatHandler;
		}

		/// <summary>
		/// Capture a specific form and save it into a file.
		/// </summary>
		/// <param name="window">This is the desired window which should be captured.</param>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( Form window, String filename, ImageFormatHandler.ImageFormatTypes format )
		{
			return Capture( window, filename, format, false );
		}

		/// <summary>
		/// Capture a specific form and save it into a file.
		/// </summary>
		/// <param name="window">This is the desired window which should be captured.</param>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <param name="onlyClient">When set to 'true' then only the client area of the form is captured,
		/// otherwise the complete window with title bar, frame etc. is captured.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( Form window, String filename, ImageFormatHandler.ImageFormatTypes format, bool onlyClient )
		{
			Capture( window, onlyClient );
			Save( filename, format );
			return images[0];
		}

		/// <summary>
		/// Execute the capturing of window specified by it's windows handle.
		/// </summary>
		/// <param name="handle">The handle of the window to capture</param>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( IntPtr handle, String filename, ImageFormatHandler.ImageFormatTypes format )
		{
			Capture( handle );
			Save( filename, format );
			return images[0];
		}

		/// <summary>
		/// Capture a specific control in the client area of a form.
		/// </summary>
		/// <param name="window">This is a control which should be captured.</param>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap CaptureControl( Control window, String filename, ImageFormatHandler.ImageFormatTypes format )
		{
			CaptureControl( window );
			Save( filename, format );
			return images[0];
		}

		/// <summary>
		/// Capture a specific control in the client area of a form.
		/// </summary>
		/// <param name="window">This is a control which should be captured.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap CaptureControl( Control window )
		{
			Rectangle rc = window.RectangleToScreen( window.DisplayRectangle );
			return capture( window, rc );
		}

		/// <summary>
		/// Capture a specific form.
		/// </summary>
		/// <param name="window">This is the desired window which should be captured.</param>
		/// <param name="onlyClient">When set to 'true' then only the client area of the form is captured,
		/// otherwise the complete window with title bar, frame etc. is captured.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( Form window, bool onlyClient )
		{
			if ( !onlyClient )
				return Capture( window );

			Rectangle rc = window.RectangleToScreen( window.ClientRectangle );
			return capture( window, rc );
		}

		/// <summary>
		/// Capture a specific form.
		/// </summary>
		/// <param name="window">This is the desired window which should be captured.</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( Form window )
		{
			Rectangle rc = new Rectangle( window.Location, window.Size );
			return capture( window, rc );
		}

		/// <summary>
		/// Execute the capturing of a specified rectangle in a given window.
		/// </summary>
		/// <param name="window">The window to capture</param>
		/// <param name="rc">The rectangle used for capturing</param>
		/// <returns>The image which has been captured.</returns>
		private Bitmap capture( Control window, Rectangle rc )
		{
			Bitmap memoryImage = null;
			images = new Bitmap[1];

			try
			{
				// Create new graphics object using handle to window.
				using ( Graphics graphics = window.CreateGraphics() )
				{
					memoryImage = new Bitmap( rc.Width, rc.Height, graphics );

					using ( Graphics memoryGrahics = Graphics.FromImage( memoryImage ) )
					{
						memoryGrahics.CopyFromScreen( rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy );
					}
				}
			}
			catch ( Exception ex )
			{
				MessageBox.Show( ex.ToString(), "Capture failed", MessageBoxButtons.OK, MessageBoxIcon.Error );
			}
			images[0] = memoryImage;
			return memoryImage;
		}

		/// <summary>
		/// Execute the capturing of a window specified by it's windows handle.
		/// The image which has been captured is saved to the 'images[0]' attribute in this class.
		/// This method uses old API calls !!!!!!!
		/// </summary>
		/// <param name="handle">The handle of the window to capture</param>
		/// <returns>The image which has been captured.</returns>
		public virtual Bitmap Capture( IntPtr handle )
		{
			//	Move the window to capture to the top of the Z order.
			NativeMethods.BringWindowToTop( handle );

			CaptureHandleDelegateHandler dlg = new CaptureHandleDelegateHandler( CaptureHandle );

			//	Do an asynchronous call of the capturing method, this is necessary to allow the captured
			//	window to come up in front of the Z-order of the displayed screens.
			IAsyncResult result = dlg.BeginInvoke( handle, null, null );
			return dlg.EndInvoke( result );
		}

		
		/// <summary>
		/// Execute the capturing of a window specified by it's windows handle.
		/// This method uses old API calls !!!!!!!
		/// </summary>
		/// <param name="handle">The handle of the window to capture</param>
		/// <returns>The image which has been captured.</returns>
		protected virtual Bitmap CaptureHandle( IntPtr handle )
		{
			Bitmap memoryImage = null;
			images = new Bitmap[1];
			try
			{
				// Create new graphics object using handle to window.
				using ( Graphics graphics = Graphics.FromHwnd( handle ) )
				{
					Rectangle rc = NativeMethods.GetWindowRect( handle );

					if ( (int)graphics.VisibleClipBounds.Width > 0 && (int)graphics.VisibleClipBounds.Height > 0 )
					{
						memoryImage = new Bitmap( rc.Width, rc.Height, graphics );

						using ( Graphics memoryGrahics = Graphics.FromImage( memoryImage ) )
						{
							memoryGrahics.CopyFromScreen( rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy );
						}
					}
				}
			}
			catch ( Exception ex )
			{
				MessageBox.Show( ex.ToString(), "Capture failed", MessageBoxButtons.OK, MessageBoxIcon.Error );
			}
			images[0] = memoryImage;
			return memoryImage; 
		}

		/// <summary>
		/// Capture the screen and save it into a file, which portion of the screen is captured
		/// is defined by <paramref name="typeOfCapture"/>.
		/// </summary>
		/// <param name="typeOfCapture">Selects, what is actually captured, see <see cref="CaptureType"/>.</param>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <returns>An array of images captured.</returns>
		public virtual Bitmap[] Capture( CaptureType typeOfCapture, String filename, ImageFormatHandler.ImageFormatTypes format )
		{
			Capture( typeOfCapture );
			Save( filename, format );
			return images;
		}

		/// <summary>
		/// Capture the screen, which portion of the screen is captured
		/// is defined by <paramref name="typeOfCapture"/>.
		/// </summary>
		/// <param name="typeOfCapture">Selects, what is actually captured, see <see cref="CaptureType"/>.</param>
		/// <returns>An array of images captured.</returns>
		public virtual Bitmap[] Capture( CaptureType typeOfCapture )
		{
			Bitmap memoryImage;
			int count = 1;

			try
			{
				Screen[] screens = Screen.AllScreens;
				Rectangle rc;
				switch ( typeOfCapture )
				{
					case CaptureType.PrimaryScreen:
						rc = Screen.PrimaryScreen.Bounds;
						break;
					case CaptureType.VirtualScreen:
						rc = SystemInformation.VirtualScreen;
						break;
					case CaptureType.WorkingArea:
						rc = Screen.PrimaryScreen.WorkingArea;
						break;
					case CaptureType.AllScreens:
						count = screens.Length;
						typeOfCapture = CaptureType.WorkingArea;
						rc = screens[0].WorkingArea;
						break;
					default:
						rc = SystemInformation.VirtualScreen;
						break;
				}
				images = new Bitmap[count];

				for ( int index = 0; index < count; index++ )
				{
					if ( index > 0 )
						rc = screens[index].WorkingArea;

					memoryImage = new Bitmap( rc.Width, rc.Height, PixelFormat.Format32bppArgb );

					using ( Graphics memoryGrahics = Graphics.FromImage( memoryImage ) )
					{
						memoryGrahics.CopyFromScreen( rc.X, rc.Y, 0, 0, rc.Size, CopyPixelOperation.SourceCopy );
					}
					images[index] = memoryImage;
				}
			}
			catch ( Exception ex )
			{
				MessageBox.Show( ex.ToString(), "Capture failed", MessageBoxButtons.OK, MessageBoxIcon.Error );
			}
			return images;
		}

		/// <summary>
		/// Print all captured screens.
		/// </summary>
		public virtual void Print()
		{
			if ( images != null )
			{
				try
				{
					for ( int i = 0; i < images.Length; i++ )
					{
						image = images[i];
						doc.DefaultPageSettings.Landscape = ( image.Width > image.Height );
						doc.Print();
					}
				}
				catch ( Exception ex )
				{
					MessageBox.Show( ex.ToString(), "Capture failed", MessageBoxButtons.OK, MessageBoxIcon.Error );
				}
			}
		}

		/// <summary>
		/// Event handler called from printing.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void printPage( object sender, PrintPageEventArgs e )
		{
			RectangleF rc = doc.DefaultPageSettings.Bounds;
			float ratio = (float)image.Height / (float)( image.Width != 0 ? image.Width : 1 );

			rc.Height = rc.Height - doc.DefaultPageSettings.Margins.Top - doc.DefaultPageSettings.Margins.Bottom;
			rc.Y = rc.Y + doc.DefaultPageSettings.Margins.Top;

			rc.Width = rc.Width - doc.DefaultPageSettings.Margins.Left - doc.DefaultPageSettings.Margins.Right;
			rc.X = rc.X + doc.DefaultPageSettings.Margins.Left;

			if ( rc.Height / rc.Width > ratio )
				rc.Height = rc.Width * ratio;
			else
				rc.Width = rc.Height / ( ratio != 0 ? ratio : 1 );

			e.Graphics.DrawImage( image, rc );
		}

		/// <summary>
		/// Save all captured screens into a file.
		/// </summary>
		/// <param name="filename">The name of the target file. The extension in there is ignored, 
		/// it will replaced by an extension derived from the desired file format.</param>
		/// <param name="format">The format of the file.</param>
		/// <returns>An array of images captured.</returns>

		public virtual void Save( String filename, ImageFormatHandler.ImageFormatTypes format )
		{
			String directory = Path.GetDirectoryName( filename );
			String name = Path.GetFileNameWithoutExtension( filename );
			String ext = Path.GetExtension( filename );

			ext = formatHandler.GetDefaultFilenameExtension( format );

			if ( ext.Length == 0 )
			{
				format = ImageFormatHandler.ImageFormatTypes.imgPNG;
				ext = "png";
			}

			try
			{
				ImageCodecInfo info;
				EncoderParameters parameters = formatHandler.GetEncoderParameters( format, out info );

				for ( int i = 0; i < images.Length; i++ )
				{
					if ( images.Length > 1 )
					{
						filename = String.Format( "{0}\\{1}.{2:D2}.{3}", directory, name, i + 1, ext );
					}
					else
					{
						filename = String.Format( "{0}\\{1}.{2}", directory, name, ext );
					}
					image = images[i];

					if ( parameters != null )
					{
						image.Save( filename, info, parameters );
					}
					else
					{
						image.Save( filename, ImageFormatHandler.GetImageFormat( format ) );
					}
				}
			}
			catch ( Exception ex )
			{
				string s = string.Format("Saving image to [{0}] in format [{1}].\n{2}", filename, format.ToString(), ex.ToString() );
				MessageBox.Show( s, "Capture failed", MessageBoxButtons.OK, MessageBoxIcon.Error );
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) Retired
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions