• C# winform实现图片裁剪效果


    准备在winform程序里做一个图片剪切功能,一个矩形框 有手柄 可进行调整 对图片进行裁剪。 就像ACDSee那样:

     仔细想了下对图片进行裁剪  裁剪这个过程完全不用我们费心
    因为.Net里为我们提供了drawImage这个万能的函数了,msdn里对他的大概解释是 把原图指定矩形区域的像素“画”到目标Image的指定矩形区域

    来看看:

    1. //图像裁剪
    2. public Bitmap GetPartOfImage(Bitmap sourceImg, int width, int height, int offsetX, int offsetY)
    3. {
    4.     Bitmap sourceBitmap = sourceImg;
    5.  
    6.     Bitmap resultBitmap = new Bitmap(width, height);
    7.     using (Graphics g = Graphics.FromImage(resultBitmap))
    8.     {
    9.         Rectangle resultRectangle = new Rectangle(0, 0, width, height);
    10.         Rectangle sourceRectangle = new Rectangle(0 + offsetX, 0 + offsetY, width, height);
    11.  
    12.         //万能的drawImage函数,七七八八的参数非常多 普通的图片拉伸 放大 等效果都可以用它来做到。
    13.         //第一个参数:原图(被裁剪的图)
    14.         //第二个参数:目标Image(裁剪后的图)
    15.         //第三个参数:原图被裁剪的区域
    16.         //第四个参数:单位(当然是像素啦)
    17.         g.DrawImage(sourceBitmap, resultRectangle, sourceRectangle, GraphicsUnit.Pixel);
    18.     }
    19.     return resultBitmap;
    20. }

    所以说裁剪的过程不需要费心 我们只需要实现那个矩形调整的效果就ok啦。
    简而言之效果就是通过鼠标对一个矩形框进行:
    在四个角的不同位置进行光标变换、 拖拽、在相应的位置固定某一个边 对矩形进行 上 下 左 右 等八个方向的拉伸。
    好解释完了 懂否?调整好后把矩形框的 宽 高 坐标 传到上面的函数进行处理就ok啦。
    好 核心的东西全解释完了 该出手了。

    为了做得比较通用本人采用了继承自定义控件的方式,因为我是这么想的:
    第一 继承了System.Windows.Forms.Control类后OnMouseOver 拖拽那些事件 都可以被天然的捕捉到然后交由自己定义的代码来处理
    第二 你需要做的处理就是 通过不同的方式对控件的长宽进行调整 并复写Control类的OnPaint来进行实时的显示
    第三 所有的东东都被封装到这个继承的控件里了 所有鼠标事件都与外界无关,这样以后使用更方便不用代码调来调去的 。
    只需要在控件里公开一个获取选择区域的方法就可以了

    首先是拖拽的效果,他的过程是这样的:在鼠标左键按下时记录当前控件相对于父容器的坐标 也就是this.location属性 还有鼠标的坐标,
    鼠标移动时检查如果左键按下 则测算出当前鼠标位置跟原来记录的偏移量, 然后对原来记录的location进行偏移 赋值给this.location 直至鼠标弹起 完成一次拖拽的效果
    鼠标左键重新按下并移动的时候重复上述过程:

    1. private Point m_MousePoint;
    2. private Point m_LastPoint;
    3. protected override void OnMouseDown(MouseEventArgs e)
    4. {
    5.     base.OnMouseDown(e);
    6.     this.m_LastPoint = this.Location;
    7.     this.m_MousePoint = this.PointToScreen(e.Location);          
    8. }
    9.  
    10. protected override void OnMouseMove(MouseEventArgs e)
    11. {
    12.     base.OnMouseMove(e);
    13.     if (e.Button == MouseButtons.Left)
    14.     {
    15.         Point t = this.PointToScreen(e.Location);
    16.         Point l = this.m_LastPoint;
    17.         l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
    18.         this.Location = l;
    19.     }
    20. }

    矩形框上下左右拉伸不用多说了吧 原理嘛大家想想就明白了,onPaint时候矩形的绘制嘛自然是沿着控件的边框绘制就可以了噻
    onMouseMove的时候矩形边框的判断嘛自然是根据控件的宽度跟高度加上location来的噻 ,在边框按下鼠标拖拽相应调整控件的宽高跟坐标就行了
    好下面是该自定义控件的关键部分代码 包括矩形框手柄以及调整效果:

    1. protected override void OnMouseMove(MouseEventArgs e)
    2.         {
    3.  
    4.             base.OnMouseMove(e);
    5.  
    6.             if (arow != arrowType.none)
    7.             {
    8.                 reSize(e);
    9.                 return;
    10.             }
    11.  
    12.             if (e.Y <= recArrow[4].Bottom && e.Y >= recArrow[4].Top && e.X >= recArrow[4].Left && e.X <= recArrow[4].Right)//左上
    13.                 Cursor = Cursors.SizeNWSE;
    14.             else if (e.Y <= recArrow[5].Bottom && e.Y >= recArrow[5].Top && e.X >= recArrow[5].Left && e.X <= recArrow[5].Right)//左下
    15.                 Cursor = Cursors.SizeNESW;
    16.             else if (e.Y <= recArrow[6].Bottom && e.Y >= recArrow[6].Top && e.X >= recArrow[6].Left && e.X <= recArrow[6].Right)//右上
    17.                 Cursor = Cursors.SizeNESW;
    18.             else if (e.Y <= recArrow[7].Bottom && e.Y >= recArrow[7].Top && e.X >= recArrow[7].Left && e.X <= recArrow[7].Right)//右下
    19.                 Cursor = Cursors.SizeNWSE;
    20.             else if (e.Y <= recArrow[0].Bottom && e.Y >= recArrow[0].Top)//
    21.                 Cursor = Cursors.SizeNS;
    22.             else if (e.Y <= recArrow[1].Bottom && e.Y >= recArrow[1].Top)//
    23.                 Cursor = Cursors.SizeNS;
    24.             else if (e.X >= recArrow[2].Left && e.X <= recArrow[2].Right)//
    25.                 Cursor = Cursors.SizeWE;
    26.             else if (e.X >= recArrow[3].Left && e.X <= recArrow[3].Right)//
    27.                 Cursor = Cursors.SizeWE;
    28.             else
    29.                 Cursor = Cursors.SizeAll;
    30.  
    31.  
    32.             if (e.Button == MouseButtons.Left)
    33.             {
    34.                 Point t = this.PointToScreen(e.Location);
    35.                 Point l = this.m_LastPoint;
    36.  
    37.                 if (e.Y <= recArrow[4].Bottom && e.Y >= recArrow[4].Top && e.X >= recArrow[4].Left && e.X <= recArrow[4].Right)//左上
    38.                     arow = arrowType.leftUp;
    39.                 else if (e.Y <= recArrow[5].Bottom && e.Y >= recArrow[5].Top && e.X >= recArrow[5].Left && e.X <= recArrow[5].Right)//左下
    40.                     arow = arrowType.leftDown;
    41.                 else if (e.Y <= recArrow[6].Bottom && e.Y >= recArrow[6].Top && e.X >= recArrow[6].Left && e.X <= recArrow[6].Right)//右上
    42.                     arow = arrowType.rightUp;
    43.                 else if (e.Y <= recArrow[7].Bottom && e.Y >= recArrow[7].Top && e.X >= recArrow[7].Left && e.X <= recArrow[7].Right)//右下
    44.                     arow = arrowType.rightDown;
    45.                 else if (e.Y <= recArrow[0].Bottom && e.Y >= recArrow[0].Top)//
    46.                     arow = arrowType.up;
    47.                 else if (e.Y <= recArrow[1].Bottom && e.Y >= recArrow[1].Top)//
    48.                     arow = arrowType.down;
    49.                 else if (e.X >= recArrow[2].Left && e.X <= recArrow[2].Right)//
    50.                     arow = arrowType.left;
    51.                 else if (e.X >= recArrow[3].Left && e.X <= recArrow[3].Right)//
    52.                     arow = arrowType.right;
    53.                 else
    54.                     arow = arrowType.none;
    55.  
    56.  
    57.                 l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
    58.                 if (arow != arrowType.none)
    59.                     reSize(e);
    60.                 else
    61.                 {
    62.                     this.Location = l;
    63.                     Refresh();//这句很重要立即重绘 不然拖动到时候会出现卡卡 的现象 ,找了半天原因
    64.                 }
    65.             }
    66.         }
    67.  
    68.         public void reSize(MouseEventArgs e)
    69.         {
    70.             Point t = this.PointToScreen(e.Location);
    71.             Point l = this.m_LastPoint;
    72.  
    73.             l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
    74.  
    75.             switch (arow)
    76.             {
    77.                 case arrowType.up:
    78.                     {
    79.                         this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
    80.                         this.Location = new Point(m_LastPoint.X, l.Y);
    81.                         break;
    82.                     }
    83.                 case arrowType.down:
    84.                     {
    85.                         this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
    86.                         break;
    87.                     }
    88.                 case arrowType.left:
    89.                     {
    90.                         this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
    91.                         this.Location = new Point(l.X, m_LastPoint.Y);
    92.                         break;
    93.                     }
    94.                 case arrowType.right:
    95.                     {
    96.                         this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
    97.                         break;
    98.                     }
    99.                 case arrowType.leftUp:
    100.                     {
    101.                         this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
    102.                         this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
    103.                         this.Location = new Point(l.X, l.Y);
    104.                         break;
    105.                     }
    106.                 case arrowType.leftDown:
    107.                     {
    108.                         this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
    109.                         this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
    110.                         this.Location = new Point(l.X, m_LastPoint.Y);
    111.                         break;
    112.                     }
    113.                 case arrowType.rightUp:
    114.                     {
    115.                         this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
    116.                         this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
    117.                         this.Location = new Point(m_LastPoint.X, l.Y);
    118.                         break;
    119.                     }
    120.                 case arrowType.rightDown:
    121.                     {
    122.                         this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
    123.                         this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
    124.                         break;
    125.                     }
    126.             }
    127.             this.Refresh();
    128.         }
    129.  
    130.   
    131.  
    132.         public enum arrowType
    133.         {
    134.             up,down,left,right,leftUp,leftDown,rightUp,rightDown,none
    135.         }
    136.  
    137.         public arrowType arow=arrowType.none;
    138.  
    139.         Rectangle []recArrow=new Rectangle[8];//8个手柄
    140.  
    141.         public Rectangle area ;//选择区域
    142.         public readonly int blank=8;//边距
    143.         protected override void OnPaint(PaintEventArgs e)
    144.         {
    145.             int side = 6;//手柄矩形的边长
    146.              
    147.             recArrow[0] = new Rectangle(new Point(this.Width / 2 - side / 2, blank - side / 2), new Size(side, side));
    148.             recArrow[1] = new Rectangle(new Point(this.Width / 2 - side / 2, this.Height - blank - side / 2), new Size(side, side));
    149.             recArrow[2] = new Rectangle(new Point(blank-side/2 , this.Height / 2 - side/2), new Size(side, side));
    150.             recArrow[3] = new Rectangle(new Point(this.Width-blank - side / 2, this.Height / 2 - side / 2), new Size(side, side));
    151.             recArrow[4] = new Rectangle(new Point(blank - side / 2, blank - side / 2), new Size(side, side));
    152.             recArrow[5] = new Rectangle(new Point(blank - side / 2, this.Height - blank - side / 2), new Size(side, side));
    153.             recArrow[6] = new Rectangle(new Point(this.Width - blank - side / 2, blank - side / 2), new Size(side, side));
    154.             recArrow[7] = new Rectangle(new Point(this.Width - blank - side / 2, this.Height - blank - side / 2), new Size(side, side));
    155.  
    156.             foreach (Rectangle item in recArrow)
    157.                 e.Graphics.DrawRectangle(Pens.Red, item);
    158.             area = new Rectangle(new Point(8, 8), new Size(this.Width-8*2, this.Height-8*2));
    159.  
    160.             加上半透明效果看倒是好看了 重绘的时候卡的凶 ,期待有解决方法
    161.             e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
    162.             System.Drawing.Color cor = System.Drawing.Color.FromArgb(50, Color.Red);
    163.             System.Drawing.SolidBrush bsh = new System.Drawing.SolidBrush(cor);
    164.             e.Graphics.FillRectangle(bsh, area);
    165.  
    166.             e.Graphics.DrawRectangle(Pens.Red,area );
    167.         }

     最后还在一个老外的网站上扣了一段羽化效果的代码,可废了俺老大劲儿了。
    好了大功告成走走看:

    代码下载:C# winform实现图片裁剪效果

  • 相关阅读:
    java基于ssm的高校人事员工工资管理系统
    面试:Service及生命周期相关问题
    详解(一)-ThreadPollExecutor-并发编程(Java)
    《Kubernetes部署篇:Ubuntu20.04基于containerd二进制部署K8S 1.25.14集群(多主多从)》
    汽车电子——产品标准规范汇总和梳理(信息安全)
    16 C++ 二叉树遍历 Binary tree traversal
    桌面扫码点餐系统(小程序+Java后台)
    python,修改数组【第十届】【省赛】【研究生组】
    从0开始学习JavaScript--JavaScript使用Promise
    冶金行业数字化供应链管理系统:平台精益化企业管理,助力产业高质量发展
  • 原文地址:https://blog.csdn.net/lwf3115841/article/details/127728462