wpf下的圖片放大縮小
WPF下實現圖片的放大縮小移動
在windows 7裡面有自帶的圖片檢視器,這個軟體可以開啟一張圖片然後以滑鼠在圖片中的焦點為原點來進行縮放,並且放大後可以隨意拖動。下面我們在WPF中實現這個功能。
在實現這個功能之前先說下使用的主要函式和步驟:
ScaleTransform:進行縮放的函式。
TranslateTransform:進行平移的函式。
TransformGroup.Inverse:縮放圖片後,把縮放後圖片上的座標轉換為在原始圖片的座標,從而使圖片正常縮放。
- 步驟如下:
- 定義一個TranslateTransform例項來修改圖片顯示的起始位置。
-
定義一個ScaleTransform例項來縮放圖片的大小,你可以通過設定CenterX和CenterY的值來指定圖片縮放的原點。
這裡使用TransformGroup.Inverse來轉換放縮原點
- 將兩個Transform放到一個TransformGroup裡面,這樣Image控制元件就可以在顯示的時候綜合使用兩個Transform的效果了。
- 將TransformGroup放到當前窗體的Resource裡面,這樣窗體裡面所有的Image控制元件都可以引用到這個例項。
- 在滑鼠移動事件裡面修改TranslateTransform對應的值。
-
在滑鼠滾輪事件裡面修改ScaleTransform的ScaleX和ScaleY的值來縮放圖片
- XAML程式碼:
<Grid x:Name="IMG" Width="500" Height="300" Background="Black"> <Grid.Resources> <TransformGroup x:Key="Imageview"> <ScaleTransform/> <TranslateTransform/> </TransformGroup> </Grid.Resources>
// 建立TransformGroup集合,設立關鍵Key,並加入縮放和移動時所需函式。
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled" Background="Wheat" Cursor="SizeAll" Margin="5" Focusable="False" x:Name="BackFrame"> <ContentControl MouseLeftButtonDown="IMG1_MouseLeftButtonDown" MouseLeftButtonUp="IMG1_MouseLeftButtonUp" MouseMove="IMG1_MouseMove" MouseWheel="IMG1_MouseWheel" > <Image Name="IMG1" Source="D:\Sun\Ta,S\1013\1.jpg" RenderTransform="{StaticResource Imageview}" Stretch="Uniform" RenderOptions.BitmapScalingMode="NearestNeighbor" ></Image> </ContentControl> </ScrollViewer> </Grid>
//建立ScrollViewer容器來放置在ContentControl 中新增滑鼠事件和圖片,並把圖片////RenderTransform的變換資訊設定為靜態資源 Imageview。////RenderOptions.BitmapScalingMode="NearestNeighbor"使圖片的變幻過程得到優化。防止出現移動和放縮圖片模糊的情況。
- C#程式碼:
private bool mouseDown; private Point mouseXY; private void IMG1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var img = sender as ContentControl; if (img == null) { return; } img.CaptureMouse(); mouseDown = true; mouseXY = e.GetPosition(img); }
滑鼠按下時的事件,啟用捕獲滑鼠位置並把座標賦值給mouseXY.
private void IMG1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { var img = sender as ContentControl; if (img == null) { return; } img.ReleaseMouseCapture(); mouseDown = false; }
滑鼠鬆開時的事件,停止捕獲滑鼠位置。
private void IMG1_MouseMove(object sender, MouseEventArgs e) { var img = sender as ContentControl; if (img == null) { return; } if (mouseDown) { Domousemove(img, e); } }
滑鼠移動時的事件,當滑鼠按下並移動時發生
Domousemove(img, e);函式
private void Domousemove(ContentControl img, MouseEventArgs e) { if (e.LeftButton != MouseButtonState.Pressed) { return; } var group = IMG.FindResource("Imageview") as TransformGroup; var transform = group.Children[1] as TranslateTransform; var position = e.GetPosition(img); transform.X-= mouseXY.X- position.X; transform.Y -= mouseXY.Y - position.Y; mouseXY = position; }
group.Children中的第二個是移動的函式
它根據X.Y的值來移動。並把當前滑鼠位置賦值給mouseXY.
private void IMG1_MouseWheel(object sender, MouseWheelEventArgs e) { var img = sender as ContentControl; if (img == null) { return; } var point = e.GetPosition(img); var group = IMG.FindResource("Imageview") as TransformGroup; var delta = e.Delta * 0.001; DowheelZoom(group, point, delta); }
滑鼠滑輪事件,得到座標,放縮函式和滑輪指數,由於滑輪值變化較大所以*0.001.
private void DowheelZoom(TransformGroup group, Point point, double delta) { var pointToContent = group.Inverse.Transform(point); 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 = -1 * ((pointToContent.X * transform.ScaleX) - point.X); transform1.Y = -1 * ((pointToContent.Y * transform.ScaleY) - point.Y); }
Group.Children中的第一個是放縮函式。
如果ScaleX+滑輪指數小於0.1時就返回。
varpointToContent = group.Inverse.Transform(point);
獲取此變換的逆變換的值
使圖片放縮後,放縮原點也隨之變化。
vartransform1 = group.Children[1]asTranslateTransform;
transform1.X = -1 *((pointToContent.X * transform.ScaleX) - point.X);
transform1.Y = -1 *((pointToContent.Y * transform.ScaleY) - point.Y);
用來捕獲圖片放縮中心。使放縮圖片時可以放大縮小自己想要的點。 - 關於放縮中心問題
下面這段程式碼可用來說明上面捕獲圖片放縮中心那段程式碼的含義
private void DowheelZoom(TransformGroup group, Point point ,double delta) { var transform = group.Children[0] as ScaleTransform; if (transform.ScaleX + delta < 0.1) return; transform.CenterX= point1.X-1; transform.CenterY= point1.Y-1; transform.ScaleX += delta; transform.ScaleY += delta; }
如果這樣寫也可以時圖片放大縮小,並且在自己設定的點放大縮小,但是等圖片放大到一定程度時,放大後,把滑鼠移到這個點,此時的放縮原點隨著滑鼠到了這個點處。滑鼠獲取的座標是相對與圖片來說的。所以當在這個點處進行縮放時,圖片會一下切換到以這一點為中心進行縮放。
為了避免這種跳躍式的變換。就要把滑鼠的座標變換成原圖片即沒有放縮過的圖片上的座標。這樣放縮就不會出現跳躍了。
這種變換座標看起來麻煩,其實WPF已經給我們提供了函式
TransformGroup.Inverse可以把轉換後圖片上的座標轉換為在原始圖片的座標。
varpointToContent =group.Inverse.Transform(point);
vartransform = group.Children[0]asScaleTransform;
if(transform.ScaleX + delta < 1)return;
transform.CenterX =pointToContent.X;
transform.CenterY =pointToContent.Y;
這樣就很大程度上減少了圖片的跳躍。但還是有小幅度的差距。
所以運用演算法可以來彌補中間的差距。具體參看第一次加入的DowheelZoom
最終圖片的放大縮小效果圖