[WP 7.5] 結合Toolkit GestureService 進行圖片裁切

[WP 7.5] 結合Toolkit GestureService 進行圖片裁切

有時候會需要結合Gesture

將裁切框移動以及做出Pinch 來放大縮小裁切框進行裁切

了解一下Windows Phone Toolkit 的Gesture後

以下是我的作法

首先在xaml處引入命名空間,這樣才可以使用Toolkit

 


xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit" 

 

裁切框以及圖片設置如下,裁切框採用Border才可以設定框線樣式,暫時先以這種方式處理

另外將GestureService.GestureListener置入,並且添加幾個關鍵事件

 


<Canvas x:Name="CanvasImg" Width="480" Height="720" VerticalAlignment="Top">
    <Image x:Name="oriPhoto" Canvas.ZIndex="1" Canvas.Left="0" Canvas.Top="0" Stretch="Fill" Width="480" Height="720"/>
    <Border x:Name="BorderCut" Canvas.ZIndex="2" Width="200" Height="200" BorderBrush="Red" BorderThickness="2" Canvas.Left="0" Canvas.Top="0" Background="Green" Opacity="0.3">
        <Border.RenderTransform>
            <CompositeTransform x:Name="transform"/>
        </Border.RenderTransform>
        <toolkit:GestureService.GestureListener>
            <toolkit:GestureListener 
                        DragDelta="OnDragDelta" DragCompleted="OnDragCompleted"                        
                        PinchDelta="OnPinchDelta" PinchCompleted="OnPinchCompleted"/>
             </toolkit:GestureService.GestureListener>
    </Border>    
</Canvas>

外觀設定好了

接下來來設定各個事件

首先先加入裁切框的暫存座標變數x y


private double x;
private double y; 

並且在建構式將xy設為0,表示初始裁切框的位置在座標x=0 y=0的地方,這邊是依據xaml的設定,如果有設Canvas.Top 或者 Canvas.Left就要調整一下


public PhotoProc()
{
      InitializeComponent();
      x = 0;
      y = 0;
}

接下來說明移動的事件

OnDragDelta為在手指移動的時候的處理事件,這邊加入裁切框的移動

OnDragCompleted為在手指移動完成要處理的事件,由於BorderCut裁切框放在CanvasImg中,

為了確保座標都可以保持在左上角,所以我就將他們的座標進行處理


private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
{
      transform.TranslateX += e.HorizontalChange;
      transform.TranslateY += e.VerticalChange;            
}

private void OnDragCompleted(object sender, DragCompletedGestureEventArgs e)
{
      Point CanvasP = e.GetPosition(CanvasImg);
      Point BorderP = e.GetPosition(BorderCut);
      x = CanvasP.X - BorderP.X;
      y = CanvasP.Y - BorderP.Y;
}

 

接下來說明Pinch縮放的事件,這邊我採取固定縮放,並沒有角度的改變。

OnPinchDelta為在手指縮放的時候的處理事件,這邊加入裁切框比例的變化

OnPinchCompleted為在手指縮放完成要處理的事件

 


private void OnPinchDelta(object sender, PinchGestureEventArgs e)
{
      transform.ScaleX = transform.ScaleY = e.DistanceRatio;
}

private void OnPinchCompleted(object sender, PinchGestureEventArgs e)
{
      transform.ScaleX = transform.ScaleY = 1;
      double change = e.DistanceRatio;
      BorderCut.Width *= change;
      BorderCut.Height *= change;
}

以下的做法是要將縮放比例回到比例1,讓下一次的縮放不會受到這次的影響


transform.ScaleX = transform.ScaleY = 1;

並且依據改變的比例來實際變換裁切框的大小

 

最後處理裁切後的圖片儲存將裁切的圖片以WriteableBitmap來作為處理後的物件

因為主要處理正方形裁切結果所以我用RetangleGeometry的方式來進行裁切,所以Size處都設同樣的長度


Canvas tmpCanvas = new Canvas();
BitmapImage bitimg = new BitmapImage();
bitimg.UriSource = new Uri("/Dragon.png", UriKind.Relative);
Image img = new Image();
img.Source = bitimg;            
tmpCanvas.Children.Add(img);
tmpCanvas.Width = oriPhoto.Width;
tmpCanvas.Height = oriPhoto.Height;
img.Width = oriPhoto.Width;
img.Height = oriPhoto.Height;
img.Stretch = Stretch.Fill;
RectangleGeometry rectangleGeometry = new RectangleGeometry();
Point point = new Point(x, y);
Size size = new Size(BorderCut.Width, BorderCut.Width);            
rectangleGeometry.Rect = new Rect(point,size);
tmpCanvas.Clip = rectangleGeometry;

//加上裁切結果的位置校正,讓圖片可以對齊左上角
TranslateTransform cuttransform = new TranslateTransform();
cuttransform.X = -x;
cuttransform.Y = -y;
TransformGroup transgroup = new TransformGroup();
transgroup.Children.Add(cuttransform);
WriteableBitmap wbitmap = new WriteableBitmap(tmpCanvas, transgroup);      
WriteableBitmap bitmap = new WriteableBitmap(tmpCanvas, null);