Search code examples
xamarin.formscameragallery

Xamarin forms: How to implement image cropping after selecting a picture from gallery or camera


I am using MediaPlugin for opening Camera and Gallery to select pictures. After selecting a picture, I need to crop it before setting it on the UI. I have tried AllowCropping = true in the camera, but it works only for windows and ios. For the camera in android and gallery on all platforms (android, ios, and windows) there is no crop option.

I tried ImageCropper.Forms package to implement the image cropping feature.

My Code:

//Camera
async void CameraClick()
{
    try
    {
        await CrossMedia.Current.Initialize();

        if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
        {
            if (!Utility.IsWindowsDevice())
            {
                await DisplayAlert("Alert", "No camera available.", "Ok");
            }
            else
            {
                ShowAlert("No camera available.");
            }
            return;
        }

        _mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
        {
            Directory = "Sample",
            Name = "test.jpg",
            AllowCropping = true,
            PhotoSize = PhotoSize.Medium
        });

        if (_mediaFile == null)
            return;
        profilephoto.Source = ImageSource.FromStream(() =>
        {
            isPicture = true;
            isAvatar = false;
            if (Device.OS == TargetPlatform.iOS)
            {
                return _mediaFile.GetStreamWithImageRotatedForExternalStorage();
            }
            else
            {
                return _mediaFile.GetStream();
            }
        });

        new ImageCropper()
        {
            PageTitle = "Test Title",
            AspectRatioX = 1,
            AspectRatioY = 1,
            CropShape = ImageCropper.CropShapeType.Rectangle,
            SelectSourceTitle = "Select source",
            TakePhotoTitle = "Take Photo",
            PhotoLibraryTitle = "Photo Library",
            Success = (imageFile) =>
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    profilephoto.Source = ImageSource.FromFile(imageFile);
                });
            }
        }.Show(this);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Exception:>" + ex);
    }
}

//Gallery
async void GalleryClick()
{
    try
    {
        await CrossMedia.Current.Initialize();

        if (!CrossMedia.Current.IsPickPhotoSupported)
        {
            if (!Utility.IsWindowsDevice())
            {
                await DisplayAlert("Alert", "No photos available.", "Ok");
            }
            else
            {
                ShowAlert("No photos available.");
            }
            return;
        }

        _mediaFile = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
        {
            PhotoSize = PhotoSize.Medium
        });

        if (_mediaFile == null)
            return;
        profilephoto.Source = ImageSource.FromStream(() =>
        {
            isPicture = true;
            isAvatar = false;
            return _mediaFile.GetStream();
        });

        new ImageCropper()
        {
            PageTitle = "Test Title",
            AspectRatioX = 1,
            AspectRatioY = 1,
            CropShape = ImageCropper.CropShapeType.Rectangle,
            SelectSourceTitle = "Select source",
            TakePhotoTitle = "Take Photo",
            PhotoLibraryTitle = "Photo Library",
            Success = (imageFile) =>
            {
                Device.BeginInvokeOnMainThread(() =>
                {
                    profilephoto.Source = ImageSource.FromFile(imageFile);
                });
            }
        }.Show(this);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Exception:>" + ex);
    }
}

I have done everything as per the blog, But when I run getting the below exception.

[0:] Exception:>System.MissingMethodException: Method not found: System.Threading.Tasks.Task`1<Plugin.Media.Abstractions.MediaFile> Plugin.Media.Abstractions.IMedia.TakePhotoAsync(Plugin.Media.Abstractions.StoreCameraMediaOptions) at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start[TStateMachine] (TStateMachine& stateMachine) [0x0002c] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:84 at Stormlion.ImageCropper.ImageCropper.Show (Xamarin.Forms.Page page, System.String imageFile) [0x00033] in <548dc893a11b47fe908c9c3d7f4a39ba>:0 at ProjectName.Pages.ProfilePage.GalleryClick () [0x00227] in F:\My Projects\Xamarin\ProjectName\ProjectName\ProjectName\Pages\ProfilePage.xaml.cs:554

[0:] Exception:>System.MissingMethodException: Method not found: System.Threading.Tasks.Task`1<Plugin.Media.Abstractions.MediaFile> Plugin.Media.Abstractions.IMedia.TakePhotoAsync(Plugin.Media.Abstractions.StoreCameraMediaOptions) at System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Start[TStateMachine] (TStateMachine& stateMachine) [0x0002c] in /Users/builder/jenkins/workspace/archive-mono/2020-02/android/release/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:84 at Stormlion.ImageCropper.ImageCropper.Show (Xamarin.Forms.Page page, System.String imageFile) [0x00033] in <548dc893a11b47fe908c9c3d7f4a39ba>:0 at ProjectName.Pages.ProfilePage.CameraClick () [0x0025b] in F:\My Projects\Xamarin\ProjectName\ProjectName\ProjectName\Pages\ProfilePage.xaml.cs:515 01-20 12:21:23.149 D/Mono (11820): Requesting loading reference 1 (of 3) of System.Collections.dll

