Accès Caméra avec Xamarin.Forme

est-ce que quelqu'un est capable de donner un exemple bref et complet sur la façon d'accéder à la caméra avec Xamarin.Les formes 1.3.x? Appeler simplement l'application caméra native et récupérer l'image résultante serait génial. Affichage d'une vue en direct sur le Xamarin.La page des formulaires serait géniale!

j'ai déjà essayé la Xamarine.Mobile et Xamarin.Forme.Labs, mais je n'ai pas pu obtenir de solution pour travailler sur les deux plates-formes (en se concentrant sur Android et iOS pour l'instant). La plupart des extraits de code trouvés sur le web (y compris stackoverflow) sont incomplets, par exemple ne pas montrer la mise en œuvre d'un objet IMediaPicker ou où ancrer la méthode pour prendre des photos.

29
demandé sur Falko 2015-01-29 08:27:18

4 réponses

j'ai finalement créé une solution minimale pour iOS et Android.

Le projet partagé

tout d'abord, regardons le code partagé. Pour une interaction facile entre le partage App la classe et de la plate-forme de code spécifiques nous stockons un statique Instance dans le public static App:

public static App Instance;

de plus, nous afficherons un Image, qui sera rempli de contenu plus tard. Nous avons donc créer un membre:

readonly Image image = new Image();

dans les App constructeur nous stockons les Instance et créer le contenu de la page, qui est un simple button et de ladite 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,
           },
       },
   };
}

le gestionnaire de clics du bouton appelle l'événement ShouldTakePicture. Il est un membre public et les parties de code spécifiques à la plate-forme lui assigneront plus tard.

public event Action ShouldTakePicture = () => {};

enfin, nous proposons une méthode publique pour afficher l'image capturée:

public void ShowImage(string filepath)
{
    image.Source = ImageSource.FromFile(filepath);
}

Le projet Android

sur Android nous modifions le MainActivity. Tout d'abord, nous définissons un chemin pour le fichier image capturé:

static readonly File file = new File(Environment.GetExternalStoragePublicDirectory(Environment.DirectoryPictures), "tmp.jpg");

À la fin de OnCreate nous pouvons utiliser le statique Instance du App et assigner un gestionnaire d'événements anonyme, qui lancera un nouveau Intent pour capturer une image:

App.Instance.ShouldTakePicture += () => {
   var intent = new Intent(MediaStore.ActionImageCapture);
   intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(file));
   StartActivityForResult(intent, 0);
};

enfin et surtout, notre activité doit réagir sur l'image résultante. Il poussera simplement son chemin de fichier vers le fichier ShowImage méthode.

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
   base.OnActivityResult(requestCode, resultCode, data);
   App.Instance.ShowImage(file.Path);
}

c'est tout! Il suffit de ne pas oublier pour définir la" caméra "et la permission" WriteExternalStorage "dans" AndroidManifest.xml"!

le projet iOS

pour l'implémentation iOS nous créons un renderer personnalisé. Par conséquent, nous ajoutons un nouveau fichier "CustomContentPageRenderer" et ajoutons l'attribut assembly correspondant juste après les instructions d'utilisation:

[assembly:ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]

CustomContentPageRenderer hérite de PageRenderer:

public class CustomContentPageRenderer: PageRenderer
{
    ...
}

nous outrepassons le ViewDidAppear méthode et ajouter ce qui suit: partie.

créer un nouveau contrôleur de picker d'image se référant à la caméra:

var imagePicker = new UIImagePickerController { SourceType = UIImagePickerControllerSourceType.Camera };

Présenter l'image du contrôleur de sélecteur, dès que l' ShouldTakePicture événement est déclenché:

App.Instance.ShouldTakePicture += () => PresentViewController(imagePicker, true, null);

après avoir pris la photo, Sauvegardez-la sur le MyDocuments le dossier et appeler le partagé ShowImage méthode:

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

et enfin, nous devons gérer une annulation du processus de prise d'image:

imagePicker.Canceled += (sender, e) => DismissViewController(true, null);
31
répondu Falko 2015-04-22 21:18:31

Essayer James Montemagno MediaPlugin.

vous pouvez installer le plugin en utilisant Console De Gestionnaire De Paquets en tapant simplement et en cours d'exécution Install-Package Xam.Plugin.Media -Version 2.6.2 ou bien aller à Gérer Les Paquets NuGet... et tapez Xam.Plugin.Media et installez le plugin. (Les plugins doivent être installés dans tous vos projets-y compris les projets clients)

readme.txt sera activé et suivre les instructions. Après que, ajouter les codes suivants (selon les besoins) à votre projet partagé. Les instructions à suivre dans le cas ci-dessus readme.txt les fichiers sont les suivants.

Pour Android Project

dans votre BaseActivity ou MainActivity (pour Xamarin.Forms) ajouter ce code:

public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
    PermissionsImplementation.Current.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}  

vous devez également ajouter quelques fichiers de configuration supplémentaires pour adhérer au nouveau mode strict:

  1. ajouter ce qui suit à votre AndroidManifest.xml à l'intérieur de la < application> tags:

    <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>
    

    YOUR_APP_PACKAGE_NAME doit être défini à votre nom de paquet app!

  2. Ajouter un nouveau dossier appelé xml dans votre dossier de Ressources et d'ajouter un nouveau fichier XML appelé file_paths.xml

    ajouter le code suivant:

    <?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>
    

    YOUR_APP_PACKAGE_NAME doit être défini à votre nom de paquet app!

pour le projet iOS

Votre app est nécessaire d'avoir des clés dans vos informations.plist pour NSCameraUsageDescription et NSPhotoLibraryUsageDescription pour accéder à la caméra et à la photothèque/vidéothèque de l'appareil. Si vous utilisez les fonctionnalités vidéo de la bibliothèque, vous devez aussi ajouter NSMicrophoneUsageDescription. La chaîne que vous fournissez pour chacune de ces clés seront affichés à l'utilisateur lorsqu'ils sont invités à fournir une autorisation pour accéder à ces fonctions de l'appareil.

tels que:

<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>

Pour Un Projet Partagé

simplement ouvrir caméra, Enregistrer photo et afficher une alerte avec le chemin du fichier, entrer ce qui suit dans le projet partagé.

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"); 
5
répondu Curiousity 2017-07-06 07:10:27

voici ce dont j'avais besoin pour faire tourner une caméra asynchrone dans mon application:

In iOS:

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

et si vous avez besoin de la routine d'autorisation, assurez-vous de remplir également l'utilisation de la caméra dans info.plist trop, et voici la fonction pour obtenir une autorisation d':

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

Dans Android:

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;
    }
}
1
répondu noelicus 2017-03-22 11:47:00

Voici comment vous pouvez le faire sur Xamarin formes cross Xamarin iOS.

il s'agit d'une bonne base pour démarrer mais elle nécessite une Page à rendre en premier dans laquelle vous pouvez simplement spécifier L'application UIApplication pour qu'elle fournisse L'uivi pour les contrôleurs Caméra / Photo Picker.

https://stackoverflow.com/a/28299259/1941942

Projet Portable

public interface ICameraProvider
{
    Task<CameraResult> TakePhotoAsync();
    Task<CameraResult> PickPhotoAsync();
}

private Command AttachImage 
{
    var camera = await DependencyService.Get<ICameraProvider>().TakePhotoAsync();
}

projet iOS

[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;
    }
}
1
répondu pampi 2017-06-28 09:22:39