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


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,以下为窗体类需要编写的代码:

  1. public partial class frmMian : Form
  2. {
  3. public frmMian()
  4. {
  5. InitializeComponent();
  6.  
  7. this.pel.Dock = System.Windows.Forms.DockStyle.Fill;
  8. this.pel.SizeChanged += new System.EventHandler(this.pel_SizeChanged);
  9.  
  10. this.pboImage.Margin = new System.Windows.Forms.Padding();
  11. this.pboImage.Location = new System.Drawing.Point(, );
  12. this.pboImage.Size = new System.Drawing.Size(this.pel.Width, this.pel.Height);
  13. this.pboImage.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
  14. this.pboImage.Cursor = Cursors.SizeAll;
  15. this.pboImage.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseDown);
  16. this.pboImage.MouseEnter += new System.EventHandler(this.pboImage_MouseEnter);
  17. this.pboImage.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseMove);
  18. this.pboImage.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseUp);
  19. this.pboImage.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.pboImage_MouseWheel);
  20.  
  21. pboImage.Image = Image.FromFile(@"C:\宝贝自拍照.jpg");
  22. }
  23.  
  24. private System.Drawing.Point MouseDownPoint = new System.Drawing.Point();//平移时鼠标按下的位置
  25. private bool IsSelected = false; //鼠标是否是按下状态
  26.  
  27. //pboImage获取焦点事件
  28. private void pboImage_MouseEnter(object sender, EventArgs e)
  29. {
  30. pboImage.Focus();
  31. }
  32.  
  33. //pboImage鼠标滚轮事件
  34. private void pboImage_MouseWheel(object sender, MouseEventArgs e)
  35. {
  36. if (pboImage.Image == null) return;
  37.  
  38. //计算缩放后的锚点和宽高
  39. int i = e.Delta * SystemInformation.MouseWheelScrollLines / ;
  40. int left = pboImage.Left - i / , top = pboImage.Top - i / ;
  41. int width = pboImage.Width + i, heigth = pboImage.Height + i;
  42.  
  43. if (i < ) //缩小时需要考虑与显示范围间关系,放大时无需考虑
  44. {
  45. //计算缩放后图片有效范围
  46. double WidthScale = Convert.ToDouble(pboImage.Image.Width) / width;
  47. double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / heigth;
  48. if (WidthScale > HeigthScale)
  49. {
  50. top = top + Convert.ToInt32(Math.Ceiling(heigth - (pboImage.Image.Height / WidthScale))) / ;
  51. heigth = Convert.ToInt32(Math.Ceiling(pboImage.Image.Height / WidthScale));
  52. }
  53. else
  54. {
  55. left = left + Convert.ToInt32(Math.Ceiling(width - (pboImage.Image.Width / HeigthScale))) / ;
  56. width = Convert.ToInt32(Math.Ceiling(pboImage.Image.Width / HeigthScale));
  57. }
  58.  
  59. if (left > ) //左侧在显示范围内部,调整到左边界
  60. {
  61. if (width - left < pel.Width) width = pel.Width;
  62. else width = width - left;
  63. left = ;
  64. }
  65. if (left + width < pel.Width)//右侧在显示范围内部,调整到右边界
  66. {
  67. if (pel.Width - width > ) left = ;
  68. else left = pel.Width - width;
  69. width = pel.Width - left;
  70. }
  71.  
  72. if (top > )//上侧在显示范围内部,调整到上边界
  73. {
  74. if (heigth - top < pel.Height) heigth = pel.Height;
  75. else heigth = heigth - top;
  76. top = ;
  77. }
  78. if (top + heigth < pel.Height)//下侧在显示范围内部,调整到下边界
  79. {
  80. if (pel.Height - heigth > ) top = ;
  81. else top = pel.Height - heigth;
  82. heigth = pel.Height - top;
  83. }
  84. }
  85.  
  86. pboImage.Width = width;
  87. pboImage.Height = heigth;
  88. pboImage.Left = left;
  89. pboImage.Top = top;
  90. }
  91.  
  92. //pboImage鼠标按下事件
  93. private void pboImage_MouseDown(object sender, MouseEventArgs e)
  94. {
  95. if (pboImage.Image == null) return;
  96.  
  97. if (e.Button == MouseButtons.Left)
  98. {
  99. //记录摁下点坐标,作为平移原点
  100. MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X;
  101. MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y;
  102. IsSelected = true;
  103. pboImage.Cursor = Cursors.Hand;
  104. }
  105. }
  106.  
  107. //pboImage鼠标移动事件
  108. private void pboImage_MouseMove(object sender, MouseEventArgs e)
  109. {
  110. if (pboImage.Image == null) return;
  111.  
  112. //计算图片有效范围
  113. double WidthScale = Convert.ToDouble(pboImage.Image.Width) / pboImage.Width;
  114. double HeigthScale = Convert.ToDouble(pboImage.Image.Height) / pboImage.Height;
  115. int InvalidTop = pboImage.Top, InvalidHeigth = pboImage.Height, InvalidLeft = pboImage.Left, InvalidWidth = pboImage.Width;
  116. if (WidthScale > HeigthScale)
  117. {
  118. InvalidTop = InvalidTop + ((int)Math.Ceiling(InvalidHeigth - (pboImage.Image.Height / WidthScale))) / ;
  119. InvalidHeigth = (int)Math.Ceiling(pboImage.Image.Height / WidthScale);
  120. }
  121. else
  122. {
  123. InvalidLeft = InvalidLeft + ((int)Math.Ceiling(InvalidWidth - (pboImage.Image.Width / HeigthScale))) / ;
  124. InvalidWidth = (int)Math.Ceiling(pboImage.Image.Width / HeigthScale);
  125. }
  126.  
  127. //鼠标是否摁在图片上
  128. bool IsMouseInPanel = InvalidLeft < PointToClient(System.Windows.Forms.Cursor.Position).X &&
  129. PointToClient(System.Windows.Forms.Cursor.Position).X < InvalidLeft + InvalidWidth &&
  130. InvalidTop < PointToClient(System.Windows.Forms.Cursor.Position).Y &&
  131. PointToClient(System.Windows.Forms.Cursor.Position).Y < InvalidTop + InvalidHeigth;
  132. if (IsSelected && IsMouseInPanel)
  133. {
  134. //计算平移后图片有效范围的锚点和宽高
  135. int left = InvalidLeft + (PointToClient(System.Windows.Forms.Cursor.Position).X - MouseDownPoint.X);
  136. int top = InvalidTop + (PointToClient(System.Windows.Forms.Cursor.Position).Y - MouseDownPoint.Y);
  137. int right = left + InvalidWidth;
  138. int down = top + InvalidHeigth;
  139.  
  140. if (left >= InvalidLeft && left >= ) left = ; //向右平移且平移后在显示范围内部,调整到左边界
  141. if (left < InvalidLeft && right <= pel.Width) left = left + pel.Width - right;//向左平移且平移后在显示范围内部,调整到右边界
  142. if (top >= InvalidTop && top >= ) top = ;//向下平移且平移后在显示范围内部,调整到上边界
  143. if (top < InvalidTop && down <= pel.Height) top = top + pel.Height - down;//向上平移且平移后在显示范围内部,调整到下 边界
  144.  
  145. //有效范围锚点换算到整体的锚点
  146. left = left + pboImage.Left - InvalidLeft;
  147. top = top + pboImage.Top - InvalidTop;
  148.  
  149. if (InvalidLeft <= ) pboImage.Left = left;
  150. if (InvalidTop <= ) pboImage.Top = top;
  151.  
  152. //记录当前平移点坐标,作为平移下一次代码执行时的平移原点
  153. MouseDownPoint.X = PointToClient(System.Windows.Forms.Cursor.Position).X;
  154. MouseDownPoint.Y = PointToClient(System.Windows.Forms.Cursor.Position).Y;
  155. }
  156. }
  157.  
  158. //pboImage鼠标弹起事件
  159. private void pboImage_MouseUp(object sender, MouseEventArgs e)
  160. {
  161. if (pboImage.Image == null) return;
  162. IsSelected = false;
  163. pboImage.Cursor = Cursors.SizeAll;
  164. }
  165.  
  166. //pel大小改变事件
  167. private void pel_SizeChanged(object sender, EventArgs e)
  168. {
  169. pboImage.Left = ;
  170. pboImage.Top = ;
  171. pboImage.Width = pel.Width;
  172. pboImage.Height = pel.Height;
  173. }
  174. }

