【C#】C#实现鼠标滚轮的图像居中缩放
最近接触了一下C# 的内容,遇到一个需求,就是关于图像的的缩放。查找了网上的一些资源,发现这些方法存在一些或多或少的问题。所以今天花点时间把自己查阅资料和实践的心得分享出来,希望对有需要的人有所帮助。准备工作 在创建了C#的工程后,为了实现图像缩放,首先需要添加一个 Panel 容器至窗口中;然后再向 Panel 中添加一个 PictureBox 公共控件,最后将 Panel 容器停靠在..
【fishing-pan:https://blog.csdn.net/u013921430 转载请注明出处】
最近接触了一下C# 的内容,遇到一个需求,就是关于图像的的缩放。查找了网上的一些资源,发现这些方法存在一些或多或少的问题,而且大部分都是相互抄袭的。所以今天花点时间把自己查阅资料和实践的心得分享出来,希望对有需要的人有所帮助。
如果这篇博客对你有所帮助,请点个赞哈。
准备工作
在创建了C#的工程后,为了实现图像缩放,首先需要添加一个 Panel 容器至窗口中;然后再向 Panel 中添加一个 PictureBox 公共控件,并且将 PictureBox 的 SizeMode 设置为Zoom,最后将 Panel 容器停靠在父窗口。至此,准备工作就结束了。添加进父窗口的方法就是点击下图中的小三角形,然后选择停靠在父窗口。
创建事件
在做完准备工作后就要添加事件了,但是在自带的事件中并没有MouseWheel事件,所以需要自己添加。
首先在Designer.cs文件的panel部分添加以下事件声明,以创建鼠标滚动事件。
this.panel1.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseWheel);
实现缩放事件
在实现缩放事件前,首先需要明确一些事情。
- 这里采用的方法是通过改变窗口大小来进行缩放的;
- 网络上的很多资料通过改变 PictureBox 相对于 panel 的位置来实现居中或者根据鼠标位置定点缩放。就是后面的的方式;
this.pictureBox.pictureBox.Location = point(Left, Top);
- 窗口滑条有两个很重要的特征,首先就是滑条的长度表示窗口的大小,也就是 panel 的高和宽;第二,滑条的位置对于水平滑条来说,是滑条左侧端点的位置,垂直滑条的位置是上端点的位置。(这一条听起来有点懵,后面会解释)
那么首先来说第二点;网络上常用的这种方法确实可以实现定点缩放;但是由于改变位置后的左上点一般是负值;会导致在窗口左侧和上侧的图像无法访问,试过的人应该都知道。是不可取的,但是我们通过修改滑条的位置来实现定点缩放就不会存在这种问题。所以我们在上面会提到滑条的一些特性。
再来说说第三点;我们知道,当图像大小小于或者等于窗口大小时,是不需要滑条的,因为此时窗口可以放下图像;当图像大于窗口大小时,则需要滑条来调节。而滑条所在的整个区间的代表的是 PictureBox 的尺寸,滑条代表窗口的大小。几者之间满足以下等式;
L
e
n
g
t
h
S
c
r
o
l
l
L
e
n
g
t
h
R
a
n
g
e
=
S
i
z
e
W
i
n
d
o
w
S
i
z
e
P
i
c
t
u
r
e
B
o
x
\frac{LengthScroll}{LengthRange}=\frac{SizeWindow}{SizePictureBox}
LengthRangeLengthScroll=SizePictureBoxSizeWindow
从上面的关系式不难分析,滑条端点的位置取决于窗口展示的图像在整个 PictureBox 中的相对位置。了解以上关系,就可以实现定点缩放,接下来以窗口中心定点缩放来进行分析;
PictureBox 相对于 panel 的位置 Left 和 Top 是可以直接获得的属性; panel 的尺寸 Width 和 Height 也是可以直接获得的属性。根据这两个属性我们可以知道窗口中心位置的像素 Centor 在 PictureBox 中的位置为;
int iOriginCentorX=(this.panel1.Width/2-this.pictureBox.Left);
int iOriginCentorY=(this.panel1.Height/2-this.pictureBox.Top);
而在了解缩放比例后,中心点在图像中的坐标也是可以知道的;而窗口大小是不变的;就可以求出位于窗口左上位置的像素点在图像中的坐标;
n
e
w
L
e
f
t
=
n
e
w
C
e
n
t
o
r
X
−
W
i
n
d
o
w
W
i
d
t
h
2
newLeft=newCentorX-\frac{WindowWidth}{2}
newLeft=newCentorX−2WindowWidth
n
e
w
T
o
p
=
n
e
w
C
e
n
t
o
r
Y
−
W
i
n
d
o
w
H
e
i
g
h
t
2
+
D
e
l
t
a
newTop=newCentorY-\frac{WindowHeight}{2}+Delta
newTop=newCentorY−2WindowHeight+Delta
而这个位置就是我们需要的滑条的位置。但是有个问题,滑动滚轮时,滑条位置会被改变;所以上面的公式中垂直滑条的位置要加上一个Delta,既是滚轮滑动一次,滑条滑动的距离。下面就是函数的代码。完整的项目资源,我放在了这里。
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
if (Control.ModifierKeys==Keys.Control)
{
float fZoomFactor = 1.2f; // 缩放因子
int iOriginCentorX=(this.panel1.Width/2-this.pictureBox.Left); //缩放前
int iOriginCentorY=(this.panel1.Height/2-this.pictureBox.Top);
//防止无限制的缩放
if ((this.pictureBox.Width < 200 && e.Delta < 0) || (this.pictureBox.Width > 10000 && e.Delta > 0))
return;
if(e.Delta>0)
{
//缩放后的picture box的大小。
this.pictureBox.Width = (int)(fZoomFactor * this.pictureBox.Width);
this.pictureBox.Height = (int)(fZoomFactor * this.pictureBox.Height);
//缩放后的中心点距离picture box左上角的距离。
int iNewCentorX=(int)(iOriginCentorX*fZoomFactor);
int iNewCentorY=(int)(iOriginCentorY*fZoomFactor);
//缩放后的滚轮的位置。
this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
(int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
}
else
{
this.pictureBox.Width = (int)(this.pictureBox.Width / fZoomFactor);
this.pictureBox.Height = (int)(this.pictureBox.Height / fZoomFactor);
int iNewCentorX = (int)(iOriginCentorX / fZoomFactor);
int iNewCentorY = (int)(iOriginCentorY / fZoomFactor);
this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
(int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
}
}
}
另一种缩放图像的方法。
上面的过程,只是修改了装载图像的Picture Box的大小,而没有真正的修改图像的大小;所以当你保存图像的话,应该还是原图的大小。这里我提供一种修改了图像大小的缩放方法(就是Bitmap的缩放方法)。
private void panel1_MouseWheel(object sender, MouseEventArgs e)
{
if (Control.ModifierKeys == Keys.Control)
{
float fZoomFactor = 1.2f; // 缩放因子
int iOriginCentorX = (this.panel1.Width / 2 - this.pictureBox.Left); //缩放前
int iOriginCentorY = (this.panel1.Height / 2 - this.pictureBox.Top);
//防止无限制的缩放
if ((this.pictureBox.Width < 200 && e.Delta < 0) || (this.pictureBox.Width > 10000 && e.Delta > 0))
return;
if (e.Delta > 0)
{
//缩放后的picture box的大小。
int iNewWidth = (int)(fZoomFactor * this.pictureBox.Width);
int iNewHeight = (int)(fZoomFactor * this.pictureBox.Height);
//定义新的Bitmap;
Bitmap BitNewImg = new Bitmap(iNewWidth, iNewHeight);
//定义对BitNewImg的绘制方法;
Graphics graph = Graphics.FromImage(BitNewImg);
graph.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
//用原始图像绘制新图像;
graph.DrawImage((Bitmap)this.pictureBox.Image, new Rectangle(0, 0, iNewWidth, iNewHeight),
new Rectangle(0, 0, this.pictureBox.Width, this.pictureBox.Height), GraphicsUnit.Pixel);
//缩放后的中心点距离picture box左上角的距离。
int iNewCentorX = (int)(iOriginCentorX * fZoomFactor);
int iNewCentorY = (int)(iOriginCentorY * fZoomFactor);
this.pictureBox.Image = BitNewImg;
this.pictureBox.Width = this.pictureBox.Image.Width;
this.pictureBox.Height = this.pictureBox.Image.Height;
//缩放后的滚轮的位置。
this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
(int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
graph.Dispose();
}
else
{
int iNewWidth = (int)(this.pictureBox.Width / fZoomFactor);
int iNewHeight = (int)(this.pictureBox.Height / fZoomFactor);
Bitmap BitNewImg = new Bitmap(iNewWidth, iNewHeight);
//定义对BitNewImg的绘制方法;
Graphics graph = Graphics.FromImage(BitNewImg);
graph.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Bilinear;
//用原始图像绘制新图像;
graph.DrawImage((Bitmap)this.pictureBox.Image, new Rectangle(0, 0, iNewWidth, iNewHeight),
new Rectangle(0, 0, this.pictureBox.Width, this.pictureBox.Height), GraphicsUnit.Pixel);
this.pictureBox.Image = BitNewImg;
this.pictureBox.Width = this.pictureBox.Image.Width;
this.pictureBox.Height = this.pictureBox.Image.Height;
int iNewCentorX = (int)(iOriginCentorX / fZoomFactor);
int iNewCentorY = (int)(iOriginCentorY / fZoomFactor);
this.panel1.AutoScrollPosition = new Point((int)(iNewCentorX - this.panel1.Width / 2),
(int)(iNewCentorY - this.panel1.Height / 2 + e.Delta));
}
}
}
最后
从文章可以看出,其实图像缩放的实现并不难,重要的是理解滑条的位置的意义,从而决定缩放后滑条的位置,以达到定点缩放。虽然这篇博客讲的是以窗口中心的像素点进行定点缩放,但是了解了原理,根据鼠标位置进行缩放也并不难。
如果这篇博客对你有所帮助,就点个赞吧。
更多推荐
所有评论(0)