WindowsPhone: Image crop with rectangle (C#-XAML)
Introduction
With photo photo apps in particular, we may need to crop the image using a rectangle. That is a somewhat difficult to implement using the code. This article explains anapproach using WriteableBitmap.
Requirements
This sample is targeted to the Windows Phone 7.1 OS.
Description
In this sample, the image is cropped using a rectangle and then saved it to "MedialLibrary". So let's start the development by the following procedure.
Step 1
- Open Visual Studio.
- Create a new project named for example "ImageCropWithRect".
Step 2
**
**Open MainPage.xaml and add the following XMAL code.
XAML
- <Grid x:Name="LayoutRoot" Background="White">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto"/>
- <RowDefinition Height="*"/>
- </Grid.RowDefinitions>
- <!--ContentPanel - place additional content here-->
- <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"></Grid>
- <StackPanel Orientation="Vertical">
- <TextBlock HorizontalAlignment="Center" FontSize="30" Text="Image Crop with Recatngle" Foreground="#FF17CDC4"/>
- <Rectangle Margin="0,5,0,0" Height="0.5" Fill="#FF17CDC4" />
- <Canvas Height="300" Margin="5" x:Name="canvas" Width="480">
- <!--Original Image-->
- <Image Width="470" Stretch="Uniform" Name="OriginalImage" Source="/Assets/Nature1.jpg" MouseLeftButtonDown="OriginalImage_MouseLeftButtonDown" MouseLeftButtonUp="OriginalImage_MouseLeftButtonUp" MouseMove="OriginalImage_MouseMove"/>
- <!--Rectangle to be used for Crop Original Image-->
- <Rectangle x:Name="rect" StrokeThickness="4" Stroke="#FFEA18A7"></Rectangle>
- </Canvas>
- <Button Name="CropBtn" Content="CropImage" Background="#FF3CD3CC" Click="CropBtn_Click" />
- <!--Cropped Image-->
- <Image Stretch="None" Name="FinalCroppedImage"/>
- <Button Name="SaveBtn" Visibility="Collapsed" Content="Save to Gallery" Background="#FF3CD3CC" Click="SaveBtn_Click" />
- </StackPanel>
- </Grid>
In the code above in the Canvas layout I added two child controls (OriginalImage and rect). Here "rect" is used for cropping the "OriginalImage" with a rectangle shape. So when we click "CropBtn", the selected rectangle area of the original image source will be set to "FinalCroppedImage". And the cropped image will be saved to the media library when you click on "SaveBtn". You will be able to understand the code above by proceeding to the further important steps.
Step 3
To crop the image, we need the (x, y) co-ordinates and the height and width of the cropped image. On the MouseEvents of "OriginalImage" get the Poin1 and Point2 values to crop the image with a rectangle.
C# Code
- //Mouse Move
- private void OriginalImage_MouseMove(object sender, MouseEventArgs e)
- {
- Point2 = e.GetPosition(OriginalImage);
- }
- //Mouse Up
- private void OriginalImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
- {
- Point2 = e.GetPosition(OriginalImage);
- }
- //Mouse Down
- private void OriginalImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
- {
- Point1 = e.GetPosition(OriginalImage);//Set first touchable coordinates as point1
- Point2 = Point1;
- rect.Visibility = Visibility.Visible;
- }
And draw the dynamic rectangle on the mouse move of "OriginalImage".
C# Code
- Point Point1, Point2;
- public MainPage()
- {
- InitializeComponent();
- //fire when render frame
- CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
- }
- private void CompositionTarget_Rendering(object sender, EventArgs e)
- {
- //Used for rendering the cropping rectangle on the image.
- rect.SetValue(Canvas.LeftProperty, (Point1.X < Point2.X) ? Point1.X : Point2.X);
- rect.SetValue(Canvas.TopProperty, (Point1.Y < Point2.Y) ? Point1.Y : Point2.Y);
- rect.Width = (int)Math.Abs(Point2.X - Point1.X);
- rect.Height = (int)Math.Abs(Point2.Y - Point1.Y);
- }
Step 4
Be sure to set "WriteableBitmap" with the OrgianlImage on PageLoad.
C# Code
- WriteableBitmap WB_CapturedImage;//for original image
- WriteableBitmap WB_CroppedImage;//for cropped image
- public MainPage()
- {
- InitializeComponent();
- //fire when render frame
- CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
- this.Loaded+=MainPage_Loaded;
- }
- private void MainPage_Loaded(object sender, RoutedEventArgs e)
- {
- //Set WriteableBitmap with OrgianlImage
- WB_CapturedImage = new WriteableBitmap(OriginalImage, null);
- }
Step 5
Get the cropped image area when "CropBtn" is clicked and set it to "FinalCroppedImage".
C# Code
- private void CropBtn_Click(object sender, RoutedEventArgs e)
- {
- // Get the size of the source image
- double originalImageWidth = WB_CapturedImage.PixelWidth;
- double originalImageHeight = WB_CapturedImage.PixelHeight;
- // Get the size of the image when it is displayed on the phone
- double displayedWidth = OriginalImage.ActualWidth;
- double displayedHeight = OriginalImage.ActualHeight;
- // Calculate the ratio of the original image to the displayed image
- double widthRatio = originalImageWidth / displayedWidth;
- double heightRatio = originalImageHeight / displayedHeight;
- // Create a new WriteableBitmap. The size of the bitmap is the size of the cropping rectangle
- // drawn by the user, multiplied by the image size ratio.
- WB_CroppedImage = new WriteableBitmap((int)(widthRatio * Math.Abs(Point2.X - Point1.X)), (int)
- (heightRatio * Math.Abs(Point2.Y - Point1.Y)));
- // Calculate the offset of the cropped image. This is the distance, in pixels, to the top left corner
- // of the cropping rectangle, multiplied by the image size ratio.
- int xoffset = (int)(((Point1.X < Point2.X) ? Point1.X : Point2.X) * widthRatio);
- int yoffset = (int)(((Point1.Y < Point2.Y) ? Point1.Y : Point2.X) * heightRatio);
- // Copy the pixels from the targeted region of the source image into the target image,
- // using the calculated offset
- if (WB_CroppedImage.Pixels.Length > 0)
- {
- for (int i = 0; i < WB_CroppedImage.Pixels.Length; i++)
- {
- int x = (int)((i % WB_CroppedImage.PixelWidth) + xoffset);
- int y = (int)((i / WB_CroppedImage.PixelWidth) + yoffset);
- WB_CroppedImage.Pixels[i] = WB_CapturedImage.Pixels[y * WB_CapturedImage.PixelWidth + x];
- }
- // Set the source of the image control to the new cropped image
- FinalCroppedImage.Source = WB_CroppedImage;
- SaveBtn.Visibility = Visibility.Visible;
- }
- else
- {
- FinalCroppedImage.Source = null;
- SaveBtn.Visibility = Visibility.Collapsed;
- }
- //rect.Visibility = Visibility.Collapsed;
- }
Step 6
Finally save the cropped image to the MediaLibary when we click on "SaveBtn".
C# Code
- private void SaveBtn_Click(object sender, RoutedEventArgs e)
- {
- try
- {
- String tempJPEG = "CroppedImage.jpg";
- //Create virtual store and file stream. Check for duplicate tempJPEG files.
- var myStore = IsolatedStorageFile.GetUserStoreForApplication();
- if (myStore.FileExists(tempJPEG))
- {
- myStore.DeleteFile(tempJPEG);
- }
- IsolatedStorageFileStream myFileStream = myStore.CreateFile(tempJPEG);
- //Encode the WriteableBitmap into JPEG stream and place into isolated storage.
- Extensions.SaveJpeg(WB_CroppedImage, myFileStream, WB_CroppedImage.PixelWidth, WB_CroppedImage.PixelHeight, 0, 85);
- myFileStream.Close();
- //Create a new file stream.
- myFileStream = myStore.OpenFile(tempJPEG, FileMode.Open, FileAccess.Read);
- //Add the JPEG file to the photos library on the device.
- MediaLibrary library = new MediaLibrary();
- Picture pic = library.SavePicture("SavedPicture.jpg", myFileStream);
- MessageBox.Show("Cropped image saved successfully to media library!");
- myFileStream.Close();
- }
- catch
- {
- MessageBox.Show("Error on image saving!");
- }
- }
Note:
You need to add a reference to the Microsoft.Xna.Framework in the references of your project.
Ensure you have the ID_CAP_MEDIALIB turned on in your WMAppManifest.xml file.
Result
Summary
From this article we have learned how to crop an image with a rectangle in Windows Phone.
This article is also available at my original blog and also source code is available @ link.