gpt4 book ai didi

.net - 使用 Windows 窗体缩放大图片

转载 作者:行者123 更新时间:2023-12-04 19:16:23 25 4
gpt4 key购买 nike

我必须在 Windows 窗体应用程序中显示大图像。用户应该有可能标记图像的一个区域,然后应该像下面所示的示例那样进行缩放。

Zoom illustration

如前所述,图像会很大,所以我的问题是:是否可以使用默认值 PictureBox 来实现这一点?控制还是我更好地使用第 3 方控制?如果是这样,请推荐一个包含提供这些功能的控件的库。

正如所 promise 的,这是我所做的控制的来源:

/// <summary>
/// A panel used to display an image and zoom into areas of the displayed
/// image.
/// </summary>
public sealed class PictureZoomPanel : Panel
{
// The image to dispay, set in the Image property
private Image _image;
// The current zoom factor
private float _zoom = 1;
// The zoom rectangle on the panel.
private Rectangle _panelZoomRect;
// _panelZoomRect on the actual image
private Rectangle? _imageZoomRect;
// Used in the mouse event handlers
private bool _mouseDown;
// The pen used to draw the zoom rectangle
private Pen _zoomPen;

/// <summary>
/// Create a new <see cref="PictureZoomPanel"/>
/// </summary>
public PictureZoomPanel()
{
// To prevent flickering
DoubleBuffered = true;
// To make resizing smoother
ResizeRedraw = true;
// Set default zoom pen
ZoomPen = null;
}

/// <summary>
/// The image to be displayed
/// </summary>
[Category("Appearance"),
Description("The image to be displayed.")]
public Image Image
{
get { return _image; }
set
{
_image = value;
ZoomToFit();
}
}

/// <summary>
/// The pen used to draw the zoom rectangle.
/// </summary>
[Category("Appearance"),
Description("The pen used to draw the zoom rectangle.")]
public Pen ZoomPen
{
get { return _zoomPen; }
set {
_zoomPen = value ?? new Pen(Color.Green, 2);
}
}

/// <summary>
/// Sets the zoom to a value where the whole image is visible.
/// </summary>
public void ZoomToFit()
{
_imageZoomRect = null;
_mouseDown = false;
_zoom = 1;

// If no image is present, there is nothing further to do
if (_image == null)
return;

var widthZoom = (float) Width / _image.Width;
var heightZoom = (float) Height / _image.Height;

// Make sure the whole image is visible
_zoom = widthZoom < heightZoom ? widthZoom : heightZoom;

// Force redraw
Invalidate();
}

protected override void OnMouseDown(MouseEventArgs e)
{
if (_image == null)
return;

_mouseDown = true;
_panelZoomRect = new Rectangle(e.X, e.Y, 0, 0);
}

protected override void OnMouseUp(MouseEventArgs e)
{
if (_image == null || !_mouseDown)
return;

_mouseDown = false;

// Without this, doubling clicking the control would cause zoom
if (_panelZoomRect.Height == 0 || _panelZoomRect.Width == 0)
return;

// Tell the paint method to zoom
_imageZoomRect = CalculateImageZoomRectangle();
_zoom = RecalculateZoom();
}

protected override void OnMouseMove(MouseEventArgs e)
{
if (_image == null)
return;

// This makes sure that the left mouse button is pressed.
if (e.Button == MouseButtons.Left)
{
// Draws the rectangle as the mouse moves
_panelZoomRect = new Rectangle(
_panelZoomRect.Left,
_panelZoomRect.Top,
e.X - _panelZoomRect.Left,
e.Y - _panelZoomRect.Top);
}

// Force redraw to make sure the zoomRegion is painted
Invalidate();
}

private Rectangle CalculateImageZoomRectangle()
{
// Calculate all the coordinates to required to transform
var topLeft = new Point(_panelZoomRect.X,
_panelZoomRect.Y);
var topRight = new Point(_panelZoomRect.X + _panelZoomRect.Width,
_panelZoomRect.Y);
var bottomLeft = new Point(_panelZoomRect.X,
_panelZoomRect.Y - _panelZoomRect.Height);
var bottomRight = new Point(_panelZoomRect.X + _panelZoomRect.Height,
_panelZoomRect.Y - _panelZoomRect.Height);

var points = new [] { topLeft, topRight, bottomLeft, bottomRight };

// Converts the points from panel to image position
var mx = new Matrix(_zoom, 0, 0, _zoom, 0, 0);
mx.Invert();
mx.TransformPoints(points);

var rectangleWidth = points[1].X - points[0].X;
var rectangleHeight = points[0].Y - points[2].Y;

// _imageZoom != null, means that we are zooming in on an
// already zoomed in image. We must add the original values
// to zoom in deeper
return _imageZoomRect == null
? new Rectangle(points[0].X,
points[0].Y,
rectangleWidth,
rectangleHeight)
: new Rectangle(points[0].X + _imageZoomRect.Value.X,
points[0].Y + _imageZoomRect.Value.Y,
rectangleWidth,
rectangleHeight);
}

private float RecalculateZoom()
{
if (!_imageZoomRect.HasValue)
return _zoom;

var widthZoom = (float)Width / _imageZoomRect.Value.Width;
var heightZoom = (float)Height / _imageZoomRect.Value.Height;

return widthZoom < heightZoom ? widthZoom : heightZoom;
}

protected override void OnPaint(PaintEventArgs e)
{
if (_image == null)
{
OnPaintBackground(e);
return;
}

e.Graphics.Transform = new Matrix(_zoom, 0, 0, _zoom, 0, 0);

// Turn of interpolation when zoomed
e.Graphics.InterpolationMode = _imageZoomRect != null
? InterpolationMode.NearestNeighbor
: InterpolationMode.Default;

DrawImage(e);

if (_mouseDown)
DrawZoomRectangle(e);

base.OnPaint(e);
}

private void DrawImage(PaintEventArgs e)
{
var destRec = !_imageZoomRect.HasValue
? new Rectangle(0, 0, _image.Width, _image.Height)
: new Rectangle(0, 0, _imageZoomRect.Value.Width,
_imageZoomRect.Value.Height);

var sourceRec = !_imageZoomRect.HasValue
? new Rectangle(0, 0, _image.Width, _image.Height)
: _imageZoomRect.Value;

e.Graphics.DrawImage(_image, destRec,
sourceRec.Location.X, sourceRec.Location.Y,
sourceRec.Width, sourceRec.Height,
GraphicsUnit.Pixel);
}

private void DrawZoomRectangle(PaintEventArgs e)
{
e.Graphics.Transform = new Matrix();
e.Graphics.DrawRectangle(_zoomPen, _panelZoomRect);
}
}

