Prendre des photos et contrôler les paramètres de l'appareil photo

Miguel Casas-Sanchez
François Beaufort
François Beaufort

Image Capture est une API permettant de capturer des images fixes et de configurer les paramètres matériels de l'appareil photo. Cette API est disponible dans Chrome 59 sur Android et sur ordinateur. Nous avons également publié une bibliothèque de polyfills ImageCapture.

L'API permet de contrôler les fonctionnalités de l'appareil photo telles que le zoom, la luminosité, le contraste, l'ISO et la balance des blancs. Cerise sur le gâteau, Image Capture vous permet d'accéder à la résolution maximale de n'importe quel appareil photo ou webcam disponible. Les techniques précédentes de prise de photos sur le Web utilisaient des instantanés vidéo, dont la résolution est inférieure à celle disponible pour les images fixes.

Un objet ImageCapture est construit avec un MediaStreamTrack comme source. L'API dispose alors de deux méthodes de capture : takePhoto() et grabFrame(), ainsi que de deux méthodes permettant de récupérer les fonctionnalités et les paramètres de l'appareil photo, et de modifier ces paramètres.

Construction

L'API Image Capture accède à un appareil photo via un MediaStreamTrack obtenu à partir de getUserMedia():

navigator.mediaDevices.getUserMedia({video: true})
    .then(gotMedia)
    .catch(error => console.error('getUserMedia() error:', error));

function gotMedia(mediaStream) {
    const mediaStreamTrack = mediaStream.getVideoTracks()[0];
    const imageCapture = new ImageCapture(mediaStreamTrack);
    console.log(imageCapture);
}

Vous pouvez essayer ce code à partir de la console DevTools.

Filmez

Vous pouvez prendre une photo de deux façons: en mode plein écran ou en mode Instantané rapide. takePhoto() renvoie un Blob, le résultat d'une seule exposition photographique, qui peut être téléchargé, stocké par le navigateur ou affiché dans un élément <img>. Cette méthode utilise la résolution d'appareil photo la plus élevée disponible. Exemple :

const img = document.querySelector('img');
// ...
imageCapture.takePhoto()
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('takePhoto() error:', error));

grabFrame() renvoie un objet ImageBitmap, un instantané d'une vidéo en direct, qui peut (par exemple) être dessiné sur un <canvas>, puis post-traité pour modifier de manière sélective les valeurs de couleur. Notez que ImageBitmap ne connaît que la résolution de la source vidéo, qui est généralement inférieure aux capacités d'image fixe de la caméra. Exemple :

const canvas = document.querySelector('canvas');
// ...
imageCapture.grabFrame()
    .then(imageBitmap => {
    canvas.width = imageBitmap.width;
    canvas.height = imageBitmap.height;
    canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
    })
    .catch(error => console.error('grabFrame() error:', error));

Fonctionnalités et paramètres

Il existe plusieurs façons de manipuler les paramètres de capture, selon que les modifications sont répercutées dans MediaStreamTrack ou qu'elles ne peuvent être visibles qu'après takePhoto(). Par exemple, un changement de niveau zoom est immédiatement propagé à MediaStreamTrack, tandis que la réduction de l'effet "yeux rouges", lorsqu'elle est définie, n'est appliquée que lors de la prise de la photo.

Les capacités et les paramètres de la caméra "en direct" sont manipulés via l'aperçu MediaStreamTrack: MediaStreamTrack.getCapabilities() renvoie un dictionnaire MediaTrackCapabilities avec les capacités concrètes acceptées et les plages ou valeurs autorisées (par exemple, plage de zoom compatible ou modes de balance des blancs autorisés). Par conséquent, MediaStreamTrack.getSettings() renvoie un MediaTrackSettings avec les paramètres actuels concrets. Le zoom, la luminosité et le mode lampe de poche appartiennent à cette catégorie, par exemple:

var zoomSlider = document.querySelector('input[type=range]');
// ...
const capabilities = mediaStreamTrack.getCapabilities();
const settings = mediaStreamTrack.getSettings();
if (capabilities.zoom) {
    zoomSlider.min = capabilities.zoom.min;
    zoomSlider.max = capabilities.zoom.max;
    zoomSlider.step = capabilities.zoom.step;
    zoomSlider.value = settings.zoom;
}

