Cropping Images in Windows Phone 7

Recently I had to do some work in cropping an image programmatically through Windows Phone 7, and while it’s not hard, it wasn’t immediately obvious how to do it, so I thought I would share.

While the Clip property does seem to crop images, the image still remains its original size, making it not a true “crop”. Instead, we’ll use the WriteableBitmap class found as part of Silverlight.

WriteableBitmap takes in a few constructors, including a fixed pixel width/height constructor, and once constructed, you call the .Render() method and pass in UIElements (so that’s Textblocks, Buttons, etc – but most importantly: Image), and a Transform if you want to resize/translate your UIElement.

Therefore, to crop an image, we just need to create a WriteableBitmap with the size of the target cropped area, and pass in a transform that will move the Image to the right area within the crop surface.

After rendering all the UIElements required on the WriteableBitmap, we need to call the .Invalidate() method to force it to redraw its contents and display properly.

Here’s some sample code that crops an image (provided as stream data from, say, a WebService class) to a square:

[sourcecode language="csharp"]
internal static Stream CropSquare(Stream stream)
{
//turn stream into bitmapimage object
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);

//calculate bounding box
int iOriginalWidth = bitmapImage.PixelWidth;
int iOriginalHeight = bitmapImage.PixelHeight;

if (iOriginalWidth == iOriginalHeight)
{
//image is already square – return it
return stream;
}

int smallestSide = (iOriginalHeight < iOriginalWidth) ? iOriginalHeight : iOriginalWidth;

//generate temporary control to render image
Image temporaryImage = new Image { Source = bitmapImage, Width = iOriginalWidth, Height = iOriginalHeight };

//create writeablebitmap
WriteableBitmap wb = new WriteableBitmap(smallestSide, smallestSide);
wb.Render(temporaryImage, new TranslateTransform { X = (iOriginalWidth – smallestSide) / -2, Y = (iOriginalHeight – smallestSide) / -2 });
wb.Invalidate();

//get stream from writeablebitmap
Stream streamResizedImage = new MemoryStream(); //will need to be disposed by whatever is using this method
wb.SaveJpeg(streamResizedImage, smallestSide, smallestSide, 0, 70);
return streamResizedImage;
}
[/sourcecode]

As shown above, we can resize, skew and pretty much do anything we want to an image by passing in the correct combination of translations to the render method of the WriteableBitmap. Note that to convert the WriteableBitmap to a stream, the .SaveJpeg() method was called. I’m not entirely sure which version of Silverlight supports this, or whether it’s a Windows Phone 7 specific extension as I couldn’t find it on MSDN, but it works in the RTM WP7 tools so I imagine it’s not going to be a problem.

Here is a sample project that I made while working all this out, which demonstrates the code I provided in this post in use.

Hope that was helpful!

3 thoughts on “Cropping Images in Windows Phone 7

  1. Chris

    This is exactly what I was looking for! I was doing the same thing, but was forgetting to assign a width and height to my temporary image. Arggh.

    You’re setting temporaryImage.Width and Height twice (in the constructor and below) but it doesn’t make much of a difference. many thanks!

    Reply
  2. Kris

    Thanks for the post Henry.

    Additionally, if anyone’s like me and wants to perform a scale, skew, rotate and translate in one step, you can use CompositeTransform or TransformGroup in place of TranslateTransform.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>