最佳答案

您可以通过平移图形对象来实现缩放。我认为不是使用 PictureBox,而是使用 double buffered Panel是更好的选择工具。

您处理绘制事件,并从那里调整它的矩阵表示。此外,您需要调整 AutoScrollMinSize 属性以使滚动条代表缩放图像的正确范围。

快速示例:

Bitmap bmp = new Bitmap(@"c:\myimage.png");
int zoom = 2;

private void Form1_Load(object sender, EventArgs e) {
panel1.AutoScrollMinSize = new Size(bmp.Width * zoom, bmp.Height * zoom);
}

private void panel1_Paint(object sender, PaintEventArgs e) {
using (Matrix mx = new Matrix(zoom, 0, 0, zoom, 0, 0)) {
mx.Translate(panel1.AutoScrollPosition.X / zoom, panel1.AutoScrollPosition.Y / zoom);
e.Graphics.Transform = mx;
e.Graphics.DrawImage(bmp, new Point(0, 0));
}
}

此方法用于跟踪缩放图像的鼠标移动:
protected Point BacktrackMouse(MouseEventArgs e)
{
Matrix mx = new Matrix(_zoom, 0, 0, _zoom, 0, 0);
mx.Translate(this.AutoScrollPosition.X * (1.0f / zoom),
this.AutoScrollPosition.Y * (1.0f / zoom));
mx.Invert();
Point[] p = new Point[] { new Point(e.X, e.Y) };
mx.TransformPoints(p);
return p[0];
}

关于.net - 使用 Windows 窗体缩放大图片,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9062206/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com