Silverlight 3 introduces the WriteableBitmap class and with it, the ability to crop an image programmatically on the client!
All you need to do is create a new instance of the WritableBitmap class as your destination (supplying the dimensions in the constructor). Then create or acquire another instance of the WriteableBitmap class fully loaded with an image (among other ways, you can do this by creating a BitmapSource object from a stream via .SetSource and passing that BitmapSource instance into the constructor of a new WriteableBitmap)
Once you have your source and destination WriteableBitmap classes, just retrieve one pixel at a time from the source instance and set that pixel on a destination instance. The pixels are stored in a property on the object call Pixels which is a 1 dimensional array. Geting the index of a given pixel in an array is simple: index = x + y * width.
In my first pass, I just looped thru pixel by pixel. This was fast but not as fast as using Array.Copy (almost twice as fast)…
private static WriteableBitmap CropImage(WriteableBitmap Source, int XOffset, int YOffset, int Width, int Height)
{
int SourceWidth = Source.PixelWidth;
WriteableBitmap Result = new WriteableBitmap(Width, Height);
for (int y = 0; y <= Height – 1; y++)
{
int SourceIndex = XOffset + (YOffset + y) * SourceWidth;
int DestIndex = y * Width;
Array.Copy(Source.Pixels, SourceIndex, Result.Pixels, DestIndex, Width);
}
return Result;
}
The result (a WriteableBitmap) can then simply be used as the source of an Image control to display your cropped image.
Note: WriteableBitmap.PixelWidth is expensive. Be sure to call it only once if possible.
Possible Improvement: Had the source width and destination width been the same I could have done it in a single call to Array.Copy and presumably made it even faster.
It’s high time that web developers are able to do complicated tasks on the client and not forced to use the server just because the client-side platform doesn’t support it. We’re still not all the way there yet but Silverlight gets us a lot closer than anything before it.
Cropping an image in Silverlight 3 « Programmer Payback…
Thank you for submitting this cool story – Trackback from NewsPeeps…
Thanks for the useful post. But shouldn’t it be:
int SourceIndex = XOffset +( YOffset + y) * SourceWidth;
I have written on the same topic but found this after writing. Interesting to find a different approach to achieve the same thing.
http://blog.blueboxes.co.uk/2009/08/22/how-to-crop-instead-of-clip-in-silverlight/
Rahul, good eye. I had refactored and forgot to re-add the parenthesis.
John, thanks for the link! Interesting approach using the clip property and forcing that result to a writable bitmap. I wonder how the two options compare performance wise.
Just a general note to other readers about the clip property:
Cropping an image via the clip property does have the same visual effect but there is one key difference, the entire image is still loaded in memory. This can help performance if you need to change your clipping region at runtime but it can hurt performance if you need to break a single image up into many smaller images.