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

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

L'API Image Capture permet d'enregistrer 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, la sensibilité ISO et la balance des blancs. Cerise sur le gâteau, la capture d'image vous permet d'accéder à toutes les capacités de résolution de n'importe quel appareil photo ou webcam disponible. Les techniques précédentes pour prendre des photos sur le Web utilisaient des instantanés vidéo, dont la résolution était inférieure à celle disponible pour les images fixes.

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

Travaux

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 tester ce code dans la console DevTools.

Filmez

Vous pouvez effectuer une capture du mode plein cadre ou prendre un instantané. takePhoto() renvoie un Blob, 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 la plus élevée disponible pour l'appareil photo. 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, c'est-à-dire un instantané d'une vidéo en direct qui peut, par exemple, être dessiné sur une <canvas>, puis post-traité pour modifier de manière sélective les valeurs de couleur. Notez que ImageBitmap ne dispose que de la résolution de la source vidéo, qui est généralement inférieure à celle des images fixes 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 ne peuvent être vues qu'après takePhoto(). Par exemple, une modification du niveau zoom est immédiatement propagée à MediaStreamTrack, tandis que la réduction des yeux rouges, lorsqu'elle est définie, n'est appliquée que lorsque la photo est prise.

Les fonctionnalités et paramètres de l'appareil photo "en direct" sont manipulés via l'aperçu MediaStreamTrack: MediaStreamTrack.getCapabilities() renvoie un dictionnaire MediaTrackCapabilities avec les capacités concrètes compatibles et les plages ou valeurs autorisées, par exemple les plages de zoom compatibles ou les modes de balance des blancs autorisés. En conséquence, 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 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 d'appareil photo disponibles "Non en direct". Par conséquent, à 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 à l'aide des MediaStreamTrack applyConstraints() contraintes de l'aperçu, 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 la caméra "Non 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 le prochain VideoFrame disponible dans le MediaStreamTrack à l'intérieur du processus du moteur de rendu, tandis que takePhoto() interrompt le MediaStream, reconfigure l'appareil photo, prend la photo (généralement dans un format compressé, d'où le Blob), puis reprend le MediaStreamTrack. En substance, cela signifie que takePhoto() donne accès à toutes les capacités de résolution d'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 voir cet exemple).

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

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

La gamme complète de résolutions de caméra disponibles pour les images fixes peut être obtenue et définie à 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 les vidéos. Comme indiqué plus haut, elles peuvent être différentes des capacités de l'appareil photo pour les images fixes. En d'autres termes, vous ne pourrez peut-être pas accéder aux fonctionnalités de résolution maximale de votre appareil lors de l'enregistrement depuis getUserMedia() sur un canevas. La démonstration de la contrainte de résolution WebRTC montre comment définir des contraintes getUserMedia() pour la résolution.

Autre chose ?

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

  • Vous pouvez accéder au flash de la caméra (voyant de l'appareil) via FillLightMode dans PhotoCapabilities, mais le mode Torche (flash constamment activé) est disponible dans MediaTrackCapabilities.

Démonstrations et exemples de code

Assistance

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

En savoir plus