• C#图片缩放平移 —— 从功能分析到编码实现


           一直都是在看别人的博客,查到想要的,看完后把页面一关就万事大吉了,没啥感觉;直到后来遇到了同样的问题,总想不起来咋弄,关键是还查不到以前看过的,郁闷!现在想想,还是“好记性不如烂笔头”啊,自己弄过的东西总要留下的什么呀,不然你都不知道自己曾经多么优秀。注册博客园也好久了,因为不知道该写点啥,再加上懒,一直没有去管它,今日有空,正好开张!


     1. 需求说明

           这个没啥好说的,主要干三个事,用电脑的照片查看器打开一张你宝贝的自拍照。

           (1)拉动显示窗口,图片按照原有比例被放大和缩小,照片查看器中当图片没能完全显示时,拉框时只是拉框,我们不管这个,只要图片显示窗口变了,那就按照原有比例被放大和缩小。

           (2)鼠标放在图片的有效区域,鼠标滚轮放大和缩小图片,缩小时最小只能到图片原大小;放大无限制,照片查看器放大也有限制,咱也不管它。

           (3)鼠标放在图片的有效区域,按住鼠标左键平移图片,平移时只能平移图片有效范围。


     2. 功能分析

           想想上面要实现的功能,结合C#,我们用Winform的窗体程序来实现,图片显示用PictureBox控件,它有一个PictureBoxSizeMode属性,值改成Zoom,这样就能保证PictureBox控件里面的图片随PictureBox控件大小改变而按照原有比例缩放,然后把PictureBox控件放大Form窗体中,dock属性改成Fill填满就可以了,但dock属性改成Fill填满之后,PictureBox控件的大小变得无法改变(我也是试了之后才知道的),一种有效的解决方案是在窗体里面放一个Panel控件,dock属性Fill,然后把PictureBox控件放在Panel中,大小改成和Panel控件一样大,再加一个Panel控件的SizeChanged事件,随时设置PictureBox控件和Panel控件一样大。这里不细说,具体看下面的C#编码实现,咱重点说说PictureBox控件里的图斑如何缩放和平移。

           要想实现缩放和平移,首先我们得了解它实现的原理,这是下面编码实现的基础。因为图片随PictureBox控件大小改变而按照原有比例缩放,因此我们改变PictureBox控件的大小,也就是它的Width和Height属性,在视觉上就能看到图片被放大和缩小,也就是缩放;当图片被放大后,窗体中不能显示完整的图片内容,这时就需要我们通过平移来查看未能显示在窗体上的图片部分了,同样的,我们只要改变PictureBox控件的位置,也就是它的Left和Top属性,就能把需要展示的图片局部正好显示在窗体上,从而在视觉上看到图片平移。

           原理简单说明了一下后,所以,我们想要实现缩放与偏移,本质上就是计算PictureBox控件的大小和位置,只要搞定了这个,缩放平移也就搞定了。那么这个大小和位置咋算呢,请接着往下看。我们知道照片查看器缩放用的鼠标滚轮,前滚放大,后滚缩小。PictureBox控件中找一下,MouseWheel事件正好干这个事。再一查,哎呀,SystemInformation.MouseWheelScrollLines代码滚一格(微软叫它制动器)代表多少行。那就好办了,我们把这个多少行按一定的比例转换成PictureBox控件Left、Top、Width、Height四个属性的增量,加上原值后,调整与显示窗体大小以及图片有效区域的位置关系,重新赋值回去就OK了。平移稍稍麻烦一点,其实也不是太麻烦。涉及到MouseDown、MouseMove、MouseUp三个事件,在鼠标按下时记录下按下点坐标,同时标识正在平移操作;在鼠标移动时计算移动的距离,换算Left、Top的增量,并与显示窗体大小和图片有效区域做调整,最后赋值会这俩属性;鼠标弹起时结束平移操作标识。


     3. 编码实现

           新建一个窗体应用程序,改窗体名称为frmMian,在其内添加一个Panel控件,命名pel;再在Panel控件中添加一个PictureBox控件,命名pboImage,以下为窗体类需要编写的代码:

    public partial class frmMian : Form
    {
        public frmMian()
        {
            InitializeComponent();
    
            this.pel.Dock = System.Windows.Forms.DockStyle.Fill;
            this.pel.SizeChanged += new System.EventHandler(this.pel_SizeChanged);
    
            this.pboImage.Margin = new System.Windows.Forms.Padding(0);
            this.pboImage.Location = new System.Drawing.Point(0, 0);
            this.pboImage.Size = new System.Drawing.Size(this.pel.Width, this.pel.Height);
            this.pboImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
            this.pboImage.Cursor = Cursors.SizeAll;
            this.pboImage.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseDown);
            this.pboImage.MouseEnter += new System.EventHandler(this.pboImage_MouseEnter);
            this.pboImage.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseMove);
            this.pboImage.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseUp);
            this.pboImage.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseWheel);
    
            pboImage.Image = Image.FromFile(@"C:宝贝自拍照.jpg");
        }
    
        private System.Drawing.Point MouseDownPoint = new System.Drawing.Point();//平移时鼠标按下的位置
        private bool IsSelected = false;    //鼠标是否是按下状态
    
        //pboImage获取焦点事件
        private void pboImage_MouseEnter(object sender, EventArgs e)
        {
            pboImage.Focus();
        }
    
        //pboImage鼠标滚轮事件
        private void pboImage_MouseWheel(object sender, MouseEventArgs e)
        {
            if (pboImage.Image == null) return;
    
            //计算缩放后的锚点和宽高
            int i = e.Delta * SystemInformation.MouseWheelScrollLines / 4;
            int left = pboImage.Left - i / 2, top = pboImage.Top - i / 2;
            int width = pboImage.Width + i, heigth = pboImage.Height + i;
    
            if (i < 0)      //缩小时需要考虑与显示范围间关系,放大时无需考虑
            {
                //计算缩放后图片有效范围
                double WidthScale = Convert.ToDouble(pboImage.Image.Width) / width;
                double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / heigth;
                if (WidthScale > HeigthScale)
                {
                    top = top + Convert.ToInt32(Math.Ceiling(heigth - (pboImage.Image.Height / WidthScale))) / 2;
                    heigth = Convert.ToInt32(Math.Ceiling(pboImage.Image.Height / WidthScale));
                }
                else
                {
                    left = left + Convert.ToInt32(Math.Ceiling(width - (pboImage.Image.Width / HeigthScale))) / 2;
                    width = Convert.ToInt32(Math.Ceiling(pboImage.Image.Width / HeigthScale));
                }
    
                if (left > 0)   //左侧在显示范围内部,调整到左边界
                {
                    if (width - left < pel.Width) width = pel.Width;
                    else width = width - left;
                    left = 0;
                }
                if (left + width < pel.Width)//右侧在显示范围内部,调整到右边界
                {
                    if (pel.Width - width > 0) left = 0;
                    else left = pel.Width - width;
                    width = pel.Width - left;
                }
    
                if (top > 0)//上侧在显示范围内部,调整到上边界
                {
                    if (heigth - top < pel.Height) heigth = pel.Height;
                    else heigth = heigth - top;
                    top = 0;
                }
                if (top + heigth < pel.Height)//下侧在显示范围内部,调整到下边界
                {
                    if (pel.Height - heigth > 0) top = 0;
                    else top = pel.Height - heigth;
                    heigth = pel.Height - top;
                }
            }
    
            pboImage.Width = width;
            pboImage.Height = heigth;
            pboImage.Left = left;
            pboImage.Top = top;
        }
    
        //pboImage鼠标按下事件
        private void pboImage_MouseDown(object sender, MouseEventArgs e)
        {
            if (pboImage.Image == null) return;
    
            if (e.Button == MouseButtons.Left)
            {
                //记录摁下点坐标,作为平移原点
                MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X;
                MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y;
                IsSelected = true;
                pboImage.Cursor = Cursors.Hand;
            }
        }
    
        //pboImage鼠标移动事件
        private void pboImage_MouseMove(object sender, MouseEventArgs e)
        {
            if (pboImage.Image == null) return;
    
            //计算图片有效范围
            double WidthScale = Convert.ToDouble(pboImage.Image.Width) / pboImage.Width;
            double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / pboImage.Height;
            int InvalidTop = pboImage.Top, InvalidHeigth = pboImage.Height, InvalidLeft = pboImage.Left, InvalidWidth = pboImage.Width;
            if (WidthScale > HeigthScale)
            {
                InvalidTop = InvalidTop + ((int)Math.Ceiling(InvalidHeigth - (pboImage.Image.Height / WidthScale))) / 2;
                InvalidHeigth = (int)Math.Ceiling(pboImage.Image.Height / WidthScale);
            }
            else
            {
                InvalidLeft = InvalidLeft + ((int)Math.Ceiling(InvalidWidth - (pboImage.Image.Width / HeigthScale))) / 2;
                InvalidWidth = (int)Math.Ceiling(pboImage.Image.Width / HeigthScale);
            }
    
            //鼠标是否摁在图片上
            bool IsMouseInPanel = InvalidLeft < PointToClient(System.Windows.Forms.Cursor.Position).X &&
                                    PointToClient(System.Windows.Forms.Cursor.Position).X < InvalidLeft + InvalidWidth &&
                                    InvalidTop < PointToClient(System.Windows.Forms.Cursor.Position).Y &&
                                    PointToClient(System.Windows.Forms.Cursor.Position).Y < InvalidTop + InvalidHeigth;
            if (IsSelected && IsMouseInPanel)
            {
                //计算平移后图片有效范围的锚点和宽高
                int left = InvalidLeft + (PointToClient(System.Windows.Forms.Cursor.Position).X - MouseDownPoint.X);
                int top = InvalidTop + (PointToClient(System.Windows.Forms.Cursor.Position).Y - MouseDownPoint.Y);
                int right = left + InvalidWidth;
                int down = top + InvalidHeigth;
    
                if (left >= InvalidLeft && left >= 0) left = 0; //向右平移且平移后在显示范围内部,调整到左边界
                if (left < InvalidLeft && right <= pel.Width) left = left + pel.Width - right;//向左平移且平移后在显示范围内部,调整到右边界
                if (top >= InvalidTop && top >= 0) top = 0;//向下平移且平移后在显示范围内部,调整到上边界
                if (top < InvalidTop && down <= pel.Height) top = top + pel.Height - down;//向上平移且平移后在显示范围内部,调整到下  边界
    
                //有效范围锚点换算到整体的锚点
                left = left + pboImage.Left - InvalidLeft;
                top = top + pboImage.Top - InvalidTop;
    
                if (InvalidLeft <= 0) pboImage.Left = left;
                if (InvalidTop <= 0) pboImage.Top = top;
    
                //记录当前平移点坐标,作为平移下一次代码执行时的平移原点
                MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X;
                MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y;
            }
        }
    
        //pboImage鼠标弹起事件
        private void pboImage_MouseUp(object sender, MouseEventArgs e)
        {
            if (pboImage.Image == null) return;
            IsSelected = false;
            pboImage.Cursor = Cursors.SizeAll;
        }
    
        //pel大小改变事件
        private void pel_SizeChanged(object sender, EventArgs e)
        {
            pboImage.Left = 0;
            pboImage.Top = 0;
            pboImage.Width = pel.Width;
            pboImage.Height = pel.Height;
        }
    }
    参考代码


    作者:喵...鱼...喵

    出处:https://www.cnblogs.com/bwuwj/ 

    本文为作者原创,版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如本文有误,欢迎批评指正。

  • 相关阅读:
    windows CMD大全
    算法导论(一):渐进记号
    数据结构之树
    Python读取文件内容与存储
    Python绘图的颜色设置
    Python中多个列表与字典的合并方法
    Pandas之Dataframe叠加,排序,统计,重新设置索引
    数据挖掘——聚类算法(一)
    WPF学习————制作时钟
    Opencv Sharp 基于灰度模板的多目标匹配
  • 原文地址:https://www.cnblogs.com/bwuwj/p/10307788.html
Copyright © 2020-2023  润新知