AlexanderEngman
AlexanderEngman

Reputation: 25

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

Upvotes: 0

Views: 974

Answers (2)

Silver Huynh
Silver Huynh

Reputation: 1

With some adjust, you can use @Wyck 's code with PictureBoxSizeMode.StretchImage

protected override void OnPaint(PaintEventArgs pe)
    {
        if (!DesignMode && Source != null && Source.Image != null)
        {
            Rectangle destRect = new (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:
            float stretch_X = source.Image.Width  / (float)source.Width;
            float stretch_Y = source.Image.Height / (float)source.Height;
            Rectangle srcRect = new ((int)(sourcePoint.X * stretch_X) - Width / 4, (int)(sourcePoint.Y * stretch_Y) - Height / 4, Width / 2, Height / 2);
            pe.Graphics.DrawImage(source.Image, destRect, srcRect, GraphicsUnit.Pixel);
        }
        else
        {
            base.OnPaint(pe);
        }
    }

Upvotes: 0

Wyck
Wyck

Reputation: 11760

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.

Upvotes: 1

Related Questions