Xamarin forms:如何在从图库或相机中选择图片后实现图像裁剪
Xamarin forms: How to implement image cropping after selecting a picture from gallery or camera
我正在使用 MediaPlugin 打开相机和图库以 select 图片。在 select 拍摄图片后,我需要在将其设置到 UI 之前对其进行裁剪。我在相机里试过 AllowCropping = true
,但它只对 windows 和 ios 有效。对于 android 中的相机和所有平台(android、ios 和 windows)中的图库,没有裁剪选项。
我尝试了 ImageCropper.Forms 包来实现图像裁剪功能。
我的代码:
//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);
}
}
我已经按照博客完成了所有操作,但是当我 运行 遇到以下异常时。
[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
不知道这背后的问题是什么。有没有其他简单的包来实现图像裁剪功能?
首先,将ImageCropper.Forms.Fix.v2 nuget 包添加到您的项目中。
那么,如果您使用AndroidX
,请更改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>
另外,您不需要调用CrossMedia.Current.PickPhotoAsync,直接像下面的代码一样执行ImageCropper即可。
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);
}
}
}
}
我正在使用 MediaPlugin 打开相机和图库以 select 图片。在 select 拍摄图片后,我需要在将其设置到 UI 之前对其进行裁剪。我在相机里试过 AllowCropping = true
,但它只对 windows 和 ios 有效。对于 android 中的相机和所有平台(android、ios 和 windows)中的图库,没有裁剪选项。
我尝试了 ImageCropper.Forms 包来实现图像裁剪功能。
我的代码:
//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);
}
}
我已经按照博客完成了所有操作,但是当我 运行 遇到以下异常时。
[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
不知道这背后的问题是什么。有没有其他简单的包来实现图像裁剪功能?
首先,将ImageCropper.Forms.Fix.v2 nuget 包添加到您的项目中。
那么,如果您使用AndroidX
,请更改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>
另外,您不需要调用CrossMedia.Current.PickPhotoAsync,直接像下面的代码一样执行ImageCropper即可。
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);
}
}
}
}