艾伟_转载:在WPF里面实现以鼠标位置为中心缩放移动图片
2011-08-29 00:17
561 查看
在以前的文章使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果里面,介绍了如何在WPF里面移动和放大缩小图片,程序也支持使用滚轮的方式缩放图片。然而前面文章里介绍的缩放功能只能以图片中心为原点来实现,但是这种功能往往并不是客户想要的,我们看图片的时候,往往都喜欢以鼠标放在图片的焦点为原点进行图片的缩放。
咋看起来,实现这个功能也不是很难, ScaleTransform类里面定义了CenterX和CenterY两个属性就是用来设置缩放的原点坐标的。将这两个属性分别赋予鼠标的X, Y坐标值,就可以实现对原始图片,以鼠标位置为原点缩放图片了。但是,请注意,我说的原始图片是指没有移动之前的图片,如果图片缩放并且移动了,再次缩放的时候,就是另外一个故事了。
画个图说明一下吧,比如下图里面右下方方块是一个WPF程序里面的一个图片,大小是40 x 40,里面的黑点是预备缩放的原点,假设黑点的坐标是(10, 10),在运行程序的时候,用户首先将方块移动到左边的位置,当然原点(黑点)也移动了,假如这个时候图片移动了50个像素。
接着用户在移动后的位置上,将图片缩放,比如说放大了2倍,这个操作也会移动原点(黑点)在最终图片的位置。因为放大图片,实际上就是将原始图片的各个像素移动到新的位置(红点),这个时候,新的原点(红点)的坐标应该是(20, 20),相邻两个像素的空间使用插值的方法填充。这个时候,
ScaleTransform.ScaleX = 2;
ScaleTransform.ScaleY = 2;
这个时候,用户打算放大图片当中的另外一个区域,再放大一倍(即放大到原图的3倍),下图里是蓝点,假设坐标是(50, 50),因为无论图片缩放与否,用户只会以他在实际图片看到的内容来判断新的缩放焦点:
如果我们直接盲目地将ScaleTransform的各个属性设置为类似下面的值的话:
ScaleTransform.ScaleX = 3;
ScaleTransform.ScaleY = 3;
ScaleTransform.CenterX = 50;
ScaleTransform.CenterY = 50;
就发生问题了, 因为ScaleX = 3表示新图是原图的3倍,然而我们的原点却是在2倍图片上设置的—原图的大小只有40 x 40。解决方案当然是将蓝点的位置转换回在原始图片的位置,注意原始图片应该是下图右下方的图片,而不是左边的—用户最初已经移动了图片。
看起来转换起来有点麻烦,不过WPF提供了一个 函数TransformGroup.Inverse,可以把转换后图片上的坐标转换会在原始图片的坐标。当然啦,如果你熟悉图形学和线性代数的话,实际上,图片的缩放和移动就是将原始图片乘上一个矩阵,而TransformGroup.Inverse函数就是执行矩阵求逆操作。
下面就是关键代码:
XAML代码:
C#代码:
咋看起来,实现这个功能也不是很难, ScaleTransform类里面定义了CenterX和CenterY两个属性就是用来设置缩放的原点坐标的。将这两个属性分别赋予鼠标的X, Y坐标值,就可以实现对原始图片,以鼠标位置为原点缩放图片了。但是,请注意,我说的原始图片是指没有移动之前的图片,如果图片缩放并且移动了,再次缩放的时候,就是另外一个故事了。
画个图说明一下吧,比如下图里面右下方方块是一个WPF程序里面的一个图片,大小是40 x 40,里面的黑点是预备缩放的原点,假设黑点的坐标是(10, 10),在运行程序的时候,用户首先将方块移动到左边的位置,当然原点(黑点)也移动了,假如这个时候图片移动了50个像素。
接着用户在移动后的位置上,将图片缩放,比如说放大了2倍,这个操作也会移动原点(黑点)在最终图片的位置。因为放大图片,实际上就是将原始图片的各个像素移动到新的位置(红点),这个时候,新的原点(红点)的坐标应该是(20, 20),相邻两个像素的空间使用插值的方法填充。这个时候,
ScaleTransform.ScaleX = 2;
ScaleTransform.ScaleY = 2;
这个时候,用户打算放大图片当中的另外一个区域,再放大一倍(即放大到原图的3倍),下图里是蓝点,假设坐标是(50, 50),因为无论图片缩放与否,用户只会以他在实际图片看到的内容来判断新的缩放焦点:
如果我们直接盲目地将ScaleTransform的各个属性设置为类似下面的值的话:
ScaleTransform.ScaleX = 3;
ScaleTransform.ScaleY = 3;
ScaleTransform.CenterX = 50;
ScaleTransform.CenterY = 50;
就发生问题了, 因为ScaleX = 3表示新图是原图的3倍,然而我们的原点却是在2倍图片上设置的—原图的大小只有40 x 40。解决方案当然是将蓝点的位置转换回在原始图片的位置,注意原始图片应该是下图右下方的图片,而不是左边的—用户最初已经移动了图片。
看起来转换起来有点麻烦,不过WPF提供了一个 函数TransformGroup.Inverse,可以把转换后图片上的坐标转换会在原始图片的坐标。当然啦,如果你熟悉图形学和线性代数的话,实际上,图片的缩放和移动就是将原始图片乘上一个矩阵,而TransformGroup.Inverse函数就是执行矩阵求逆操作。
下面就是关键代码:
XAML代码:
<Grid.Resources> <TransformGroup x:Key="ImageCompareResources"> <ScaleTransform /> <TranslateTransform/> TransformGroup> Grid.Resources> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" Grid.Row="0" Grid.Column="0" x:Name=
"MasterScrollViewer" Margin="5" Background="WhiteSmoke"> <ContentControl x:Name="TestContentControl1" MouseLeftButtonDown="MasterImage_MouseLeftButtonDown" MouseLeftButtonUp="MasterImage_MouseLeftButtonUp" MouseMove="MasterImage_MouseMove" MouseWheel="MasterImage_MouseWheel"> <Image RenderOptions.BitmapScalingMode="NearestNeighbor" x:Name="MasterImage" Source="{Binding Path=MasterImagePath}" Stretch
="Uniform" RenderTransform="{StaticResource ImageCompareResources}"/> ContentControl> ScrollViewer>
C#代码:
private void MasterImage_MouseWheel(object sender, MouseWheelEventArgs e) { ContentControl image = sender as ContentControl; if (image == null) { return; } TransformGroup group = ImageComparePanel.FindResource("ImageCompareR
esources") as TransformGroup; Debug.Assert(group != null, "Can't find transform group from image compare p
anel resource"); Point point = e.GetPosition(image); double scale = e.Delta * 0.001; ZoomImage(group, point, scale); } private static void ZoomImage(TransformGroup group, Point point, double scale) { Debug.Assert(group != null, "Oops, ImageCompareResources is removed from
current control's resouce"); Point pointToContent = group.Inverse.Transform(point); ScaleTransform transform = group.Children[0] as ScaleTransform; if (transform.ScaleX + scale < 1) { return; } transform.ScaleX += scale; transform.ScaleY += scale; TranslateTransform transform1 = group.Children[1] as TranslateTransform; transform1.X = -1 * ((pointToContent.X * transform.ScaleX) - point.X); transform1.Y = -1 * ((pointToContent.Y * transform.ScaleY) - point.Y); } private void MasterImage_MouseMove(object sender, MouseEventArgs e) { ContentControl image = sender as ContentControl; if (image == null) { return; } if (this.isMouseLeftButtonDown && e.LeftButton == MouseButtonState.Pressed) { this.DoImageMove(image, e.GetPosition(image)); } } private void DoImageMove(ContentControl image, Point position) { TransformGroup group = ImageComparePanel.FindResource("ImageCompareR
esources") as TransformGroup; Debug.Assert(group != null, "Can't find transform group from image compare
panel resource"); TranslateTransform transform = group.Children[1] as TranslateTransform; transform.X += position.X - this.previousMousePoint.X; transform.Y += position.Y - this.previousMousePoint.Y; this.previousMousePoint = position; }
相关文章推荐
- 在WPF里面实现以鼠标位置为中心缩放移动图片
- 在WPF里面实现以鼠标位置为中心缩放移动图片
- MFC GDI+实现以鼠标为中心缩放图片(并且可以拖动)
- ZK集成jqueryui 实现图片鼠标滚轮缩放以及拖拽位置
- c# WPF 中图片缩放功能,鼠标拖动位置
- Javascript实现图片位置控制(鼠标拖拽 + 键盘方向键移动)源码分享
- MFC GDI+实现以鼠标为中心缩放图片(并且可以拖动)
- ImageView里面的图片实现同时移动缩放旋转 photoView自定义
- 使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果
- css实现在鼠标放上去时图片从中心位置变大
- 使用WPF Resource以及Transform等技术实现鼠标控制图片缩放和移动的效果
- flex实现图片根据鼠标的滚动放大或缩小(以鼠标的的位置 为中心放大缩小)
- css3 实现鼠标放上去图片外框不变大,里面中心放大
- 移动鼠标实现图片的缩放
- Javascript实现图片位置控制(鼠标拖拽 + 键盘方向键移动)源码分享
- 以鼠标位置为中心缩放平移图片(图片map)
- css3 实现鼠标放上去图片外框不变大,里面中心放大
- MFC GDI+实现以鼠标为中心缩放图片(并且可以拖动)
- iphone ipad 开发:结合UIImageView实现图片的移动和缩放
- WPF通过鼠标滑轮缩放显示图片