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. 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.