Make a close-up window for an image in C#


close-up window

Lots of web sites display a close-up window that displays a zoomed-in piece of an image so you can see extra details. You move the mouse around on the main image and it displays the close-up in a separate picture. This example does something similar. (Some of the math the example uses is pretty tricky so you may need to look at it pretty hard to see how it works.)

The close-up is really just a full-scale copy of the original image. (The “main” image is the same image at a smaller scale.) To display a close-up, the program displays the full-scale image inside a PictureBox named picCloseup. That control sits inside a Panel named panCloseup. By moving picCloseup around inside panCloseup, the program can display different pieces of the full-scale image.

The following code gets the program ready to start.

// Save the original image.
private Bitmap OriginalImage, ShadedImage;
private int SmallWidth, SmallHeight;
private float ScaleX, ScaleY;
private void Form1_Load(object sender, EventArgs e)
{
    OriginalImage = picWhole.Image as Bitmap;
    picCloseup.Image = OriginalImage;
    picCloseup.SizeMode = PictureBoxSizeMode.AutoSize;

    // Make a shaded version of the image.
    ShadedImage = new Bitmap(OriginalImage);
    using (Graphics gr = Graphics.FromImage(ShadedImage))
    {
        using (Brush br =
            new SolidBrush(Color.FromArgb(128, 255, 255, 255)))
        {
            Rectangle rect = new Rectangle(0, 0,
                ShadedImage.Width, ShadedImage.Height);
            gr.FillRectangle(br, rect);
        }
    }

    // Get scale factors to map from big scale to small scale.
    ScaleX = (float)panCloseup.ClientSize.Width /
        OriginalImage.Width;
    ScaleY = (float)panCloseup.ClientSize.Height /
        OriginalImage.Height;

    // See how big the closeup is on the small scale.
    SmallWidth = (int)(ScaleX * picWhole.ClientSize.Width);
    SmallHeight = (int)(ScaleY * picWhole.ClientSize.Height);
}

This code saves the original image and makes a lightened version of that image. To make the lightened version, it copies the original and then fills it with a semi-transparent white rectangle. This becomes the main image that you move the mouse over.

The following code executes when the mouse moves in or out of the main image.

// Use the shaded background image.
private void picWhole_MouseEnter(object sender, EventArgs e)
{
    picWhole.Image = ShadedImage;
    panCloseup.Visible = true;
}

// Use the regular image.
private void picWhole_MouseLeave(object sender, EventArgs e)
{
    picWhole.Image = OriginalImage;
    panCloseup.Visible = false;
}

When the mouse is outside of the main image, the program displays the normal non-lightened version. When the mouse enters the image, the program switches to show the lightened image.

When the mouse moves while over the main image, the following code displays a close-up of the area around the mouse.

// Display a closeup of this area.
private Rectangle ViewingRectangle;
private void picWhole_MouseMove(object sender, MouseEventArgs e)
{
    // Position picCloseup inside its parent Panel.
    float x = (float)e.X / picWhole.ClientSize.Width *
        OriginalImage.Width -
        (float)panCloseup.ClientSize.Width / 2;
    float y = (float)e.Y / picWhole.ClientSize.Height *
        OriginalImage.Height -
        (float)panCloseup.ClientSize.Height / 2;
    if (x < 0) x = 0;
    if (y < 0) y = 0;
    if (x > OriginalImage.Width - panCloseup.ClientSize.Width)
        x = OriginalImage.Width - panCloseup.ClientSize.Width;
    if (y > OriginalImage.Height - panCloseup.ClientSize.Height)
        y = OriginalImage.Height - panCloseup.ClientSize.Height;
    picCloseup.Location = new Point(-(int)x, -(int)y);

    // Record the position we are viewing.
    ViewingRectangle = new Rectangle((int)x, (int)y,
        panCloseup.ClientSize.Width, 
        panCloseup.ClientSize.Height);

    // Draw the closeup area.
    picWhole.Invalidate();
}

First the code decides where the area around the mouse is. If that area lies partly outside of the main image, the code adjusts its X and Y coordinates so the area lies within the main image. That lets the close-up show as much of the image as possible.

The code moves picCloseup within panCloseup to display the correct piece of the full-scale image. It then records the area on the main image that it will display in the variable ViewingRectangle and invalidates the main image to make it redraw. The following code shows the main picture’s Paint event handler, which handles that redrawing.

// Draw the viewing area.
private void picWhole_Paint(object sender, PaintEventArgs e)
{
    // Scale so we can draw in the full scale coordinates.
    e.Graphics.ScaleTransform(ScaleX, ScaleY);

    // Draw the viewing area using the original image.
    e.Graphics.DrawImage(OriginalImage, ViewingRectangle, 
        ViewingRectangle, GraphicsUnit.Pixel);
    //e.Graphics.DrawRectangle(Pens.Red, ViewingRectangle);
}

This code uses a transformation so it can draw using the full-scale image’s coordinates instead of those used by the main image (which you may recall is at a reduced scale). It then copies part of the original full-scale image onto the main image to show the area around the mouse. The result is that the main image is shaded except for this area, which is drawn with its original brightness. Uncomment the last line in this method to draw a red rectangle around the close-up area in the main image.

I admit that this is a confusing example, but it’s a very cool effect so I encourage you to download it and give it a try. If you experiment with the code a bit, you can figure out how it works. (And Enceladus is a particularly strange moon to look at!)


Download Example   Follow me on Twitter   RSS feed




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

Leave a Reply

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