Have C# forms application with PictureBox embedded in Panel, to take advantage of Panel AutoScroll as suggested in other posts when image and thus PictureBox need to be scrolled horizontally or vertically. Want to zoom the image and recompute AutoScrollPosition to keep same Point visible after zooming. Can double size of PictureBox, then recopy source image, accomplishing zoom. But AutoScrollPosition remains unchanged, thus what was visible before zoom has moved off screen. How to recompute AutoScrollPosition to keep image focus after zoom?
问题:
回答1:
There are three typical types of zooming:
- zoom into the center, triggered by zoom buttons
- zoom into the mouse position, triggered by clicking or scroll-wheeling
- zoom into a rectangle, by drawing a rectangle
I assume the typical setup: A PictureBox
set to SizeMode=Zoom
nested in a Panel
with AutoScroll=true
and zooming that takes care to keep the aspect ratios of Image
and PictureBox
equal.
Let's start by introducing terminology:
- There is an
Image
we call bitmap and - it is displayed by a
PictureBox
; let's call it canvas.. - .. which is nested in a
Panel
we call frame
User-friendly zooming needs a fixed point, that is a point that shall stay put.
For 1) it is the center of the frame, for 2) it is the mouse location and for 3) it is the center of the rectangle.
Before zooming we calculate the old zoom ratio, the fixed point in the frame, the fixed point in the canvas and finally the fixed point in the bitmap.
After zoming we calculate the new zoom ratio and the new fixed point in the canvas. Finally we use it to move the canvas to bring the fixed canvas point to the fixed frame point.
Here is an example for zooming into the (current) center; it is a common click event for two buttons and it only doubles and halves the zoom ratio.
Much finer grained factors are of course simple to implement; even better is a fixed list of zoom levels, like Photoshop has!
private void zoom_Click(object sender, EventArgs e)
{
PictureBox canvas = pictureBox1;
Panel frame = panel1;
// Set new zoom level, depending on the button
float zoom = sender == btn_ZoomIn ? 2f : 0.5f;
// calculate old ratio:
float ratio = 1f * canvas.ClientSize.Width / canvas.Image.Width;
// calculate frame fixed pixel:
Point fFix = new Point( frame.Width / 2, frame.Height / 2);
// calculate the canvas fixed pixel:
Point cFix = new Point(-canvas.Left + fFix.X, -canvas.Top + fFix.Y );
// calculate the bitmap fixed pixel:
Point iFix = new Point((int)(cFix.X / ratio),(int)( cFix.Y / ratio));
// do the zoom
canvas.Size = new Size( (int)(canvas.Width * zoom), (int)(canvas.Height * zoom) );
// calculate new ratio:
float ratio2 = 1f * canvas.ClientSize.Width / canvas.Image.Width;
// calculate the new canvas fixed pixel:
Point cFix2 = new Point((int)(iFix.X * ratio2),(int)( iFix.Y * ratio2));
// move the canvas:
canvas.Location = new Point(-cFix2.X + fFix.X, -cFix2.Y + fFix.Y);
}
Note that while one can try to restore the relative AutoScrollValues
this is not only hard, because their values are a little quirky but it is also won't be adaptable to the other zoom types.