zoukankan      html  css  js  c++  java
  • 图片裁剪效果

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

    在园子里找了下没有现成的东东,准备自己整个。仔细想了下对图片进行裁剪  裁剪这个过程完全不用我们费心
    因为.Net里盖茨大叔开的公司为我们提供了drawImage这个万能的函数啦,msdn里对他的大概解释是 把原图指定矩形区域的像素“画”到目标Image的指定矩形区域

    来看看:

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

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

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

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

     private Point m_MousePoint;
     private Point m_LastPoint;
     protected override void OnMouseDown(MouseEventArgs e)
     {
         base.OnMouseDown(e);
         this.m_LastPoint = this.Location;
         this.m_MousePoint = this.PointToScreen(e.Location);           
     }
    
     protected override void OnMouseMove(MouseEventArgs e)
     {
         base.OnMouseMove(e);
         if (e.Button == MouseButtons.Left)
         {
             Point t = this.PointToScreen(e.Location);
             Point l = this.m_LastPoint;
             l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
             this.Location = l;
         }
     }
    

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

    protected override void OnMouseMove(MouseEventArgs e)
            {
    
                base.OnMouseMove(e);
    
                if (arow != arrowType.none)
                {
                    reSize(e);
                    return;
                }
    
                if (e.Y <= recArrow[4].Bottom && e.Y >= recArrow[4].Top && e.X >= recArrow[4].Left && e.X <= recArrow[4].Right)//左上
                    Cursor = Cursors.SizeNWSE;
                else if (e.Y <= recArrow[5].Bottom && e.Y >= recArrow[5].Top && e.X >= recArrow[5].Left && e.X <= recArrow[5].Right)//左下
                    Cursor = Cursors.SizeNESW;
                else if (e.Y <= recArrow[6].Bottom && e.Y >= recArrow[6].Top && e.X >= recArrow[6].Left && e.X <= recArrow[6].Right)//右上
                    Cursor = Cursors.SizeNESW;
                else if (e.Y <= recArrow[7].Bottom && e.Y >= recArrow[7].Top && e.X >= recArrow[7].Left && e.X <= recArrow[7].Right)//右下
                    Cursor = Cursors.SizeNWSE;
                else if (e.Y <= recArrow[0].Bottom && e.Y >= recArrow[0].Top)//上
                    Cursor = Cursors.SizeNS;
                else if (e.Y <= recArrow[1].Bottom && e.Y >= recArrow[1].Top)//下
                    Cursor = Cursors.SizeNS;
                else if (e.X >= recArrow[2].Left && e.X <= recArrow[2].Right)//左
                    Cursor = Cursors.SizeWE;
                else if (e.X >= recArrow[3].Left && e.X <= recArrow[3].Right)//右
                    Cursor = Cursors.SizeWE;
                else
                    Cursor = Cursors.SizeAll;
    
    
                if (e.Button == MouseButtons.Left)
                {
                    Point t = this.PointToScreen(e.Location);
                    Point l = this.m_LastPoint;
    
                    if (e.Y <= recArrow[4].Bottom && e.Y >= recArrow[4].Top && e.X >= recArrow[4].Left && e.X <= recArrow[4].Right)//左上
                        arow = arrowType.leftUp;
                    else if (e.Y <= recArrow[5].Bottom && e.Y >= recArrow[5].Top && e.X >= recArrow[5].Left && e.X <= recArrow[5].Right)//左下
                        arow = arrowType.leftDown;
                    else if (e.Y <= recArrow[6].Bottom && e.Y >= recArrow[6].Top && e.X >= recArrow[6].Left && e.X <= recArrow[6].Right)//右上
                        arow = arrowType.rightUp;
                    else if (e.Y <= recArrow[7].Bottom && e.Y >= recArrow[7].Top && e.X >= recArrow[7].Left && e.X <= recArrow[7].Right)//右下
                        arow = arrowType.rightDown;
                    else if (e.Y <= recArrow[0].Bottom && e.Y >= recArrow[0].Top)//上
                        arow = arrowType.up;
                    else if (e.Y <= recArrow[1].Bottom && e.Y >= recArrow[1].Top)//下
                        arow = arrowType.down;
                    else if (e.X >= recArrow[2].Left && e.X <= recArrow[2].Right)//左
                        arow = arrowType.left;
                    else if (e.X >= recArrow[3].Left && e.X <= recArrow[3].Right)//右
                        arow = arrowType.right;
                    else
                        arow = arrowType.none;
    
    
                    l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
                    if (arow != arrowType.none)
                        reSize(e);
                    else
                    {
                        this.Location = l;
                        Refresh();//这句很重要立即重绘 不然拖动到时候会出现卡卡 的现象 ,找了半天原因
                    }
                }
            }
    
            public void reSize(MouseEventArgs e)
            {
                Point t = this.PointToScreen(e.Location);
                Point l = this.m_LastPoint;
    
                l.Offset(t.X - this.m_MousePoint.X, t.Y - this.m_MousePoint.Y);
    
                switch (arow)
                {
                    case arrowType.up:
                        {
                            this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
                            this.Location = new Point(m_LastPoint.X, l.Y);
                            break;
                        }
                    case arrowType.down:
                        {
                            this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
                            break;
                        }
                    case arrowType.left:
                        {
                            this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
                            this.Location = new Point(l.X, m_LastPoint.Y);
                            break;
                        }
                    case arrowType.right:
                        {
                            this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
                            break;
                        }
                    case arrowType.leftUp:
                        {
                            this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
                            this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
                            this.Location = new Point(l.X, l.Y);
                            break;
                        }
                    case arrowType.leftDown:
                        {
                            this.Width = m_Size.Width - (t.X - this.m_MousePoint.X);
                            this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
                            this.Location = new Point(l.X, m_LastPoint.Y);
                            break;
                        }
                    case arrowType.rightUp:
                        {
                            this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
                            this.Height = m_Size.Height - (t.Y - this.m_MousePoint.Y);
                            this.Location = new Point(m_LastPoint.X, l.Y);
                            break;
                        }
                    case arrowType.rightDown:
                        {
                            this.Width = m_Size.Width + (t.X - this.m_MousePoint.X);
                            this.Height = m_Size.Height + (t.Y - this.m_MousePoint.Y);
                            break;
                        }
                }
                this.Refresh();
            }
    
     
    
            public enum arrowType
            {
                up,down,left,right,leftUp,leftDown,rightUp,rightDown,none
            }
    
            public arrowType arow=arrowType.none;
    
            Rectangle []recArrow=new Rectangle[8];//8个手柄
    
            public  Rectangle area ;//选择区域
            public readonly int blank=8;//边距
            protected override void OnPaint(PaintEventArgs e)
            {
                int side = 6;//手柄矩形的边长
                
                recArrow[0] = new Rectangle(new Point(this.Width / 2 - side / 2, blank - side / 2), new Size(side, side));
                recArrow[1] = new Rectangle(new Point(this.Width / 2 - side / 2, this.Height - blank - side / 2), new Size(side, side));
                recArrow[2] = new Rectangle(new Point(blank-side/2 , this.Height / 2 - side/2), new Size(side, side));
                recArrow[3] = new Rectangle(new Point(this.Width-blank - side / 2, this.Height / 2 - side / 2), new Size(side, side));
                recArrow[4] = new Rectangle(new Point(blank - side / 2, blank - side / 2), new Size(side, side));
                recArrow[5] = new Rectangle(new Point(blank - side / 2, this.Height - blank - side / 2), new Size(side, side));
                recArrow[6] = new Rectangle(new Point(this.Width - blank - side / 2, blank - side / 2), new Size(side, side));
                recArrow[7] = new Rectangle(new Point(this.Width - blank - side / 2, this.Height - blank - side / 2), new Size(side, side));
    
                foreach (Rectangle item in recArrow)
                    e.Graphics.DrawRectangle(Pens.Red, item);
                area = new Rectangle(new Point(8, 8), new Size(this.Width-8*2, this.Height-8*2));
    
                ////加上半透明效果看倒是好看了 重绘的时候卡的凶 ,期待有解决方法
                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                System.Drawing.Color cor = System.Drawing.Color.FromArgb(50, Color.Red);
                System.Drawing.SolidBrush bsh = new System.Drawing.SolidBrush(cor);
                e.Graphics.FillRectangle(bsh, area);
    
                e.Graphics.DrawRectangle(Pens.Red,area );
            }
    

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

    你是不是想说这图很給力哇(¯▽¯;)
    这是测试程序(带源码)下载链接

    可能有朋友说拖动的时候还一闪一闪的,俺只有这水平 尽力了哈 至少功能全部实现了吧,正在改进中。。。
    要源码的朋友给俺发邮件哈,连代码跟图一起发给你 ,多半是冲着图来的吧 挖哈哈(¯▽¯;)。

    重新编辑了 源码都发出来了哈,别留邮箱了 哥们儿些

  • 相关阅读:
    资深项目经理推荐的几款免费/开源项目管理工具
    内网穿透工具frp简单使用教程
    10部全尺度欧美宫斗剧!献给不甘平淡的你
    Spring Boot后端+Vue前端+微信小程序,完整的开源解决方案!
    搭建Keepalived + Nginx + Tomcat的高可用负载均衡架构
    集成Activiti工作流的J2EE快速开发框架
    国内5大前端团队网站,你了解多少
    5 天 4000 star 的一个爆款开源项目
    「干货」常用的10个网络DOS命令,菜鸟学了变高手
    js自定义正则表达式
  • 原文地址:https://www.cnblogs.com/assassinx/p/2174320.html
Copyright © 2011-2022 走看看