Don't know what is the issue behind this. Is there any other simple package for implementing the image cropping feature?


Solution

  • First of all, Add ImageCropper.Forms.Fix.v2 nuget package to your project.

    Then, if you use AndroidX, please change the code in tag of AndroidManifest.xaml

    <application android:label="ImageCropDemo.Android" android:theme="@style/MainTheme">
        <activity android:name="com.theartofdev.edmodo.cropper.CropImageActivity"
                  android:theme="@style/Base.Theme.AppCompat"/>
        <provider android:name="androidx.core.content.FileProvider"
              android:authorities="${applicationId}.fileprovider"
              android:exported="false"
              android:grantUriPermissions="true">
          <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
                           android:resource="@xml/file_paths"></meta-data>
        </provider>
        </application>
    

    In addition, You do not need to call CrossMedia.Current.PickPhotoAsync, just execute ImageCropper directly like following code.

    namespace ImageCropDemo
    {
        public partial class MainPage : ContentPage
        {
            private MediaFile _mediaFile;
            public MainPage()
            {
                InitializeComponent();
    
     
    
                CrossMedia.Current.Initialize();
    
     
    
            }
            protected  void OnClickedRectangle(object sender, EventArgs e)
            {
                new ImageCropper()
                {
                    //                PageTitle = "Test Title",
                    //                AspectRatioX = 1,
                    //                AspectRatioY = 1,
                    Success = (imageFile) =>
                    {
                        Device.BeginInvokeOnMainThread(() =>
                        {
                            image.Source = ImageSource.FromFile(imageFile);
                        });
                    }
                }.Show(this);
            }
            async void OpenCamera(object sender, EventArgs args)
            {
                try
                {
                    await CrossMedia.Current.Initialize();
    
     
    
                    //if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
                    //{
                    //    await DisplayAlert("Alert", "No camera available.", "Ok");
                    //    return;
                    //}
    
     
    
                    //_mediaFile = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
                    //{
                    //    Directory = "Sample",
                    //    Name = "test.jpg",
                    //    AllowCropping = true,
                    //    PhotoSize = PhotoSize.Medium
                    //});
    
     
    
                    //if (_mediaFile == null)
                    //    return;
                    //image.Source = ImageSource.FromStream(() =>
                    //{
                    //    if (Device.OS == TargetPlatform.iOS)
                    //    {
                    //        return _mediaFile.GetStreamWithImageRotatedForExternalStorage();
                    //    }
                    //    else
                    //    {
                    //        return _mediaFile.GetStream();
                    //    }
                    //});
    
     
    
                    new ImageCropper()
                    {
                        PageTitle = "Test Title",
                        AspectRatioX = 1,
                        AspectRatioY = 1,
                        CropShape = ImageCropper.CropShapeType.Rectangle,
                        SelectSourceTitle = "Select source",
                        TakePhotoTitle = "Take Photo",
                        PhotoLibraryTitle = "Photo Library",
                        Success = (imageFile) =>
                        {
                            Device.BeginInvokeOnMainThread(() =>
                            {
                                image.Source = ImageSource.FromFile(imageFile);
                            });
                        }
                    }.Show(this);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("CameraException:>" + ex);
                }
            }
            string imagefile;
            async void OpenGallery(object sender, EventArgs args)
            {
                try
                {
                    await CrossMedia.Current.Initialize();
    
     
    
                    //if (!CrossMedia.Current.IsPickPhotoSupported)
                    //{
                    //    await DisplayAlert("Alert", "No photos available.", "Ok");
                    //    return;
                    //}
    
     
    
                    //_mediaFile = await CrossMedia.Current.PickPhotoAsync(new PickMediaOptions
                    //{
                    //    PhotoSize = PhotoSize.Medium
                    //});
    
     
    
                    //if (_mediaFile == null)
                    //    return;
    
     
    
                    //image.Source = ImageSource.FromStream(() =>
                    //{
                    //    return _mediaFile.GetStream();
                    //});
    
     
    
                    new ImageCropper()
                    {
                        PageTitle = "Test Title",
                        AspectRatioX = 1,
                        AspectRatioY = 1,
                        CropShape = ImageCropper.CropShapeType.Rectangle,
                        SelectSourceTitle = "Select source",
                        TakePhotoTitle = "Take Photo",
                        PhotoLibraryTitle = "Photo Library",
                        Success = (imageFile) =>
                        {
                            Device.BeginInvokeOnMainThread (() =>
                            {
                                image.Source = ImageSource.FromFile(imageFile);
    
     
    
                                imagefile = imageFile;
                            });
                        }
                    }.Show(this);
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine("GalleryException:>" + ex);
                }
            }
        }
    }