zl程序教程

您现在的位置是:首页 >  .Net

当前栏目

C#笔记 picturebox功能实现(滚动放大,拖动)

2023-02-18 16:27:17 时间

代码链接

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);
        }