Les fonctionnalités et les paramètres de la caméra "non en direct" sont manipulés via l'objet ImageCapture: ImageCapture.getPhotoCapabilities() renvoie un objet PhotoCapabilities qui donne accès aux fonctionnalités de caméra disponibles "non en direct". De même, à partir de Chrome 61, ImageCapture.getPhotoSettings() renvoie un objet PhotoSettings avec les paramètres actuels concrets. La résolution de la photo, la réduction des yeux rouges et le mode flash (à l'exception de la lampe de poche) appartiennent à cette section, par exemple:

var widthSlider = document.querySelector('input[type=range]');
// ...
imageCapture.getPhotoCapabilities()
    .then(function(photoCapabilities) {
    widthSlider.min = photoCapabilities.imageWidth.min;
    widthSlider.max = photoCapabilities.imageWidth.max;
    widthSlider.step = photoCapabilities.imageWidth.step;
    return imageCapture.getPhotoSettings();
    })
    .then(function(photoSettings) {
    widthSlider.value = photoSettings.imageWidth;
    })
    .catch(error => console.error('Error getting camera capabilities and settings:', error));

Configuration

Les paramètres de caméra "En direct" peuvent être configurés via les contraintes applyConstraints() de l'aperçu MediaStreamTrack, par exemple:

var zoomSlider = document.querySelector('input[type=range]');

mediaStreamTrack.applyConstraints({ advanced: [{ zoom: zoomSlider.value }]})
    .catch(error => console.error('Uh, oh, applyConstraints() error:', error));

Les paramètres de caméra non diffusés en direct sont configurés avec le dictionnaire facultatif PhotoSettings de takePhoto(), par exemple:

var widthSlider = document.querySelector('input[type=range]');
imageCapture.takePhoto({ imageWidth : widthSlider.value })
    .then(blob => {
    img.src = URL.createObjectURL(blob);
    img.onload = () => { URL.revokeObjectURL(this.src); }
    })
    .catch(error => console.error('Uh, oh, takePhoto() error:', error));

Fonctionnalités de l'appareil photo

Si vous exécutez le code ci-dessus, vous remarquerez une différence de dimensions entre les résultats grabFrame() et takePhoto().

La méthode takePhoto() permet d'accéder à la résolution maximale de l'appareil photo.

grabFrame() prend simplement la prochaine VideoFrame disponible dans MediaStreamTrack dans le processus du moteur de rendu, tandis que takePhoto() interrompt MediaStream, reconfigure l'appareil photo, prend la photo (généralement dans un format compressé, d'où le Blob), puis réactive MediaStreamTrack. Concrètement, cela signifie que takePhoto() donne accès à l'ensemble des capacités de résolution des images fixes de l'appareil photo. Auparavant, il n'était possible de "prendre une photo" qu'en appelant drawImage() sur un élément canvas, en utilisant une vidéo comme source (comme dans l'exemple ici).

Pour en savoir plus, consultez la section README.md.

Dans cette démonstration, les dimensions de <canvas> sont définies sur la résolution du flux vidéo, tandis que la taille naturelle de <img> correspond à la résolution maximale de l'image fixe de la caméra. Le CSS, bien sûr, permet de définir la taille d'affichage des deux types.

Vous pouvez obtenir et définir la gamme complète des résolutions d'appareil photo disponibles pour les images fixes à l'aide des valeurs MediaSettingsRange pour PhotoCapabilities.imageHeight et imageWidth. Notez que les contraintes de largeur et de hauteur minimales et maximales pour getUserMedia() concernent la vidéo, qui (comme indiqué) peut être différente des capacités de la caméra pour les images fixes. En d'autres termes, vous ne pourrez peut-être pas accéder aux fonctionnalités haute résolution de votre appareil lors de l'enregistrement de getUserMedia() sur un canevas. La démonstration des contraintes de résolution WebRTC montre comment définir des contraintes getUserMedia() pour la résolution.

Autre chose ?

  • L'API Shape Detection fonctionne bien avec Image Capture: grabFrame() peut être appelé à plusieurs reprises pour alimenter FaceDetector ou BarcodeDetector en ImageBitmap. Pour en savoir plus sur l'API, consultez cet article de blog de Paul Kinlan.

  • Vous pouvez accéder au flash de l'appareil photo (luminosité de l'appareil) via FillLightMode dans PhotoCapabilities, mais le mode Torch (Flash allumé en permanence) est disponible dans le MediaTrackCapabilities.

Démonstrations et exemples de code

Assistance

  • Chrome 59 sur Android et ordinateur.
  • Chrome Canary sur Android et les ordinateurs de bureau antérieurs à la version 59 avec les fonctionnalités de la plate-forme Web expérimentale activées.

En savoir plus