Ionic : Prendre une photo, utiliser la Galerie native

Cordova Plugin Camera

Les photos et vidéos sont au cœur des fonctionnalités natives de nos smartphones. Partagées sur les réseaux sociaux, envoyées comme pièces jointes par email ou simplement uploadées sur un serveur distant... Et les applications hybrides n'ont pas à rester en touche !

Nous en parlions le mois dernier : Cordova permet l'accès à toutes les fonctionnalités natives de nos systèmes mobiles grâce à ses plugins.


Cordova Plugin Camera

Le plugin Camera, maintenu par Apache, permet à une application hybride de :

  • Prendre une photo
  • Sélectionner une photo de la galerie
  • Redimensionner la photo prise/sélectionnée

Et ce pour la majorité des systèmes : iOs, Android, Windows Phone et même BlackBerry.

Installation du Plugin

Sur Android, la sélection de Photos/Images peut se faire depuis différentes sources (Picasa, DropBox, Hubic, Drive, ...). Jusqu'à récemment, un bug empêchait le plugin de récupérer l'URI du fichier sélectionné depuis une source autre que la galerie par défaut. Dans le doute, installez le plugin depuis l'URL du dépôt GitHub et non pas le nom du package NPM. Cas échéant, des tests plus poussés seront nécessaires : le plugin compilé depuis le dépôt Git n'est pas considéré comme étant Stable.

ionic plugins install cordova-plugin-camera  

Ou directement depuis la dernière version du code source :

ionic plugins install https://github.com/apache/cordova-plugin-camera  

Comme à mon habitude, j'ai écrit un service AngularJS pour découpler le code de mon application du code exploitant le plugin. Ce dernier est accessible dans le namespace navigator.camera. Il faut attendre que la plateforme Cordova soit prête pour y accéder :

function activate() {  
    ionic.Platform.ready(function() {
        pluginCamera = navigator.camera;
    });
}

activate est la fonction appelée pour initialiser mon service CameraService. Je vous invite à lire l'excellent Angular Style Guide de John Papa si cette approche vous est inconnue.

Prendre une photo

La méthode getPicture accepte plusieurs options dont : le type d'encodage (JPEG/PNG), la qualité de la compression, le format de sortie (données de l'image encodées en base64 & URI). Liste complète : camera.CameraOptions.

Un exemple simpliste :

self.takePhoto = function(callback) {  
    var options = {
            quality: 75,
            correctOrientation: true,
            encodingType: window.Camera.EncodingType.JPEG,
            destinationType: window.Camera.DestinationType.FILE_URI,
            sourceType: window.Camera.PictureSourceType.CAMERA
    };

    pluginCamera.getPicture(function(fileUri) {
        return callback(null, fileUri);
    }, function(error) {
         if (error.indexOf(ignoredErrorSuffix) === -1) {
            return callback(error);
         }

         // operation cancelled
         return callback(null, null);
    }, options);
};

Avec callback une fonction qui accepte deux paramètres (erreur et URI du fichier).

Il est aussi possible de passer dans les options targetWidth et targetHeight pour redimensionner la photo. Comme l'indique la documentation, le ratio hauteur/largeur de la photo est conservée. On peut donc passer (par exemple) targetWidth: 1024 et targetHeight: 768 pour s'assurer que l'image fera au maximum 768px de haut et/ou 1024px de large.

Le plugin lève une erreur sous forme de chaîne de caractères, ce qui explique l'utilisation d'une string ignoredErrorSuffix pour gérer le cas particulier de l'abandon : je ne souhaite pas traiter le cas de l'abandon de l'utilisateur comme une erreur. La chaîne de caractères vient du code source natif et contient "cancelled" sur Android et Windows Phone. ignoredErrorSuffixest donc égale à 'cancelled'. Si vous souhaitez gérer le cas d'iOs, l'erreur retournée par le plugin est 'no image selected'

Sélectionner une photo de la Galerie

Le code employé est très similaire au précédent, la différence résidant dans la valeur de l'option sourceType : (ici, PHOTOLIBRARY)

self.selectPicture = function(callback) {  
    var options = {
        quality: 75,
        targetWidth: 1280,
        targetHeight: 1280,
        correctOrientation: true,
        encodingType: window.Camera.EncodingType.JPEG,
        mediaType: window.Camera.MediaType.PICTURE,
        destinationType: window.Camera.DestinationType.FILE_URI,
        sourceType: window.Camera.PictureSourceType.PHOTOLIBRARY
    };

    pluginCamera.getPicture(function(fileUri) {
        return callback(null, fileUri);
    }, function(error) {
        if (error.indexOf(ignoredErrorSuffix) === -1) {
            return callback(error);
        }

        return callback(null, null);
    }, options);
};

Pour l'exemple, on décide d'imposer les dimensions de la photo sélectionnée, qui sera copiée puis compressée/redimensionnée : très pratique lorsque l'on offre à l'utilisateur la possibilité d'uploader l'image vers un serveur distant (gain de temps et de bande passante).

Afficher la photo prise/sélectionnée

Il est possible d'afficher la photo prise (ou sélectionnée) en utilisant son URI directement dans une template :

<img src="{{ ctrl.fileUri }}" alt="">  

Avec ctrl.fileUri l'URI vers la photo. Cette "technique" ne fonctionne que si l'application est exécutée localement (fonctionnement normal). Si vous utilisez le live reload d'Ionic, l'application ne saura pas charger le fichier ciblé.

On ne prend pas la précaution d'utiliser ng-src puisqu'Angular est supposé chargé à cet instant.


Nous verrons dans un prochain article qu'il est aussi possible de télécharger et d'uploader des fichiers, grâce au plugin file-transfer.