参考代码


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

出处: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. MyEclipse显示 Install new software 在线安装插件选项

    转自:https://blog.csdn.net/greatpresident/article/details/8950869 昨天不知道怎么就删除了电脑中的eclipse 我x,还原不回来了. 今天 ...

  2. mysql 乱码 utf8

    my.ini [mysql]default-character-set=utf8 [mysqld]character-set-server=utf8 show variables like '%cha ...

  3. delphi BLE 学习

    TBluetoothLE 控件 TBluetoothLE.FManager: TBluetoothLEManager; class constructor TBluetoothLEManager.Cr ...

  4. vue 起步_code

    <template> <div class="hello"> <h1>{{ msg }}</h1> <div>{{dat ...

  5. 译文:TypeScript新手指南

    你是否听过 TypeScript? TypeScript 是微软开发的 JavaScript 的超集,TypeScript兼容JavaScript,可以载入JavaScript代码然后运行.TypeS ...

  6. Apache Flume的介绍安装及简单案例

    概述 Flume 是 一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的软件.Flume 的核心是把数据从数据源(source)收集过来,再将收集到的数据送到指定的目的地(sink).为了保证 ...

  7. 【SPOJ -NSUBSTR】Substrings 【后缀自动机+dp】

    题意 给出一个字符串,要你找出所有长度的子串分别的最多出现次数. 分析 我们建出后缀自动机,然后预处理出每个状态的cnt,cnt[u]指的是u这个状态的right集合大小.我们设f[len]为长度为l ...

  8. Mysql配置文件详解 my.cof

    Mysql配置文件详解 # For advice on how to change settings please see # http://dev.mysql.com/doc/refman/5.6/ ...

  9. 制作initramfs/initrd镜像

    Linux kernel在自身初始化完成之后,需要能够找到并运行第一个用户程序(这个程序通常叫做"init"程序).用户程序存在于文件系统之中,因此,内核必须找到并挂载一个文件系统 ...

  10. Openssl pkeyutl命令

    一.简介 pkeyutl命令能够测试所支持的密钥算法的性能 二.语法 openssl rsautl [-in file] [-out file] [-sigfile file] [-inkey fil ...