Crop images to specific sizes in C#

[example]

Sometimes I need to crop images to specific sizes or aspect ratios. For example, the following list shows some recommended image sizes for Google Business.

  • Profile image – 250×250 pixels
  • Cover photo – 1080×608 pixels
  • Shared images – 497×373 pixels

Unfortunately if you use a program like MS Paint to crop the image, it’s hard to get a desired size that is nicely centered on an area of interest. This example shows how you can crop images by positioning a selection rectangle over a desired part of the image.

Use the File menu’s Open command to open an image file. Next, enter the width and height of the area that you want to select. Then click and drag the selection rectangle to select the part of the image that you want to keep. Finally, use the File menu’s Save As command to save the selected part of the image into a new file.

The following sections describe the main pieces of the program’s code.

Dragging the Selection Rectangle

The program uses the following variables to keep track of the selection rectangle.

private Rectangle SelectedRect = new Rectangle();
private bool Dragging = false;
private Point LastPoint;

The variable SelectedRect gtracks the currently selected rectangle. The value Dragging is true while a drag is in progress. The point LastPoint stores the last mouse position while a drag is in progress.

When you press the mouse button down on the picImage PictureBox, the following event handler executes.

// Start dragging.
private void picImage_MouseDown(object sender, MouseEventArgs e)
{
    // If the mouse is not inside the
    // selection rectangle, do nothing.
    if (!SelectedRect.Contains(e.Location)) return;

    // Start the drag.
    LastPoint = e.Location;
    Dragging = true;
}

This code calls the SelectedRect rectangle’s Contains method to determine whether the mouse’s location is inside the rectangle. If the mouse is not inside the rectangle, the method returns without doing anything.

If the mouse is inside the rectangle, the code saves the mouse location in variable LastPoint and sets Dragging to true.

If you move the mouse over the PictureBox, the following event handler executes.

// Continue dragging.
private void picImage_MouseMove(object sender, MouseEventArgs e)
{
    // See if we are dragging.
    if (Dragging)
    {
        // We are dragging. Move the selected rectangle.
        SelectedRect.X += e.Location.X - LastPoint.X;
        SelectedRect.Y += e.Location.Y - LastPoint.Y;
        LastPoint = e.Location;
        picImage.Refresh();
    }
    else
    {
        // We are not dragging. Update the cursor.
        if (SelectedRect.Contains(e.Location))
            Cursor = Cursors.SizeAll;
        else
            Cursor = Cursors.Default;
    }
}

This code checks the Dragging variable to see if a drag is in progress.

If a drag is in progress, the code subtracts the coordinates of the previous mouse location (stored in the variable LastPoint) from the mouse’s current location. It uses the difference in coordinates to update the upper left corner of the selection rectangle. It then saves the mouse’s current location in variable LastPoint and refreshes the PictureBox to display new selection rectangle.

If no drag is in progress, the code calls the selection rectangle’s Contains method to see if the mouse if over the currently selected rectangle. If the mouse is over the rectangle, the program displays the SizeAll cursor. If the mouse is not over the rectangle, the program displays the default cursor.

When you release the mouse button, the following event handler executes.

// Stop dragging.
private void picImage_MouseUp(object sender, MouseEventArgs e)
{
    Dragging = false;
}

This code simply sets Dragging to false to end the current drag.

Drawing the Selection Rectangle

The following code shows how the program’s PictureBox draws the selection rectangle.

// Draw the selection rectangle.
private void picImage_Paint(object sender, PaintEventArgs e)
{
    try
    {
        // Draw the selection rectangle.
        using (Pen pen = new Pen(Color.Red, 2))
        {
            e.Graphics.DrawRectangle(pen, SelectedRect);

            pen.Color = Color.Yellow;
            pen.DashPattern = new float[] { 5, 5 };
            e.Graphics.DrawRectangle(pen, SelectedRect);
        }
    }
    catch
    {
    }
}

This code creates a two-pixel-wide red Pen and uses it to draw the selection rectangle.

The code then changes the pen’s color to yellow, gives it a dash pattern, and redraws the rectangle with the modified pen. The result is the thick, dashed, red and yellow rectangle shown in the picture at the top of the post.

Saving the Selected Area

When you invoke the File menu’s Save As command, the following code executes.

// Save the selected area.
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
    if (sfdImage.ShowDialog() == DialogResult.OK)
    {
        try
        {
            // Copy the selected area into a new Bitmap.
            Bitmap bm = new Bitmap(
                SelectedRect.Width,
                SelectedRect.Height);
            using (Graphics gr = Graphics.FromImage(bm))
            {
                gr.DrawImage(picImage.Image, 0, 0,
                    SelectedRect, GraphicsUnit.Pixel);
            }

            // Save the new Bitmap.
            SaveImage(bm, sfdImage.FileName);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}

This code displays a SaveFileDialog to let you pick the file that should contain the selected part of the image. If you pick a file and click Save, the code creates a new Bitmap that is the same size as the rectangle and makes a Graphics object associated with the Bitmap. The code then uses the Graphics object’s DrawImage method to draw the selected part of the image on the Bitmap.

The code finishes by using the SaveImage method to save the bitmap into the file with the appropriate file format (JPG, PNG, BMP, etc.). For information on the SaveImage method, see my post Save images with an appropriate format depending on the file name’s extension in C#.

Resizing the Rectangle

If you change the value in the width or height text box, one of the following event handlers executes.

private void txtWidth_TextChanged(object sender, EventArgs e)
{
    // Get the new value.
    int value;
    if (!int.TryParse(txtWidth.Text, out value)) value = 0;
    SelectedRect.Width = value;
    picImage.Refresh();
}

private void txtHeight_TextChanged(object sender, EventArgs e)
{
    int value;
    if (!int.TryParse(txtHeight.Text, out value)) value = 0;
    SelectedRect.Height = value;
    picImage.Refresh();
}

These methods try to parse the width and height values. If a value is not a valid integer, the program sets that value to zero. It then sets the selection rectangle’s corresponding size accordingly and refreshes the PictureBox to show the resized rectangle.

Conclusion

This example lets you crop images to a specific size relatively easily. A nice enhancement would be to let you change the size of the selection rectangle while preserving its aspect ratio. Maybe I’ll add that feature some day if I’m really bored.

Download the example to experiment with it and to see additional details.


Download Example   Follow me on Twitter   RSS feed   Donate




About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, graphics, image processing, tools and tagged , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.