Friday, January 19, 2007

Snap It! - How to take screen shot using .Net

Introduction

We all would have used snap shots (screen shots) to illustrate bugs or behavior or something that others could understand by seeing them. For taking snap shots we just hit the "Print Screen" key and copy it to Ms Paint and save it. Ever wondered how to programmatically take a snap shot? Then this article is for you.

Image-1 This is how the application looks

Scenario


Why do we need to take snapshots programmatically? Consider a scenario where you want to report some kind of behavior errors in an application. Human supervision is not possible when the occurrence of error is random. So we just code a program to take snap shots are regular intervals and store it as a image file. So that later you can use it.

GDI classes we need to know

Lets see what we need to know before we do coding. We need to have a little knowledge about GDI and graphics classes. The Graphics class provides methods for drawing objects to the display device. A Graphics object is associated with a specific device context. This class is used as a canvas to draw images. In order to display anything in a window, you have to obtain a reference to the window's Graphics object.


Next comes the Bitmap class. A Bitmap object is an object used to work with images defined by pixel data. A bitmap consists of the pixel data for a graphics image and its attributes.

Getting Started


To use the GDI classes we need to include System.Drawing.Imaging namespace in the "using" section of the code. Go to the source view and add a string variable and a property to the class. This string variable is used in the property to store and retrieve the output file name.

// variable to store output file name
private string strFilename;
// Property for storing and retrieving output file name
public string filename
{

get{return strFilename;}
set{strFilename=value;}
}


In the design view, add a button and a savefiledialog to the form. Double click the button and go to the click event in the code view. Use the savefiledialog control to retrieve the output file name from the user. And store the file name in the variable strFilename using the property filename.

// Check user clicked OK button
// Get the filename and put in the textbox and property
if(saveFileDialog1.ShowDialog()!=DialogResult.Cancel)
{

filename=saveFileDialog1.FileName;
}


Before taking the snap shot we hide our application because we don't want our application in the snap shot image. Sometimes even after hiding the application, the snap shot pictures our application, this is because the application takes few extra milliseconds to hide, so we make our application to wait for some milliseconds.

this.Hide();
// Slow the thread to hide the application before taking the snap
Thread.Sleep(200);

How to Snap It?

Now we create a Bitmap object to set the size of the screen. We use the width and height of the application screen to capture the snap shot. So the user can place our application screen on any area of the screen, move/resize to get the snap shot. To make the user more comfortable in selecting the snap shot area we make the application screen semi-transparent by setting the opacity of the form to 50%

Resizing the application
Image-2 Resizing and Moving the screen


// Setting the size of the screen for the bitmap Bitmap bmp= new Bitmap(this.Width,this.Height,PixelFormat.Format32bppArgb);


A Graphics object is required to get the image bounds and create the actual picture. So we initialize a Graphics object and get the image bounds from the Bitmap that we have already created. CopyFromScreen method is used to get the snap shot from the screen. Based on the user selection of the file type in the savefiledialog box, we use different image formats to save the file using Bitmap.Save function.

// Saving file in the selected image format
bmp.Save(filename,ImageFormat.Jpeg);

After saving the picture we show the application back by using the following statement

// Showing the application again this.Show();

Viewing the snap shot


Now the screen is captured and the picture is saved. We need to view the snap shot. There is an option available to see how your snap shot has come up, just right after saving the file. We use Process class of System.Diagnostic namespace to view the image file.

// Viewing the image
Process pr= new Process();
pr.StartInfo.FileName=filename;
pr.Start();

Viewing the imageViewing the image
Image -3 Viewing the saved image file

When the Start method is executed the image file is opened in the respective application configured in the system.
Thats all folks.

11 comments:

Ramjee said...

Good one. Informative. Though I haven't faced a use for this, I can see many places I could have used it.
You have a nice blog, keep posting more such useful stuff.

Jeeva said...

Nice Stuff.. Please Post all ur articles in http://forum.only4gurus.org . This is one of large Tamil Peoples Technical Commnuity. I expects ur prarticipation too.. vanthu kalakku machan.. :-)

lanzi.matteo said...

Hi, i have the problem that with copyFromScreen i can't capture form with no full opacity (transparent)

how can i fix it?
thanks a lot
Teo

Refik said...

Nice article! I like the things you do, if you are interested to do something together check out my stuff at www.e-dsp.com! btw. I am doing my major in cs and minor in ee.

Good luck,
Refik

Avijit said...

The graphic example was really a good one. But I've tried this and found that it is not capturing the right screen.Actualy it is giving a blank picture. Could you please help?
Thanks and Regards
Avijit

Chandramohan.P said...

That was really great and useful. But I could not make it and also could not find where I'm going wrong. The this is, it is giving a black snap! Please let me know where I'm wrong.

My code follows :
------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Threading;
using System.Drawing.Imaging;
using System.Diagnostics;

namespace Snap_It
{
public partial class frmSnapIt : Form
{
private string strFileName;

public string FileName
{
get { return strFileName; }
set { strFileName = value; }
}

public frmSnapIt()
{
InitializeComponent();
}

private void btnSnapIt_Click(object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog() != DialogResult.Cancel)
FileName = saveFileDialog1.FileName;

this.Hide();
Thread.Sleep(200);

Bitmap bmp = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
bmp.Save(FileName, ImageFormat.Jpeg);

this.Show();

// Viewing the image
Process pr = new Process();
pr.StartInfo.FileName = FileName;
pr.Start();
}
}
}

Please send it to my email id.

Michael said...

A friend and I have managed to use this idea, and code, along with some SMTP classes to make it very easy to snap a few screenshots, and quickly send an email(and or HTTP POST requests), to a ticketing system which has simplified a number of processes at our work place, possibly saving many hours of time.
Thank you!
--
Michael Kubler
http://www.kublermdk.com

Swati Jain said...

Hi
can u tell me how to execute this win apps with web application
with particular area on web page
(height width)?

CELESTIAL CITIZEN said...

hi
I'm not posting a comment for this post.
I saw your article on how to pass data between forms in codeProject.
It was very simple, lucid and informative. Thank you

Nishith Raj said...

The article is good. And you have a nice blog too...

Nishith Raj said...

The article is good. And you have a nice blog too...

http://revolution-of-web.blogspot.com/