Magnify your pictures using a PictureBox so that you can zoom with the Mouse Wheel

Today’s digital cameras take pictures with much higher resolution than many computer screens. My Canon PowerShot SD800 IS camera takes pictures at 3072 x 2204 resolution.

 

One of my laptops died recently, and I noticed that local laptop retailers have machines with 1280 X 1024 resolution. I much prefer a higher resolution display, so I ordered a customizable Dell Inspiron 1525 with 1680 x 1050.

(I’ve been ordering computers from Dell for over 20 years, back in the days when it was called PC’s Limited. Why does Dell distinguish between business/government/home laptops?)

 

I was playing around with some photos using a PictureBox control, and I wanted to add a feature that would allow click/zoom using the mouse wheel to designate a point to magnify.

 

It was pretty easy to create my own class MyPictureBox which inherits from PictureBox and handles the MouseWheel and zooming.

 

Below are C# and VB versions. If I get enough requests, maybe I’ll make a Fox version (although I like this Fox version of zooming: Enable crop and zooming in on your digital photograph display form)

 

Start Visual Studio 2008 (I think these should work in VS2005)

File->New->Project->VB/C#->Windows Application.

 

View->Code, then paste the VB/C# code below, hit F5

 

Move the mouse to designate a zoom anchor point, then mouse wheel to zoom in/out

 

If you switch back to the form designer, the ToolBox has the MyPictureBox control on it, which you can drag/drop onto a form.

 

If you already have your own form that uses a PictureBox or several, you can avoid manually changing all the instances by carefully editing the Form1.Designer.vb file to replace the type with MyPictureBox (make a backup first).

 

As an exercise, try extending this feature by adding the ability to change the anchor point while zoomed or pan the zoomed picture.

 

Some VB/C# coding issues:

· semicolons

· capitalization

· intermediate arithmetic rounding results

· event handling

 

See also:

Enable crop and zooming in on your digital photograph display form

Create your own media browser: Display your pictures, music, movies in a XAML tooltip

 

<VB Code>

 

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Left = 0

        Me.Top = 0

        Me.Size = My.Computer.Screen.WorkingArea.Size

        Dim oPict = New MyPictureBox

        oPict.Size = Me.Size

        oPict.SizeMode = PictureBoxSizeMode.StretchImage

        oPict.Image = New Bitmap("d:\kids.jpg") ' path to some picture

        Me.Controls.Add(oPict)

        Me.ActiveControl = oPict

    End Sub

End Class

Public Class MyPictureBox

    Inherits PictureBox

    Private zmLevel As Integer = 1

    Private zmPt As Point

    Overloads Property Image() As Image ' we want to hook when client's set the image to reset the zoom level to unzoomed

        Get

            Return MyBase.Image

        End Get

        Set(ByVal value As Image)

            zmLevel = 1 ' reinit

            MyBase.Image = value

        End Set

    End Property

    Protected Overrides Sub OnPaint(ByVal pe As System.Windows.Forms.PaintEventArgs)

        'MyBase.OnPaint(pe) ' don't call baseclass to paint

        If Me.Image IsNot Nothing Then

            Dim loc As Point

            Dim sz As Size

            If zmLevel <> 1 Then

                sz = New Size(Me.Image.Width / zmLevel, Me.Image.Height / zmLevel)

                ' center on zmPt

                loc = New Point(Me.Image.Width * (zmPt.X / Me.ClientRectangle.Width) - sz.Width / 2, _

                                Me.Image.Height * (zmPt.Y / Me.ClientRectangle.Height) - sz.Height / 2) '

            Else

                loc = New Point(0, 0) ' no zoom: we want the entire source picture

                sz = Me.Image.Size

            End If

            Dim rectSrc = New Rectangle(loc, sz)

            ' now draw the rect of the source picture in the entire client rect of MyPictureBox

            pe.Graphics.DrawImage(Me.Image, Me.ClientRectangle, rectSrc, GraphicsUnit.Pixel)

        End If

    End Sub

    Sub PictureBox_MouseWheel(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseWheel

        If Me.zmLevel = 1 Then ' can only anchor when unzoomed

            Me.zmPt = New Point(e.X, e.Y)

        End If

        If e.Delta > 0 Then

            If zmLevel < 20 Then

                zmLevel += 1

            End If

        Else

            If e.Delta < 1 Then

                If zmLevel > 1 Then

                    zmLevel -= 1

                End If

            End If

        End If

        Me.Invalidate() ' queue msg to repaint

    End Sub

End Class

</VB Code>

<C# Code>

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

namespace WindowsFormsApplication1

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

            this.Left = 0;

            this.Top = 0;

            this.Size = Screen.PrimaryScreen.WorkingArea.Size;

            var oPict = new MyPictureBox();

            oPict.Size = this.Size;

            oPict.SizeMode = PictureBoxSizeMode.StretchImage;

            oPict.Image = new Bitmap("d:\\kids.jpg");

            this.Controls.Add(oPict);

            this.ActiveControl = oPict;

        }

    }

}

public class MyPictureBox : PictureBox

{

    private int zmLevel = 1;

    private Point zmPt;

    public MyPictureBox()

    {

        this.MouseWheel += new MouseEventHandler(MyPictureBox_MouseWheel);

    }

    void MyPictureBox_MouseWheel(object sender, MouseEventArgs e)

    {

        if (this.zmLevel == 1)

        {

            this.zmPt = new Point(e.X, e.Y);

        }

        if (e.Delta > 0)

        {

            if (zmLevel < 20)

            {

                zmLevel += 1;

            }

        }

        else

        {

            if (e.Delta < 1)

            {

                if (zmLevel > 1)

                {

                    zmLevel -= 1;

                }

            }

        }

        this.Invalidate();

    }

    new public Image Image // overrides

    {

        get

        {

            return base.Image;

        }

        set

        {

            zmLevel = 1;

            base.Image = value;

        }

    }

    protected override void OnPaint(PaintEventArgs pe)

    {

        //base.OnPaint(pe);

        if (this.Image != null)

        {

            Point loc;

            Size sz;

            if (zmLevel != 1)

            {

                sz = new Size(this.Image.Width / zmLevel, this.Image.Height / zmLevel);

                // center on zmPt. Casts are needed so integer divide doesn't occur (intermediate double result)

                loc = new Point((int)(this.Image.Width * (zmPt.X / (double)this.ClientRectangle.Width)) - sz.Width / 2,

                                 (int)(this.Image.Height * (zmPt.Y / (double)this.ClientRectangle.Height)) - sz.Height / 2);

            }

            else

            {

                loc = new Point(0, 0);

                sz = this.Image.Size;

            }

            Rectangle rectSrc = new Rectangle(loc, sz);

            // now draw the rect of the source picture in the entire client rect of MyPictureBox

            pe.Graphics.DrawImage(this.Image, this.ClientRectangle, rectSrc, GraphicsUnit.Pixel);

        }

    }

}

</C# Code>