C#笔记 picturebox功能实现(滚动放大,拖动)
1. picturebox上的坐标与原图中坐标的转换
(1) 由于图片的长宽比例和picturebox的长宽比例不同,所以图片不想拉伸的话,左右或者上下会有留白。将picturebox的sizemode设为zoom,计算留白距离。
默认情况下,在 Normal 模式中,Image 置于 PictureBox 的左上角,凡是因过大而不适合 PictureBox 的任何图像部分都将被剪裁掉。
PictureBoxSizeMode.StretchImage:使用 StretchImage 值会使图像拉伸或收缩,以便适合 PictureBox。
PictureBoxSizeMode.AutoSize:使用 AutoSize 值会使控件调整大小,以便总是适合图像的大小。
PictureBoxSizeMode.CenterImage:使用 CenterImage 值会使图像居于工作区的中心。
PictureBoxSizeMode.Zoom:使用 Zoom 的值可以使图像被拉伸或收缩以适应 PictureBox;但是仍然保持原始纵横比。
(2)picturebox的坐标都要先减去留白距离,根据比例缩放后再加上显示区域的偏移量
private OpenCvSharp.Point GetImagePoint(System.Drawing.Point p) { OpenCvSharp.Point imagePoint; int width = showImage.Width; int height = showImage.Height; int w = Width; int h = Height; double ratio; if (w_empty>0) { ratio = h * 1.0 / height; if (p.X < w_empty || p.X > w - w_empty) imagePoint.X = -1; else imagePoint.X = LUCol + (int)((p.X - w_empty) * 1.0 / ratio); imagePoint.Y = LURow + (int)(p.Y * 1.0 / ratio); } else { ratio = w * 1.0 / width; imagePoint.X = LUCol + (int)(p.X * 1.0 / ratio); if (p.Y < h_empty || p.Y > h - h_empty) imagePoint.Y = -1; else imagePoint.Y = LURow + (int)((p.Y - h_empty) * 1.0 / ratio); } return imagePoint; }
2. 滚动放大
滚动放大时,当前坐标为放大中心。
滚动放大后,显示部分占原图的比例会减小,显示部分左上角点在原图的坐标也会移动。
从原图上裁出显示部分 new Rect(LUCol, LURow, RealWidth, RealHeight)
public void pictureBox_MouseWheel(object sender, MouseEventArgs e) { if (Image == null) return; if (e.Delta > 0) { RealWidth /= 2; RealHeight /= 2; LUCol = CurrentPoint.X - (int)RealWidth / 2; LURow = CurrentPoint.Y - (int)RealHeight / 2; } else { RealWidth *= 2; RealHeight *= 2; LUCol = CurrentPoint.X - (int)RealWidth / 2; LURow = CurrentPoint.Y - (int)RealHeight / 2; } judgeBounds(); showImage = new Mat(srcImage, new Rect(LUCol, LURow, RealWidth, RealHeight)); }
3. 拖动图片
public void pictureBox_MouseMove(object sender, MouseEventArgs e) { ... if (e.Button == MouseButtons.Left) { EndPoint = GetImagePoint(e.Location); int offsetX = EndPoint.X - CurrentPoint.X; int offsetY = EndPoint.Y - CurrentPoint.Y; LURow -= offsetY; LUCol -= offsetX; judgeBounds(); showImage = new Mat(srcImage, new Rect(LUCol, LURow, RealWidth, RealHeight)); } ... }
4. 图片放大后呈现像素块
重写paint,将插值方法改为最近邻插值
public void pictureBox_Paint(object sender, PaintEventArgs e) { if (Image == null) return; var state = e.Graphics.Save(); e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; e.Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; e.Graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Half; e.Graphics.Clear(BackColor); if(h_empty!=0) e.Graphics.DrawImage(Image, 0, h_empty, Width, Height-2*h_empty); else e.Graphics.DrawImage(Image, w_empty, 0, Width - 2*w_empty, Height); e.Graphics.Restore(state); }