Use a notify icon to capture a screen image in C#

[notify icon]

The example Save an image of the computer’s screen in a file in C# lets you save an image of the computer’s screen in a file. This example provides a few convenience features.

One problem with a basic screen capture program is that it sits somewhere on the screen so the image it captures includes a picture of itself. Sometimes you may not want that.

This example is normally invisible and you interact with it through a notify icon in the system tray. Because the program doesn’t sit on the desktop, it’s not part of the screen capture.

To use a notify icon, simply add a NotifyIcon component to a form. Set the component’s ContextMenu property to the ContextMenu that you want the program to display when the user right-clicks the icon.

This example displays the context menu shown above. The Capture All command captures an image of the desktop and lets you save it into a file. The Select Area command lets you click and drag to select an area and then saves an image of that area into a file.

The following code shows how the Capture All command works.

// Capture the whole screen.
private void mnuWholeScreen_Click(object sender, EventArgs e)
{
    // Get the whole screen's image.
    using (Bitmap bm = GetScreenImage())
    {
        // Save it.
        SavePicture(bm);
    }
}

This code simply calls the GetScreenImage and SavePicture methods shown in the following code.

// Grab the screen's image.
private Bitmap GetScreenImage()
{
    // Make a bitmap to hold the result.
    Bitmap bm = new Bitmap(
        Screen.PrimaryScreen.Bounds.Width, 
        Screen.PrimaryScreen.Bounds.Height, 
        PixelFormat.Format24bppRgb);

    // Copy the image into the bitmap.
    using (Graphics gr = Graphics.FromImage(bm))
    {
        gr.CopyFromScreen(
            Screen.PrimaryScreen.Bounds.X,
            Screen.PrimaryScreen.Bounds.Y,
            0, 0,
            Screen.PrimaryScreen.Bounds.Size,
            CopyPixelOperation.SourceCopy);
    }

    // Return the result.
    return bm;
}

// Save the picture in a file selected by the user.
private void SavePicture(Bitmap bm)
{
    // Let the user pick a file to hold the image.
    if (sfdScreenImage.ShowDialog() == DialogResult.OK)
    {
        // Save the bitmap in the selected file.
        string filename = sfdScreenImage.FileName;
        FileInfo file_info = new FileInfo(filename);
        switch (file_info.Extension.ToLower())
        {
            case ".bmp":
                bm.Save(filename, ImageFormat.Bmp);
                break;
            case ".gif":
                bm.Save(filename, ImageFormat.Gif);
                break;
            case ".jpg":
            case ".jpeg":
                bm.Save(filename, ImageFormat.Jpeg);
                break;
            case ".png":
                bm.Save(filename, ImageFormat.Png);
                break;
            default:
                MessageBox.Show("Unknown file type " +
                    file_info.Extension, "Unknown Extension",
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                break;
        }
    }
}

The GetScreenImage method makes a Bitmap the size of the screen and then uses the Graphics class’s CopyFromScreen method to get an image of the screen.

The SavePicture method displays a SaveFileDialog to let the user pick a file. If the user picks a file and clicks Save, the program saves the Bitmap in a file format that depends on the file’s extension.

This is useful but the code that lets you capture an area on the desktop is even more interesting. When you select the Capture Area menu item, the following code starts the process.

// Let the user select a part of the screen.
private void mnuCaptureArea_Click(object sender, EventArgs e)
{
    // Get the whole screen's image.
    ScreenBm = GetScreenImage();

    // Display a copy.
    VisibleBm = (Bitmap)ScreenBm.Clone();

    // Display it.
    this.BackgroundImage = VisibleBm;
    this.Location = new Point(0, 0);
    this.ClientSize = VisibleBm.Size;
    this.MouseDown += Form1_MouseDown;
    this.Show();
}

This code uses the GetScreenImage method to get an image of the screen. It then makes a copy of that image and displays it on the program’s form. It installs a MouseDown event handler and displays the form.

When you press the mouse down on the form, the following event handler executes.

// Start selecting an area.
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
    X0 = e.X;
    Y0 = e.Y;
    X1 = e.X;
    Y1 = e.Y;

    this.MouseDown -= Form1_MouseDown;
    this.MouseMove += Form1_MouseMove;
    this.MouseUp += Form1_MouseUp;
}

This code saves the current mouse position. It uninstalls the MouseDown event handler and installs MouseMove and MouseUp event handlers. The following code shows the MouseMove event handler.

// Continue selecting an area.
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    X1 = e.X;
    Y1 = e.Y;

    using (Graphics gr = Graphics.FromImage(VisibleBm))
    {
        // Copy the original image.
        gr.DrawImage(ScreenBm, 0, 0);

        // Draw the selected area.
        Rectangle rect = new Rectangle(
            Math.Min(X0, X1),
            Math.Min(Y0, Y1),
            Math.Abs(X1 - X0),
            Math.Abs(Y1 - Y0));
        gr.DrawRectangle(Pens.Yellow, rect);
    }
    this.Refresh();
}

This event handler makes a Graphics object associated with the VisibleBm bitmap that is currently displayed on the form. It draws the original screen image onto this bitmap and then adds a yellow rectangle showing the area that the user has currently selected.

The following code shows the MouseUp event handler.

// Finish selecting an area.
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
    this.Visible = false;
    this.MouseMove -= Form1_MouseMove;
    this.MouseUp -= Form1_MouseUp;

    // Save the selected part of the image.
    int wid = Math.Abs(X1 - X0);
    int hgt = Math.Abs(Y1 - Y0);
    Rectangle dest_rect = new Rectangle(0, 0, wid, hgt);
    Rectangle source_rect = new Rectangle(
        Math.Min(X0, X1),
        Math.Min(Y0, Y1),
        Math.Abs(X1 - X0),
        Math.Abs(Y1 - Y0));
    using (Bitmap selection = new Bitmap(wid, hgt))
    {
        // Copy the selected area.
        using (Graphics gr = Graphics.FromImage(selection))
        {
            gr.DrawImage(ScreenBm, dest_rect,
                source_rect, GraphicsUnit.Pixel);
        }

        // Save the selected area.
        SavePicture(selection);
    }

    // Dispose of the other bitmaps.
    this.BackgroundImage = null;
    ScreenBm.Dispose();
    VisibleBm.Dispose();
    ScreenBm = null;
    VisibleBm = null;
}

This event handler hides the form and uninstalls the mouse event handlers. It copies the selected part of the original screen image into a new bitmap sized to fit and calls SavePicture to let the user save the selected area into a file.

The code finishes by disposing of the bitmaps it created to free up graphics resources.


Download Example   Follow me on Twitter   RSS feed   Donate




This entry was posted in graphics, system and tagged , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *