How to Draw on Zoomable Image in C# windows Forms

Here is a PictureBox subclass that supports the ability to apply zooming not only to the Image but also to graphics you draw onto its surface.

It includes a SetZoom function to zoom in by scaling both itself and a Matrix.

It also has a ScalePoint function you can use to calculate the unscaled coordinates from the pixel coordinates you receive in the mouse events.

The idea is to use a Transformation Matrix to scale any pixels the Graphics object will draw in the Paint event.

I include a little code for the form for testing.

public partial class ScaledPictureBox : PictureBox
{
    public Matrix ScaleM { get; set; }

    float Zoom { get; set; }
    Size ImgSize { get; set; }

    public ScaledPictureBox()
    {
        InitializeComponent();
        ScaleM = new Matrix();
        SizeMode = PictureBoxSizeMode.Zoom;
    }

    public void InitImage()
    {
        if (Image != null)
        {
            ImgSize = Image.Size;
            Size = ImgSize;
            SetZoom(100);
        }
    }

    public void SetZoom(float zoomfactor)
    {
        if (zoomfactor <= 0) throw new Exception("Zoom must be positive");
        float oldZoom = Zoom;
        Zoom = zoomfactor / 100f;
        ScaleM.Reset();
        ScaleM.Scale(Zoom , Zoom );
        if (ImgSize != Size.Empty) Size = new Size((int)(ImgSize.Width * Zoom), 
                                                   (int)(ImgSize.Height * Zoom));

    }

    public PointF ScalePoint(PointF pt)
    {   return new PointF(pt.X / Zoom , pt.Y / Zoom );     }

}

Here is the code in the Form that does the testing:

public List<PointF> somePoints = new List<PointF>();

private void scaledPictureBox1_MouseClick(object sender, MouseEventArgs e)
{
    somePoints.Add(scaledPictureBox1.ScalePoint(e.Location) );
    scaledPictureBox1.Invalidate();
}

private void scaledPictureBox1_Paint(object sender, PaintEventArgs e)
{
    // here we apply the scaling matrix to the graphics object:
    e.Graphics.MultiplyTransform(scaledPictureBox1.ScaleM);
    using (Pen pen = new Pen(Color.Red, 10f))
    {
        PointF center = new PointF(scaledPictureBox1.Width / 2f, 
                                   scaledPictureBox1.Height / 2f);
        center = scaledPictureBox1.ScalePoint(center);
        foreach (PointF pt in somePoints)
        {
            DrawPoint(e.Graphics, pt, pen);
            e.Graphics.DrawLine(Pens.Yellow, center, pt);
        }
    }
}

public void DrawPoint(Graphics G, PointF pt, Pen pen)
{
    using (SolidBrush brush = new SolidBrush(pen.Color))
    {
        float pw = pen.Width;
        float pr = pw / 2f;
        G.FillEllipse(brush, new RectangleF(pt.X - pr, pt.Y - pr, pw, pw));
    }
}

Here are the results after drawing a few points showing the same points in four different zoom settings; the ScaledPictureBox is obviously placed in an AutoScroll-Panel. The lines show how to use the regular drawing commands..

enter image description hereenter image description hereenter image description hereenter image description here

Leave a Comment