There are many screenshot/screensnipping tools out there and none of them performed as I needed them. Nevertheless I gathered
impressions and decided to compile the best ideas into a product, I am confident that you will like it.
My requirements for a snipping tool (all implemented) are as follows:
- Be able to select part of the screen with your mouse and save it to a file and/or copy it to the clipboard.
- Also detect pressing the PrintScreen key and save the clipboard contents to a file.
- Save the screenshots automatically to some predefined location with a default image format (not open a dialog every time, nor an editor)
- However be able to specify a different location and image format every now and then.
- No GUI. I wanted it to run in the background (in this case, the system tray).
- Activate it via keyboard shortcut. It is a deal breaker if you have to navigate to the app for every screenshot, when you are making a lot of them.
- Work on multiple monitors!
This is more of a Tips n' Tricks entry. I will only be addressing key problems/solutions with brief descriptions and references where I see fit. Not all of the requirements will be discussed as not all of them present a "challenge" to the programmer.
For the project, I decided to use C# as it seems the most appropriate choice for a Windows application. Furthermore for the PrintScreen keys I was going to use hooks, which is of course OS specific, so there was no way to make a OS portable application in a short time. Having said that, the application has only been tested on Windows 7 64bit with .NET 4 and Vista 32bit. The executables attached to this tip may not work on other platforms.
I expect the source code to be portable to older versions of .NET and Windows. Feedback would be appreciated.
Using the Code
There are several classes, each dedicated to a specific task. There are several secondary classes, such as the Settings Form, Help Form, etc.
It is not the purpose of this tip to discuss how the application is built so this is as much as I will say about the code structure.
The SnippingTool that comes with Windows 7 has a really nice interface. Once you start it, it dims the screen and you can draw a transparent rectangle on the screen, marking the area you want to copy. One way to do this is to create a form with no controls, maximize it, draw on it with the mouse, pick the coordinates and take a screen shot. Really, a straightforward task! However when you have multiple monitors, the form would maximize only on one of them. So I needed to resize the form manually. The Virtual Screen is the (rectangular) area that includes all the monitors.
You can get the origin and the size like this:
The origin may have negative coordinates. Beware when calculating! The resizing presented me with a challenge due to my lack of understanding! Merely setting the size and location of my form to those of the virtual screen was not enough. It did indeed resize the form but not the area on which I could draw. Maximizing the form took care of everything, but now I had to do it manually, whatever it may be that had to be done. Without going into detail (keywords being
ClientRectangle, etc.), the problem was solved by the following line:
this.Bounds = new Rectangle(SystemInformation.VirtualScreen.X, SystemInformation.VirtualScreen.Y,
Drawing on the form was an easy task:
Graphics g = this.CreateGraphics(); g.DrawRectangle(new Pen(Color.Red, 3), x, y, width, height);
As for making the screenshot programmatically, I was going to go with Win32 API if I hadn't found this similar project, Tebo Basic C Screen Capture Application which reveals a neat solution:
Bitmap bitmap = new Bitmap(width, height));
Graphics g = Graphics.FromImage(bitmap)
g.CopyFromScreen(SourcePoint, DestinationPoint, SelectionRectangle.Size);
Just for the sake of completeness (although by no means can this make the tip complete) saving an image to a file:
Retrieving an image from the clipboard and setting one is as easy as this:
Image img = Clipboard.GetImage();
For the PrintScreen hook, I blatantly copied the
InterceptKeys class into my project from here.
It is pretty basic and self explanatory. Caution should be exercised when catching the
KeyDown event nevertheless, as the order of propagating the event between applications is not set, and reading out the clipboard may occur before the new screenshot has been taken.
Since I was already using hooks, I just added a hotkey combination, namely Ctrl + Space + C.
Points of Interest
Places for improvement:
- a list of default locations to save an image to
- a list of commands/programs to be executed on capture
- quality of pictures could be better
- 2012-06-26 bug fix, files updated