C# 使用Xamarin.Forms访问摄像头
是否有人能给出一个简短的、自包含的示例,说明如何使用Xamarin.Forms 1.3.x访问相机?只需调用本机相机应用程序并检索结果图片就可以了。在Xamarin.Forms页面上显示实时视图将非常棒C# 使用Xamarin.Forms访问摄像头,c#,camera,xamarin.forms,xamarin.mobile,xamarin.forms.labs,C#,Camera,Xamarin.forms,Xamarin.mobile,Xamarin.forms.labs,是否有人能给出一个简短的、自包含的示例,说明如何使用Xamarin.Forms 1.3.x访问相机?只需调用本机相机应用程序并检索结果图片就可以了。在Xamarin.Forms页面上显示实时视图将非常棒 我已经尝试过使用Xamarin.Mobile和Xamarin.Forms.Labs,但我无法在这两个平台上找到任何解决方案(目前专注于Android和iOS)。在web上找到的大多数代码片段(包括stackoverflow)都不完整,例如,没有显示IMedipicker对象的实现,也没有显示拍照
我已经尝试过使用Xamarin.Mobile和Xamarin.Forms.Labs,但我无法在这两个平台上找到任何解决方案(目前专注于Android和iOS)。在web上找到的大多数代码片段(包括stackoverflow)都不完整,例如,没有显示IMedipicker对象的实现,也没有显示拍照方法的定位位置。我终于为iOS和Android创建了一个最低限度的解决方案 共享项目 首先,让我们看看共享代码。为了方便共享的
应用程序
类和平台特定代码之间的交互,我们在公共静态应用程序
中存储了一个静态实例
:
公共静态应用实例;
此外,我们将显示一个图像
,稍后将用内容填充该图像。因此,我们创建了一个成员:
readonly Image image = new Image();
在应用程序
构造函数中,我们存储实例
并创建页面内容,这是一个简单的按钮
和前面提到的图像
:
public App()
{
Instance = this;
var button = new Button {
Text = "Snap!",
Command = new Command(o => ShouldTakePicture()),
};
MainPage = new ContentPage {
Content = new StackLayout {
VerticalOptions = LayoutOptions.Center,
Children = {
button,
image,
},
},
};
}
按钮的单击处理程序调用事件ShouldTakePicture
。
它是一个公共成员,平台特定的代码部分稍后将分配给它
public event Action ShouldTakePicture = () => {};
最后,我们提供了一种显示捕获图像的公共方法:
public void ShowImage(string filepath)
{
image.Source = ImageSource.FromFile(filepath);
}
Android项目
在Android上,我们修改了main活动
。
首先,我们为捕获的图像文件定义一个路径:
static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");
在OnCreate
的末尾,我们可以使用创建的应用程序的静态实例
,并分配一个匿名事件处理程序,它将启动一个新的意图
来捕获图像:
App.Instance.ShouldTakePicture += () => {
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
StartActivityForResult(intent, 0);
};
最后但并非最不重要的一点是,我们的活动必须对结果图像作出反应。它只需将其文件路径推送到共享的ShowImage
方法
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
App.Instance.ShowImage(file.Path);
}
就这样!
只是别忘了在“AndroidManifest.xml”中设置“Camera”和“WriteExternalStorage”权限
iOS项目
对于iOS实现,我们创建一个自定义渲染器。
因此,我们添加一个新文件“CustomContentPageRenderer”,并在using语句之后添加相应的程序集属性:
[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]
CustomContentPageRenderer
继承自PageRenderer
:
public class CustomContentPageRenderer: PageRenderer
{
...
}
我们覆盖了viewdideappear
方法,并添加了以下部分
参照相机创建新的图像选择器控制器:
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
一旦引发ShouldTakePicture
事件,立即显示图像选择器控制器:
App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);
拍照后,将其保存到MyDocuments
文件夹,并调用共享ShowImage
方法:
imagePicker.FinishedPickingMedia += (sender, e) => {
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
InvokeOnMainThread(() => {
image.AsPNG().Save(filepath, false);
App.Instance.ShowImage(filepath);
});
DismissViewController(true, null);
};
最后,我们需要处理图像拍摄过程的取消:
imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
下面是如何在Xamarin窗体上跨Xamarin iOS执行此操作
这是一个很好的起点,但它需要先呈现一个页面,在该页面中,您可以为其指定UIView应用程序,以便为摄影机/照片拾取控制器提供UIView
可移植项目
公共接口ICameraProvider
{
Task TakePhotoAsync();
任务PickPhotoAsync();
}
私人司令部武官
{
var camera=wait DependencyService.Get().TakePhotoAsync();
}
iOS项目
[assembly:Xamarin.Forms.Dependency(typeof(CameraProvider))]
公共类摄像机提供者:ICameraProvider
{
专用UIImagePickerController\U imagePicker;
私人摄影师结果;
私有静态TaskCompletionSource\u tcs;
公共异步任务TakePhotoAsync()
{
_tcs=新任务完成源();
_imagePicker=new UIImagePickerController{SourceType=UIImagePickerController源类型.Camera};
_imagePicker.FinishedPickingMedia+=(发送方,e)=>
{
_结果=新摄像机结果();
var filepath=Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),“tmp.png”);
var image=(UIImage)e.Info.ObjectForKey(新NSString(“UIImagePickerControllerOriginalImage”);
_result.ImageSource=ImageSource.FromStream(()=>newmemoryStream(image.AsPNG().ToArray());
_result.ImageBytes=image.AsPNG().ToArray();
_result.FilePath=FilePath;
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true,null);
};
_imagePicker.Cancelled+=(发送方,e)=>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true,null);
};
等待UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(\u imagePicker,true);
返回等待任务;
}
公共异步任务PickPhotoAsync()
{
_tcs=新任务完成源();
_imagePicker=新UIImagePickerController
{
SourceType=UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes=UIImagePickerController.AvailableMediaTypes(UIImagePickerController源类型.PhotoLibrary)
};
_imagePicker.FinishedPickingMedia+=(发送方,e)=>
{
if(e.Info[UIImagePickerController.MediaType].ToString()=“public.image”)
{
var filepath=(e.Info[新NSString(“UIImagePickerControllerReferenceUrl”)]作为NSUrl);
var image=(UIImage)e.Info.ObjectForKey(新NSString(“UIImagePickerControllerOriginalImage”);
//var image=e.Info[UIImagePickerController.OriginalImage]作为UIImage;
_result.ImageSource=ImageSource.FromStream(()=>newmemoryStream(image.AsPNG().ToArray());
_result.ImageBytes=image.AsPNG().ToArray();
_result.FilePath=FilePath?.Pa
public interface ICameraProvider
{
Task<CameraResult> TakePhotoAsync();
Task<CameraResult> PickPhotoAsync();
}
private Command AttachImage
{
var camera = await DependencyService.Get<ICameraProvider>().TakePhotoAsync();
}
[assembly: Xamarin.Forms.Dependency(typeof(CameraProvider))]
public class CameraProvider : ICameraProvider
{
private UIImagePickerController _imagePicker;
private CameraResult _result;
private static TaskCompletionSource<CameraResult> _tcs;
public async Task<CameraResult> TakePhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
_result = new CameraResult();
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath;
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
public async Task<CameraResult> PickPhotoAsync()
{
_tcs = new TaskCompletionSource<CameraResult>();
_imagePicker = new UIImagePickerController
{
SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
};
_imagePicker.FinishedPickingMedia += (sender, e) =>
{
if (e.Info[UIImagePickerController.MediaType].ToString() == "public.image")
{
var filepath = (e.Info[new NSString("UIImagePickerControllerReferenceUrl")] as NSUrl);
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
//var image = e.Info[UIImagePickerController.OriginalImage] as UIImage;
_result.ImageSource = ImageSource.FromStream(() => new MemoryStream(image.AsPNG().ToArray()));
_result.ImageBytes = image.AsPNG().ToArray();
_result.FilePath = filepath?.Path;
}
_tcs.TrySetResult(_result);
_imagePicker.DismissViewController(true, null);
};
_imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
};
await UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewControllerAsync(_imagePicker, true);
return await _tcs.Task;
}
}
public async Task<string> TakePicture()
{
if (await AuthorizeCameraUse())
{
var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };
TaskCompletionSource<string> FinishedCamera = new TaskCompletionSource<string>();
// When user has taken picture
imagePicker.FinishedPickingMedia += (sender, e) => {
// Save the file
var filepath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "tmp.png");
var image = (UIImage)e.Info.ObjectForKey(new NSString("UIImagePickerControllerOriginalImage"));
image.AsPNG().Save(filepath, false);
// Close the window
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
// Stop awaiting
FinishedCamera.SetResult(filepath);
};
// When user clicks cancel
imagePicker.Canceled += (sender, e) =>
{
UIApplication.SharedApplication.KeyWindow.RootViewController.DismissViewController(true, null);
FinishedCamera.TrySetCanceled();
};
// Show the camera-capture window
UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(imagePicker, true, null);
// Now await for the task to complete or be cancelled
try
{
// Return the path we've saved the image in
return await FinishedCamera.Task;
}
catch (TaskCanceledException)
{
// handle if the user clicks cancel
}
}
return null;
}
public static async Task<bool> AuthorizeCameraUse()
{
var authorizationStatus = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
if (authorizationStatus != AVAuthorizationStatus.Authorized)
{
return await AVCaptureDevice.RequestAccessForMediaTypeAsync(AVMediaType.Video);
}
else
return true;
}
private TaskCompletionSource<bool> _tcs_NativeCamera;
public async Task<string> TakePicture()
{
_tcs_NativeCamera = new TaskCompletionSource<bool>();
// Launch the camera activity
var intent = new Intent(MediaStore.ActionImageCapture);
intent.PutExtra(MediaStore.ExtraOutput, Android.Net.Uri.FromFile(cameraCaptureFilePath));
NextCaptureType = stype;
StartActivityForResult(intent, SCAN_NATIVE_CAMERA_CAPTURE_ASYNC);
// Wait here for the activity return (through OnActivityResult)
var Result = await _tcs_NativeCamera.Task;
// Return the camera capture file path
return Result != Result.Canceled ? cameraCaptureFilePath : null;
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
switch (requestCode)
{
case SCAN_NATIVE_CAMERA_CAPTURE_ASYNC:
_tcs_NativeCamera.SetResult(resultCode);
break;
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
<provider android:name="android.support.v4.content.FileProvider"
android:authorities="YOUR_APP_PACKAGE_NAME.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"></meta-data>
</provider>
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Pictures" />
<external-path name="my_movies" path="Android/data/YOUR_APP_PACKAGE_NAME/files/Movies" />
</paths>
<key>NSCameraUsageDescription</key>
<string>This app needs access to the camera to take photos.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs access to photos.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs access to microphone.</string>
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
await DisplayAlert("No Camera", ":( No camera avaialble.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
PhotoSize = Plugin.Media.Abstractions.PhotoSize.Medium,
Directory = "Sample",
Name = "test.jpg"
});
if (file == null)
return;
await DisplayAlert("File Location", file.Path, "OK");