1. 程式人生 > 其它 >C#筆記 picturebox功能實現(滾動放大,拖動)

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