So I'm trying to achieve an affect like the native cropper when you use a PhotoChooserTask. If you aren't familiar, there's an image in the background with a border over top, and the image appears to change opacity when in and out of the border. The following code works fine, but it's not terribly smooth (the clipped image slightly lags behind the dragging movement). Is there any way to speed up the clipping or change things so that there's less lag? I have the following XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid x:Name="cropContainer" Width="375" MouseLeftButtonDown="cropContainer_MouseLeftButtonDown" MouseLeftButtonUp="cropContainer_MouseLeftButtonUp" MouseMove="cropContainer_MouseMove">
<Grid.RenderTransform>
<TranslateTransform x:Name="cropTransform" />
</Grid.RenderTransform>
<Image x:Name="fullImage" Source="{Binding Image}" Opacity=".5" />
<Image x:Name="clippedImage" Source="{Binding Image}">
<Image.Clip>
<RectangleGeometry Rect="0,0,375,267" />
</Image.Clip>
</Image>
</Grid>
</Grid>
<Border x:Name="cropBorder" Grid.Row="1" BorderThickness="1" BorderBrush="White" Opacity="1" Height="267.90571169537624660018132366274" Width="375">
</Border>
and here is the code for tracking and clipping during the sliding:
private Point _cropBorderOffset, _original, _newPosition;
private bool _moving;
private double _maxUp, _maxDown;
void Page_Loaded(object sender, RoutedEventArgs e)
{
var transform = cropBorder.TransformToVisual(Application.Current.RootVisual);
_cropBorderOffset = transform.Transform(new Point(0, 0));
_maxDown = ((fullImage.ActualHeight - cropBorder.ActualHeight) / 2);
_maxUp = -_maxDown;
var rect = (clippedImage.Clip as RectangleGeometry).Rect;
(clippedImage.Clip as RectangleGeometry).Rect = new Rect(rect.X, (fullImage.ActualHeight / 2) - 134, rect.Width, rect.Height);
}
private void cropContainer_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
cropContainer.CaptureMouse();
_original = e.GetPosition(cropBorder);
_moving = true;
}
private void cropContainer_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
cropContainer.ReleaseMouseCapture();
_moving = false;
}
private void cropContainer_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
_newPosition = e.GetPosition(cropBorder);
if(_moving)
{
var deltaY = _newPosition.Y - _original.Y;
var transform = fullImage.TransformToVisual(Application.Current.RootVisual);
var fullImageOffset = transform.Transform(new Point(0, 0));
var marginTop = deltaY;
//Too far down
if (marginTop > _maxDown)
{
marginTop = _maxDown;
}
//Too far up
else if (marginTop < _maxUp)
{
marginTop = _maxUp;
}
cropTransform.Y = marginTop;
var rect = (clippedImage.Clip as RectangleGeometry).Rect;
(clippedImage.Clip as RectangleGeometry).Rect = new Rect(rect.X, _cropBorderOffset.Y - fullImageOffset.Y, rect.Width, rect.Height);
}
}
Instead of drawing the image twice, once with clipping and once without, could you not simply draw semi-transparent rectangles to block out the sides and draw a white outlined for the center? That should reduce lag considerably.
You could then use the left, top, width and height of the clipping rectangle once the position is chosen to actually do the crop in-memory.