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>


 

Comments (18)

  1. Alex Sosa says:

    OK, this is one request for the VFP code to do the same.  I look forward to your explanation on how to do the interop.  Thanks.

    Alex

  2. Victor Espinoza says:

    I second Alex’s request …

    Please give us a VFP version.

    Thanks in advance.

  3. Luis Navas says:

    One more request for the VFP version

  4. Richard Kelleher says:

    I suspect that it is mostly to limit or alter the warrenty and support options that are displayed.  If an average home user saw the warrenty/support options offered to businesses they might actually be shocked (by the prices mostly) but would certainly be confused.

  5. Jerry O says:

    And another request for the VFP version.

  6. One more request for a VFP version.

  7. Babu says:

    I am really grateful for your kindness, wish you all success:-)

  8. Ebro says:

    Great work. Thank you for sharing. How can i move using MouseMove event? or how to add a horizontal and vertical scroll bar?

    Thank you again

  9. Bhavik Patel says:

    Described in very Simplified Manner. Should i reproduce it on my blog http://www.dotnetspan.com ?