Search code examples
c#imagepicturebox

Display zoomed in part of pictureBox in another pictureBox by hovering cursor c#


I am working on a program that displays the liveView image from a Nikon camera in a pictureBox. I want to be able to hover with the cursor over the image and display a zoomed in area around the cursor in another picturebox. I would also like to add a crosshair instead of mouse pointer. The only solution I have found so far is the following:

zoom an image in a second picturebox following cursor

It does exactly what I want, however I can not get it to work. More specifically, nothing is showing up in picZoom. In the example, images are loaded while in my case, a video stream is shown. That might be the reason why I am not getting it to work. I am relatively new to c#, and did not fully understand the example.

Lets say I have picBox where I receive the video stream. How do I show a portion of picBox around the cursor (let's say a rectangle around the cursor of dimensions x,y) in picZoom with a crosshair as in the example. I do not need to worry about differing dimensions of picBox and picZoom since they will not vary. I also want to be able to vary the degree of zoom by a factor zoomFactor.

If anyone could give me pointers or a solution, it would be greatly appreciated. Also, sorry if my question is poorly formatted, I am new to the forum.

Thank you!

Alexander


Solution

  • I would approach it like this

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace MagnifierExample
    {
        class Magnifier : PictureBox
        {
            public Magnifier()
            {
                Visible = false;
            }
    
            PictureBox source;
            private Point sourcePoint;
            Cursor oldCursor;
    
            public PictureBox Source
            {
                get
                {
                    return source;
                }
                set
                {
                    if (source != null)
                    {
                        source.MouseEnter -= Source_MouseEnter;
                        source.MouseLeave -= Source_MouseLeave;
                        source.MouseMove -= Source_MouseMove;
                        source.Cursor = oldCursor;
                    }
                    source = value;
                    if (source != null)
                    {
                        source.MouseEnter += Source_MouseEnter;
                        source.MouseLeave += Source_MouseLeave;
                        source.MouseMove += Source_MouseMove;
                        oldCursor = source.Cursor;
                        source.Cursor = Cursors.Cross;
                    }
                }
            }
    
            private void Source_MouseEnter(object sender, EventArgs e)
            {
                Visible = true;
                BringToFront();
            }
    
            private void Source_MouseLeave(object sender, EventArgs e)
            {
                Visible = false;
            }
    
            private void Source_MouseMove(object sender, MouseEventArgs e)
            {
                sourcePoint = e.Location;
                Location = new Point(source.Location.X + e.X - Width / 2, source.Location.Y + e.Y - Height / 2);
                Invalidate();
            }
    
            protected override void WndProc(ref Message m)
            {
                const int WM_NCHITTEST = 0x0084;
                const int HTTRANSPARENT = (-1);
    
                if (!DesignMode && m.Msg == WM_NCHITTEST)
                {
                    m.Result = (IntPtr)HTTRANSPARENT;
                }
                else
                {
                    base.WndProc(ref m);
                }
            }
    
            protected override void OnPaint(PaintEventArgs pe)
            {
                if (!DesignMode && Source != null && Source.Image != null)
                {
                    Rectangle destRect = new Rectangle(0, 0, Width, Height);
                    // IMPORTANT: This calculation will depend on the SizeMode of the source and the amount you want to zoom.
                    // This does 2x zoom and works with PictureBoxSizeMode.Normal:
                    Rectangle srcRect = new Rectangle(sourcePoint.X - Width / 4, sourcePoint.Y - Height / 4, Width / 2, Height / 2);
                    pe.Graphics.DrawImage(Source.Image, destRect, srcRect, GraphicsUnit.Pixel);
                }
                else
                {
                    base.OnPaint(pe);
                }
            }
        }
    }
    

    To hook it up all you have to do is add a Magnifier to your form, give it a size, and set its Source to the PictureBox you want it to magnify.

       this.magnifier1.Source = this.pictureBox1;
    

    I used the approach in this answer to ignore messages from the magnifier window.

    Importantly, I only coded up the zoom math for the PictureBoxSizeMode.Normal SizeMode of the source PictureBox. But I think this is a pretty good start.

    Not 100% sure what you wanted for crosshairs, but this uses the built-in crosshair cursor.