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

Sreejith Sree 1,251 Reputation points
2021-01-20T07:48:11.563+00:00

I am using MediaPlugin(https://github.com/jamesmontemagno/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(https://github.com/stormlion227/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?

Developer technologies .NET Xamarin
{count} votes

Accepted answer
  1. Anonymous
    2021-01-20T11:52:05.063+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    First of all, please add ImageCropper.Forms.Fix.v2 nuget package to your project.

    Then, if you use AndroidX, please change the code in <Application> 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 the end, You do not need to call CrossMedia.Current.PickPhotoAsync, just execute ImageCropper directly like following code.

       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);  
               }  
    

    When you execute the code, it will let your choose like following screenshot.

    58592-image.png

    After select the image, then you can crop the image.

    58651-image.png

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

2 additional answers

Sort by: Most helpful
  1. uday kumar 1 Reputation point
    2021-06-03T18:05:35.667+00:00

    @Sreejith Sree try updated version here
    https://github.com/INHack20/ImageCropper.Forms. (use this plugin if u are targeting android 10 and above)
    The solution suggested by @Anonymous works!! i am using the same nuget in my xamarin forms application.

    1.install the nuget and write the following code in button click:

    new ImageCropper()
    {
    // PageTitle = "Test Title",
    // AspectRatioX = 1,
    // AspectRatioY = 1,
    Success = (imageFile) =>
    {
    Device.BeginInvokeOnMainThread(() =>
    {
    image.Source = ImageSource.FromFile(imageFile);
    });
    }
    }.Show(this);

    1. as u said u have an issue in IOS check In AppDelegate.cs file whether u added following line: Stormlion.ImageCropper.iOS.Platform.Init();
    0 comments No comments

  2. Miro Georgiev 1 Reputation point
    2021-11-11T21:56:42.067+00:00

    It works for me until I enable Linking for my distribution configuration. I get this error then:

    Java.Lang.RuntimeException: 'Unable to instantiate activity ComponentInfo{com.trellise.tendrl/com.theartofdev.edmodo.cropper.CropImageActivity}: java.lang.InstantiationException: java.lang.Class<com.theartofdev.edmodo.cropper.CropImageActivity> cannot be instantiated'


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.