Search code examples
c#winformsgraphicszooming

Graphics getting drawn incorrectly in c# windows form


How do I make sure my graphics are drawn in the right position? I have a windows form project where the user draws lines on an Image in a pictureBox (on top of a panel). When the picture box is in default zoom the lines are drawn correctly, and they respond correctly to the Image being ragged around. However when I try to draw on the image while zoomed in/out the position of line is offset (up and to left when zoomed out, down and right when zoomed in). The pictureBox and panel are anchored on all four sides and not docked. I tried using the TranslateTransform( dx, dy ) method but it didn't work. I also tried getting rid of my CenterBox() method. How do i proceed?

Here is code for zooming:

private void trackBar1_Scroll(object sender, EventArgs e)  // zoom scale
{
    zoom = (float)(0.25 + 0.25 * (trackBar1.Value - 1));
    if (trackBar1.Value > 0)
    {
        pictureBox1.Image = PictureBoxZoom(imgOriginal, new Size(trackBar1.Value, trackBar1.Value));
    }

}

public Image PictureBoxZoom(Image img, Size size) //creates zoomed in clone of user image
{
    sizeNewx = (Int32) (img.Width * zoom);
    sizeNewy = (Int32) (img.Height * zoom);
    Bitmap bm = new Bitmap(img, sizeNewx,sizeNewy);
    Graphics grap = Graphics.FromImage(bm);
    grap.InterpolationMode = InterpolationMode.HighQualityBicubic;
    CenterBox(pictureBox1, bm);
    return bm;
}

private void CenterBox(PictureBox picBox, Bitmap pic)
{
    picBox.Image = pic;
    picBox.Location = new Point((picBox.Parent.ClientSize.Width / 2) - (pic.Width / 2),
                       (picBox.Parent.ClientSize.Height / 2) - (pic.Height / 2));
    picBox.Refresh();
} 

Here is how graphics are drawn and zoomed:

private Stack<Line> lines = new Stack<Line>();

private void pictureBox1_MouseDown(object sender, MouseEventArgs e) //click in box
{
    var mouseEventArgs2 = e as MouseEventArgs;

    if (e.Button == MouseButtons.Left)
    {        
        lines.Push(new Line { Start = mouseEventArgs2.Location });
    }
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{       
    if (lines.Count > 0 && e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        lines.Peek().End = e.Location;
        pictureBox1.Invalidate();
    }
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.ScaleTransform(zoom, zoom);

    foreach (var line in lines)
    {
        Pen magenta = new Pen(Color.Magenta, 2);
        e.Graphics.DrawLine(magenta, line.Start, line.End);
    }
}

Solution

  • Ok found the issue. The problem is that the points you get in mouse move and mouse end are basically scaled, cause image is scaled and then in paint you scale them again. So you need to un scale them before paint:

    private void pictureBox1_MouseDown(object sender, MouseEventArgs e) //click in box
    {
        var mouseEventArgs2 = e as MouseEventArgs;
    
        if (e.Button == MouseButtons.Left)
        {        
            Point[] pnts = new Point[ 1 ];
            Matrix scaleMatrix = new Matrix( 1 / zoom, 0, 0, 1 / zoom, 0, 0 ); //un scale
            pnts[0]= mouseEventArgs2.Location;
            scaleMatrix.TransformPoints( pnts );
    
            lines.Push(new Line { Start = pnts[0] });
        }
    }
    
    private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
    {       
        if (lines.Count > 0 && e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            Point[] pnts = new Point[ 1 ];
            Matrix scaleMatrix = new Matrix( 1 / zoom, 0, 0, 1 / zoom, 0, 0 ); //un scale
            pnts[0]= e.Location;
            scaleMatrix.TransformPoints( pnts );
    
            lines.Peek().End = pnts[0];
            pictureBox1.Invalidate();
        }
     }