图像比例关系及缩放规则
<Image Name="image" Source="F:\chenggeng\source\Image\Desert.jpg"
Width="Auto" Height="Auto" RenderTransform="{StaticResource Imageview}" Stretch="Uniform" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
当Stretch="Uniform"时,图像按比例适应布局,在无缩放及平移时,图像中心与布局中心重合。
如上图的图1与图2所示,布局缩放后会改变布局控件及图像控件的尺寸,但当缩放为1,偏移为0时,黑色框代表的图像与蓝色框代表的区域中心重合在一起。图3为缩放偏移后的位置关系,绿色框代表缩放无偏移后的图像,黑色框代表无缩放无偏移图像,无偏缩放时,图像左上角的位置不变。图四则有如下关系:
有
向
线
段
1
+
有
向
线
段
3
=
有
向
线
段
2
+
有
向
线
段
4
m
o
v
e
1.
x
+
p
o
i
n
t
.
x
∗
s
c
a
l
e
1
=
m
o
v
e
2.
x
+
p
o
i
n
t
.
x
∗
s
c
a
l
e
2
m
o
v
e
2.
x
−
m
o
v
e
1.
x
=
−
p
o
i
n
t
.
x
∗
(
s
c
a
l
e
2
−
s
c
a
l
e
1
)
=
−
p
o
i
n
t
.
x
∗
d
e
l
t
a
m
o
v
e
=
m
o
v
e
−
p
o
i
n
t
∗
d
e
l
t
a
有向线段1+有向线段3 = 有向线段2+有向线段4 \\ move1.x+point.x*scale1 = move2.x+point.x*scale2 \\ move2.x - move1.x = -point.x*(scale2-scale1) = -point.x*delta \\ move = move - point*delta
有向线段1+有向线段3=有向线段2+有向线段4move1.x+point.x∗scale1=move2.x+point.x∗scale2move2.x−move1.x=−point.x∗(scale2−scale1)=−point.x∗deltamove=move−point∗delta
即,在滚轮滚动缩放时,使move = move - point*delta即可实现以point为中心的缩放。
根据图3的示意图,绿色图像平移不完全超出蓝色窗口的边界限制条件为:
线段1<move<线段2
W+w > 2*move_x > -((2*scale-1)*w + W) 水平平移限制条件
H+h > 2*move_y > -((2*scale-1)*h + H) 垂直平移限制条件
根据上述结论,前后端代码如下:
PageCamera.xaml:
<Page ...>
<Grid>
...
<Grid Name="workspace" Grid.Row="2" Grid.Column="1" Background="Black">
<Grid.Resources>
<TransformGroup x:Key="Imageview">
<ScaleTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled"
Cursor="SizeAll" Focusable="False" x:Name="BackFrame">
<ContentControl MouseLeftButtonDown="ImgMouseLeftButtonDown"
MouseLeftButtonUp="ImgMouseLeftButtonUp"
MouseMove="ImgMouseMove"
MouseWheel="ImgMouseWheel">
<Image Name="image" Source="F:\chenggeng\source\Image\Desert.jpg"
Width="Auto" Height="Auto" RenderTransform="{StaticResource Imageview}"
Stretch="Uniform" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</ContentControl>
</ScrollViewer>
</Grid>
</Grid>
</Page>
PageCamera.xaml.cs:
...
namespace wpfbase
{
public partial class PageCamera : Page
{
public PageCamera()
{
InitializeComponent();
this.SizeChanged += new System.Windows.SizeChangedEventHandler(PageCameraResized);
}
/* -----------窗口大小变化响应------------ */
private void PageCameraResized(object sender, System.EventArgs e) {
var group = workspace.FindResource("Imageview") as TransformGroup;
var scale = group.Children[0] as ScaleTransform;
var move = group.Children[1] as TranslateTransform;
move.X = 0;
move.Y = 0;
scale.ScaleX = 1;
scale.ScaleY = 1;
}
/* -------------图像缩放处理--------------- */
// img为可视区域,image为图像
private bool mouseDown;
private Point position;
private void ImgMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
var img = sender as ContentControl;
if(img == null) {return;}
img.CaptureMouse();
mouseDown = true;
position = e.GetPosition(img);
}
private void ImgMouseLeftButtonUp(object sender, MouseButtonEventArgs e) {
var img = sender as ContentControl;
if(img == null) {return;}
img.ReleaseMouseCapture();
mouseDown = false;
var group = workspace.FindResource("Imageview") as TransformGroup;
var move = group.Children[1] as TranslateTransform;
}
private void ImgMouseMove(object sender, MouseEventArgs e) {
var img = sender as ContentControl;
if(img == null) {return;}
if(mouseDown) {
DoMouseMove(img, e);
}
}
private void DoMouseMove(ContentControl img, MouseEventArgs e) {
if(e.LeftButton != MouseButtonState.Pressed) {return;}
var group = workspace.FindResource("Imageview") as TransformGroup;
var scale = group.Children[0] as ScaleTransform;
var move = group.Children[1] as TranslateTransform;
var mouseXY = e.GetPosition(img);
move.X += mouseXY.X - position.X;
move.Y += mouseXY.Y - position.Y;
position = mouseXY;
// W+w > 2*move_x > -((2*scale-1)*w + W) 水平平移限制条件
// H+h > 2*move_y > -((2*scale-1)*h + H) 垂直平移限制条件
if(move.X*2 > image.ActualWidth+img.ActualWidth-20)
move.X = (image.ActualWidth+img.ActualWidth-20)/2;
if(-move.X*2 > (2*scale.ScaleX-1)*image.ActualWidth+img.ActualWidth-20)
move.X = -((scale.ScaleX-0.5)*image.ActualWidth+img.ActualWidth/2-10);
if(move.Y*2 > image.ActualHeight+img.ActualHeight-20)
move.Y = (image.ActualHeight+img.ActualHeight-20)/2;
if(-move.Y*2 > (2*scale.ScaleY-1)*image.ActualHeight+img.ActualHeight-20)
move.Y = -((scale.ScaleY-0.5)*image.ActualHeight+img.ActualHeight/2-10);
}
private void ImgMouseWheel(object sender, MouseWheelEventArgs e) {
var img = sender as ContentControl;
if(img == null) {return;}
var point = e.GetPosition(image);
var group = workspace.FindResource("Imageview") as TransformGroup;
var delta = e.Delta * 0.002;
DoWheelZoom(group, point, delta);
}
private void DoWheelZoom(TransformGroup group, Point point, double delta) {
var transform = group.Children[0] as ScaleTransform;
if (transform.ScaleX + delta < 0.1) return;
transform.ScaleX += delta;
transform.ScaleY += delta;
var transform1 = group.Children[1] as TranslateTransform;
transform1.X -= point.X*delta;
transform1.Y -= point.Y*delta;
}
}
}
效果图如下:
wpf图像缩放