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


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();
this.pboImage.Location = new System.Drawing.Point(, );
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 / ;
int left = pboImage.Left - i / , top = pboImage.Top - i / ;
int width = pboImage.Width + i, heigth = pboImage.Height + i; if (i < ) //缩小时需要考虑与显示范围间关系,放大时无需考虑
{
//计算缩放后图片有效范围
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))) / ;
heigth = Convert.ToInt32(Math.Ceiling(pboImage.Image.Height / WidthScale));
}
else
{
left = left + Convert.ToInt32(Math.Ceiling(width - (pboImage.Image.Width / HeigthScale))) / ;
width = Convert.ToInt32(Math.Ceiling(pboImage.Image.Width / HeigthScale));
} if (left > ) //左侧在显示范围内部,调整到左边界
{
if (width - left < pel.Width) width = pel.Width;
else width = width - left;
left = ;
}
if (left + width < pel.Width)//右侧在显示范围内部,调整到右边界
{
if (pel.Width - width > ) left = ;
else left = pel.Width - width;
width = pel.Width - left;
} if (top > )//上侧在显示范围内部,调整到上边界
{
if (heigth - top < pel.Height) heigth = pel.Height;
else heigth = heigth - top;
top = ;
}
if (top + heigth < pel.Height)//下侧在显示范围内部,调整到下边界
{
if (pel.Height - heigth > ) top = ;
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))) / ;
InvalidHeigth = (int)Math.Ceiling(pboImage.Image.Height / WidthScale);
}
else
{
InvalidLeft = InvalidLeft + ((int)Math.Ceiling(InvalidWidth - (pboImage.Image.Width / HeigthScale))) / ;
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 >= ) left = ; //向右平移且平移后在显示范围内部,调整到左边界
if (left < InvalidLeft && right <= pel.Width) left = left + pel.Width - right;//向左平移且平移后在显示范围内部,调整到右边界
if (top >= InvalidTop && top >= ) top = ;//向下平移且平移后在显示范围内部,调整到上边界
if (top < InvalidTop && down <= pel.Height) top = top + pel.Height - down;//向上平移且平移后在显示范围内部,调整到下 边界 //有效范围锚点换算到整体的锚点
left = left + pboImage.Left - InvalidLeft;
top = top + pboImage.Top - InvalidTop; if (InvalidLeft <= ) pboImage.Left = left;
if (InvalidTop <= ) 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 = ;
pboImage.Top = ;
pboImage.Width = pel.Width;
pboImage.Height = pel.Height;
}
}

参考代码


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

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

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

C#图片缩放平移 —— 从功能分析到编码实现的更多相关文章

  1. android图片缩放平移

    <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android=" ...

  2. Android实现支持缩放平移图片

    本文主要用到了以下知识点 Matrix GestureDetector 能够捕捉到长按.双击 ScaleGestureDetector 用于检测缩放的手势 自由的缩放 需求:当图片加载时,将图片在屏幕 ...

  3. Android 手势检测实战 打造支持缩放平移的图片预览效果(下)

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/39480503,本文出自:[张鸿洋的博客] 上一篇已经带大家实现了自由的放大缩小图 ...

  4. Android 图片的平移和镜面和倒影效果

    在前面的文章中陆续介绍了图片的旋转与缩放,本文继续介绍关于图片的操作 图片的平移 使用下面的代码将图水平竖直方向平移10个像素 matrix.setTranslate(10, 10); 可以看到图片不 ...

  5. Asp.net 实现图片缩放 无水印(方法一)

    /// <summary> /// 图片缩放 无水印 /// </summary> /// <param name="sourceFile">图 ...

  6. Android----基于多触控的图片缩放和拖动代码实现

    引自:http://www.codefans.net/articles/584.shtml 一个android中自定义的ImageView控制,可对图片进行多点触控缩放和拖动类,包括了对图片放大和图片 ...

  7. Android绘画板(普通绘画模式和缩放平移绘画模式)

    ScaleSketchPadDemo 项目地址: demo apk体验下载 demo2 apk体验下载 用法: 进入项目根目录:https://github.com/ShaunSheep/ScaleS ...

  8. Android 开源可缩放平移的绘画板

    ScaleSketchPadDemo 此项目包含两个模块 app1 为普通绘画板 app2 为可所发的绘画板 方便各位Android 开发者理解和使用 用法: 进入项目根目录:https://gith ...

  9. OpenCV4.1.0实践(3) - 图片缩放

    简单的案例: (1)通过比例进行缩放 import cv2 as cv import numpy as np # 图片缩放 img = cv.imread('images/animal.jpg', f ...

随机推荐

  1. Python2处理字符集问题

    这篇文章主要介绍了Python2.x中文乱码问题解决方法,本文解释问题原因.给出了处理办法并讲解了编码解码的一些知识,需要的朋友可以参考下 Python中乱码问题是一个很头痛的问题. 在Python3 ...

  2. Windows Server 2003 简体中文企业版

    Windows Server 2003 简体中文企业版,真正免激活. CD-KEY:JB88F-WT2Q3-DPXTT-Y8GHG-7YYQY 安装序列号:JCGMJ-TC669-KCBG7-HB8X ...

  3. Dbvisualizer设置SQL语句自动提示

    Dbvisualizer默认不自动提示SQL语句的命令及查询的表,虽然可以通过Ctrl+/快捷键进行手动调用出提示信息,用习惯了PLSQL Developer难免有些不适应. 设置自动提示方法: 点击 ...

  4. 数据库执行的时候报ORA-01653错误

    查明原因是因为表空间文件到达了32G,因为oracle11g单个表空间大于32G的时候就不会自动在扩展了于是需要增加新的表空间文件,下面是4种解决此问题的方法 Meathod1:给表空间增加数据文件 ...

  5. eclipse Oxygen 4.7 + pydev

    pydev 官网  安装手册 PyDev requires Java 8 and Eclipse 4.6 (Neon) in order to run and only supports Python ...

  6. 【原】Coursera—Andrew Ng机器学习—Week 6 习题—Advice for applying machine learning

    [1] 诊断的作用 [2]过拟合 [3] [4] 高偏差bias,欠拟合underfitting 高方差variance,过拟合overfitting [5]参数λ Answer:  λ太大,则参数都 ...

  7. Python面向对象相关知识1

    1. python是动态的语言,这样在使用类的时候,类的属性就可以随意的添加,但是这样在实际开发中有一定的缺陷,所以,可以在类中定义一个特殊的__init__()方法,当创建实例时,__init__( ...

  8. Hadoop HA 机制学习

    一.Hadoop 系统架构 1.1 Hadoop1.x和Hadoop2.x 架构 在介绍HA之前,我们先来看下Hadoop的系统架构,这对于理解HA是至关重要的.Hadoop 1.x之前,其官方架构如 ...

  9. 运行Junit方法项目启动不了

    从控制台看不出任何有用信息,通过JUnit右键”Copy Failure List”将信息拷贝出来 TestStart.start initializationError(org.junit.runn ...

  10. mysql 错误集锦

    Got fatal error 1236 from master when reading data from binary log: 'could not find next log; the fi ...