This code allows for the phone to be used in either portrait or landscape mode. Aspect ratio is not locked, but the code could be tweaked to enforce this.
Try it out here in my WP8 Meme Maker app.
How it works
Two images sit within a grid, with the semi-transparent instance behind in z-order. A rectangle is positioned in each corner. The topmost image is clipped to a rectangle defined by dragging the rectangles around.
XAML:
<Grid> <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <Image Source="Assets/someImage.png" IsHitTestVisible="False" Opacity="0.3" ></Image> <Image Name="imgSauce" Source="Assets/someImage.png" > <Image.Clip> <RectangleGeometry x:Name="clipRect" ></RectangleGeometry> </Image.Clip> </Image> <Rectangle Name="rectTopLeft" Width="20" Height="20" Margin="-10" Fill="Yellow" HorizontalAlignment="Left" VerticalAlignment="Top" > <Rectangle.RenderTransform> <TranslateTransform></TranslateTransform> </Rectangle.RenderTransform> </Rectangle> <Rectangle Name="rectTopRight" Width="20" Height="20" Margin="-10" Fill="Yellow" HorizontalAlignment="Right" VerticalAlignment="Top" > <Rectangle.RenderTransform> <TranslateTransform></TranslateTransform> </Rectangle.RenderTransform> </Rectangle> <Rectangle Name="rectBotLeft" Width="20" Height="20" Margin="-10" Fill="Yellow" HorizontalAlignment="Left" VerticalAlignment="Bottom" > <Rectangle.RenderTransform> <TranslateTransform></TranslateTransform> </Rectangle.RenderTransform> </Rectangle> <Rectangle Name="rectBotRight" Width="20" Height="20" Margin="-10" Fill="Yellow" HorizontalAlignment="Right" VerticalAlignment="Bottom" > <Rectangle.RenderTransform> <TranslateTransform></TranslateTransform> </Rectangle.RenderTransform> </Rectangle> </Grid> </Grid>
Code Behind:
using System; using System.Windows; using Microsoft.Phone.Controls; using System.Windows.Media; using System.Windows.Shapes;
public partial class CropPage : Page { private Rectangle _draggedRect = null; public CropPage() { InitializeComponent(); var rects = new Rectangle[] { rectTopRight, rectTopLeft, rectBotRight, rectBotLeft }; Point _dragOrigin =new Point(); double origLeftPerc= 0, origRightPerc = 0, origTopPerc = 0, origBotPerc = 0; var setOrigin = new Action<Point>((p) => { _dragOrigin = p; origLeftPerc = this._clipLeftPerc; origRightPerc = this._clipRightPerc; origTopPerc = this._clipTopPerc; origBotPerc = this._clipBotPerc; }); foreach (var aRect in rects) { aRect.MouseLeftButtonDown += (s, e) => { var r = (Rectangle)s; _draggedRect = r; setOrigin( e.GetPosition(this.imgSauce)); r.CaptureMouse(); }; aRect.MouseLeftButtonUp += (s, e) => { _draggedRect = null; }; aRect.MouseMove += (s, e) => { if (_draggedRect != null) { var pos = e.GetPosition(this.imgSauce); if (s == this.rectTopLeft || s == this.rectTopRight) { // Adjust top _clipTopPerc = origTopPerc + (pos.Y - _dragOrigin.Y) / imgSauce.ActualHeight; } if (s == this.rectTopLeft || s == this.rectBotLeft) { // Adjust Left _clipLeftPerc = origLeftPerc + (pos.X - _dragOrigin.X) / imgSauce.ActualWidth; } if (s == this.rectBotLeft || s == this.rectBotRight) { // Adjust bottom _clipBotPerc = origBotPerc - (pos.Y - _dragOrigin.Y) / imgSauce.ActualHeight; } if (s == this.rectTopRight || s == this.rectBotRight) { // Adjust Right _clipRightPerc = origRightPerc - (pos.X - _dragOrigin.X) / imgSauce.ActualWidth; } this.updateClipAndTransforms(); } }; } var draggingImg = false; imgSauce.MouseLeftButtonDown += (s, e) => { setOrigin( e.GetPosition(this.imgSauce)); imgSauce.CaptureMouse(); draggingImg = true; }; imgSauce.MouseLeftButtonUp += (s, e) => { draggingImg = false; }; imgSauce.MouseMove += (s, e) => { if (draggingImg) { var pos = e.GetPosition(this.imgSauce); var xAdjust = (pos.X - _dragOrigin.X) / imgSauce.ActualWidth; var yAdjust = (pos.Y - _dragOrigin.Y) / imgSauce.ActualHeight; _clipLeftPerc = origLeftPerc + xAdjust; _clipRightPerc = origRightPerc - xAdjust; _clipTopPerc = origTopPerc + yAdjust; _clipBotPerc = origBotPerc - yAdjust; this.updateClipAndTransforms(); } }; imgSauce.SizeChanged += (x,y) => { this.updateClipAndTransforms(); }; this.updateClipAndTransforms(); } private double _clipLeftPerc, _clipRightPerc, _clipTopPerc, _clipBotPerc = 0; void updateClipAndTransforms() { // Check bounds if (_clipLeftPerc + _clipRightPerc >= 1) _clipLeftPerc = (1 - _clipRightPerc) - 0.04; if (_clipTopPerc + _clipBotPerc >= 1) _clipTopPerc = (1 - _clipBotPerc) - 0.04; if (_clipLeftPerc < 0) _clipLeftPerc = 0; if (_clipRightPerc < 0) _clipRightPerc = 0; if (_clipBotPerc < 0) _clipBotPerc = 0; if (_clipTopPerc < 0) _clipTopPerc = 0; if (_clipLeftPerc >= 1) _clipLeftPerc = 0.99; if (_clipRightPerc >= 1) _clipRightPerc = 0.99; if (_clipBotPerc >= 1) _clipBotPerc = 0.99; if (_clipTopPerc >= 1) _clipTopPerc = 0.99; // Image Clip var leftX = _clipLeftPerc * this.imgSauce.ActualWidth; var topY = _clipTopPerc * this.imgSauce.ActualHeight; clipRect.Rect = new Rect(leftX, topY, (1 -_clipRightPerc) * this.imgSauce.ActualWidth - leftX, (1 - _clipBotPerc) * this.imgSauce.ActualHeight - topY); // Rectangle Transforms ((TranslateTransform)this.rectTopLeft.RenderTransform).X = clipRect.Rect.X; ((TranslateTransform)this.rectTopLeft.RenderTransform).Y = clipRect.Rect.Y; ((TranslateTransform)this.rectTopRight.RenderTransform).X = -_clipRightPerc * this.imgSauce.ActualWidth; ((TranslateTransform)this.rectTopRight.RenderTransform).Y = clipRect.Rect.Y; ((TranslateTransform)this.rectBotLeft.RenderTransform).X = clipRect.Rect.X; ((TranslateTransform)this.rectBotLeft.RenderTransform).Y = - _clipBotPerc * this.imgSauce.ActualHeight; ((TranslateTransform)this.rectBotRight.RenderTransform).X = -_clipRightPerc * this.imgSauce.ActualWidth; ((TranslateTransform)this.rectBotRight.RenderTransform).Y = -_clipBotPerc * this.imgSauce.ActualHeight; } }
5 comments:
Really nice
Thank you very much. I have been trying to accomplish this for some time now with manual cropping. But the clipping solution works a lot smoother.
this is really interesting, as I'm searching for a way to resize and crop images at the moment.
You don't happen to have a nice way to resize/crop images for c# Windows Phone 8.1? Because that would be really awesome ... (I even had a look into the new Nokia Imaging Lib 1.2, but no luck there...)
Anon, to resize/crop in WP 8.1, use Nuget to import the WriteableBitmapEx package, and then use Crop() and Resize() functions, it's pretty straightforward. Contact me directly using contact form if you need more help. Here's how you can use Crop() on a WriteableBitmap after user has finished cropping in above control (in VB.Net):
ImageToCrop.Crop(ImageToCrop.PixelWidth * _clipLeftPerc, ImageToCrop.PixelHeight * _clipTopPerc, ImageToCrop.PixelWidth * (1 - (_clipLeftPerc + _clipRightPerc)), ImageToCrop.PixelHeight * (1 - (_clipTopPerc + _clipBotPerc)))
Post a Comment