Problem when trying to create a minimap using imagebox

Started by t831011, October 06, 2017, 09:07:13 AM

Previous topic - Next topic

t831011

Greeting from Taiwan. Thanks for the wonderful imagebox control. It saves me, a c# beginer, a hell lot of time making an image viewer. 


I want to make a minimap feature in a image viewer. Which show the whole image and draw a rectangle on where the section of main imagebox is on the screen now.
codes here
//in designer
this.minimap.AllowZoom = false;
this.minimap.AutoPan = false;
this.minimap.SizeMode = Cyotek.Windows.Forms.ImageBoxSizeMode.Fit;
//get the region presented in main screen
private void imageBox_MouseMove(object sender, MouseEventArgs e)
        {
            minimap_region.X = -this.imageBox.AutoScrollPosition.X;
            minimap_region.Y = -this.imageBox.AutoScrollPosition.Y;
            minimap_region.Width = this.imageBox.GetImageViewPort().Width ;
            minimap_region.Height = this.imageBox.GetImageViewPort().Height;
            minimap.Invalidate();
           
        }
//paint rectangle in minimap
private void minimap_Paint(object sender, PaintEventArgs e)
        {
            //Rectangle temp = minimap.GetScaledRectangle(minimap_region);
            Pen blackPen = new Pen(Color.Aquamarine, 3);
            Point x = new Point(minimap_region.X, minimap_region.Y);
            PointF trans_x = minimap.GetOffsetPoint(x);
            RectangleF temp= new RectangleF();
            temp.Width = minimap_region.Width / (float)imageBox.ZoomFactor * (float)minimap.ZoomFactor;
            temp.Height = minimap_region.Height / (float)imageBox.ZoomFactor * (float)minimap.ZoomFactor;
            temp.X = trans_x.X/ (float)imageBox.ZoomFactor;
            temp.Y = trans_x.Y / (float)imageBox.ZoomFactor ;
            e.Graphics.DrawRectangle(blackPen, Rectangle.Round(temp));
        }
//synchronize the image with main image box
private void imageBox_ImageChanged(object sender, EventArgs e)
        {
            this.minimap.Image = this.imageBox.Image;
        }

However I find out that it only works perfect when zoom scale=100%
When the zoomscale change ,the left top point I get wasn't quite right.
the second image attached displays the problem.

Any help will be so appreciated.

Richard Moss

#1
Hello,

Welcome to the forums and I'm glad you're finding the control useful. I've created a new sample project which demonstrates what you're trying to achieve, you can download it from the link below.

This is the code I came up with the generate the rectangle - you can condense it quite a bit, but I wanted to show each step individually.

      // define the initial size. We'll take the current
      // size from the source imagebox's image viewport
      viewSize = zoomImageBox.GetImageViewPort().Size;
      w = viewSize.Width;
      h = viewSize.Height;

      // next we need to scale the size to match the zoomfactor of the source imagebox
      w /= zoomImageBox.ZoomFactor;
      h /= zoomImageBox.ZoomFactor;

      // next we scale the size again - this time by the zoomfactor the destination imagebox
      w *= miniMapImageBox.ZoomFactor;
      h *= miniMapImageBox.ZoomFactor;

      // with the size define, we can now turn out attention to the origin
      // first, we get the current auto scroll offsets, and reverse them
      // to give us our origin
      x = -zoomImageBox.AutoScrollPosition.X;
      y = -zoomImageBox.AutoScrollPosition.Y;

      // next, we need to scale that to account for the source imagebox zoom
      x /= zoomImageBox.ZoomFactor;
      y /= zoomImageBox.ZoomFactor;

      // as with the size, we need to scale again to account for the destination imagebox
      x *= miniMapImageBox.ZoomFactor;
      y *= miniMapImageBox.ZoomFactor;

      // and for our final action, we need to offset the origin to account
      // for where the destination imagebox is painting the output image
      location = miniMapImageBox.GetImageViewPort().Location;
      x += location.X;
      y += location.Y;

      // all done, create the final rectangle for painting
      proposedView = new Rectangle(Convert.ToInt32(x), Convert.ToInt32(y), Convert.ToInt32(w), Convert.ToInt32(h));


Note that I identified a performance issue with trying to do this, as forced repainting of the minimap control has a nasty impact. I mitigated most of this in two ways:


  • For the minimap imagebox, I generate a correctly sized thumbnail graphic and paint that, instead of scaling the image every single time
  • When calculating the new rectangle I compare it with the old, and if they are the same then I save forcing painting then too (also note I just went with an integer Rectangle rather than floating point.

All this is in the sample - I hope it helps!

Regards;
Richard Moss

Edit: Noticed some typo's in the commented source - oops. Let me know if anything isn't clear.
Read "Before You Post" before posting (https://forums.cyotek.com/cyotek-webcopy/before-you-post/). Do not send me private messages. Do not expect instant replies.

All responses are hand crafted. No AI involved. Possibly no I either.

t831011

Thanks, the problem is solved after spending some time studying the demo project.
Apparently I missed the "offset the origin to account "part.