Introduction
I was looking for a crop control in Silverlight when I found article Silverlight Extended Canvas Control to Crop Images. The control described in it impressed me by its simplicity and usefullness. Because I needed a crop control with movable edges I started to write my own version.
Main features are:
- Sizable/movable crop area
- Loaded image is fitted to the dimensions of the container control
- The crop function crops the original image, preserving the resolution of the original image
- Possible to set aspect ratio
- Possible to set minimal crop area size
- Image Source and Aspect Ratio are dependency objects, they are bindable.
In this picture the aspect ratio was set to 4:3.
How It Works
In the article mentioned above the dimensions of the clip area are kept in a Rectangle
UI element. Because I needed pointers to indicate the places where the crop field can be modified I decided to store crop field dimensions in a custom object called ClipRect
(it it almost the same as Rect
, but the Right
and Bottom
properties are not readonly, and contains some additional features) and added four images to visualize the crop pointers. At first I used a fifth image to visualize the crop area move functionality, but later I decided to solve it with a Cursor.Hand
pointer. To emphasize the part of the image that is selected to crop I added two instances of the croppable image to the control, one as an inverse mask to the background, and one as a foreground. Then I bound the dimensions of the Clip
of the foreground image to imitate a crop behaviour. The control is able to maintain predefined aspect ratios as well. In this case the horizontal change of crop field width is calculated from the vertical shift of the cursor.
Using the code
Simply place a CropControl
control to your XAML:
<c:CropControl x:Name="cropControl" Width="500" Height="390" MinimalCropSize="60.0"
AspectRatio="None" />
Set the source property (it can be bound as well):
BitmapImage bmp = new BitmapImage();
FileStream fs = imgOpenFileDialog.File.OpenRead();
bmp.SetSource(fs);
cropControl.Source = LoadFromBitmapImage(bmp);
And crop the image:
imgCropped.Source = cropControl.CropImage();
Points of Interest
I found an article about Making Value Converters More Accessible in Markup
that I found very helpful.
I struggled a lot with Data Binding in xaml code. Finally I realized that the functionality I missed is called Multibinding, which exists in WPF but not in Silverlight.
I also had a lot of problem from the fact that ActualWidth
/Height
of the image is only calculated sometimes after the
ImageOpened
event, and I needed this value to position the crop pointers, so I decided to set the image dimensions from codebehind and not to let the framework to calculate it.
Any suggestions to make the code better appretiated.
Reference
Two pictures in the library are from Wikipedia:
Budapest from Gellert Hill
Budapest Montage
History
- v. 1.1: 04/27/2012. Open File Dialog added to test project
- v. 1.0: 04/27/2012.