Signatur
Beschreibung
Die Methode grabFrame() des ImageCapture-Interfaces liest das Bild aus, das der Video-Track gerade anzeigt, und gibt es als ImageBitmap zurück. Sie arbeitet mit der aktuellen Auflösung des Streams und verändert keine Kameraeinstellungen. Deshalb eignet sie sich für schnelle, wiederholte Aufnahmen, zum Beispiel für Vorschaubilder, Bildanalyse (Barcode- oder Gesichtserkennung), Zeitraffer oder das Weiterverarbeiten der Bilder in einem <canvas>.
Im Unterschied dazu löst ImageCapture.prototype.takePhoto() eine echte Fotoaufnahme aus. Dabei kann die Kamera in eine höhere Auflösung wechseln und Blitz, Autofokus oder Rote-Augen-Korrektur verwenden. Das Ergebnis ist ein Blob. Wer wenig Verzögerung braucht und die Rohpixel weiterverarbeiten will, nimmt grabFrame(). Wer ein Foto in bestmöglicher Qualität will, nimmt takePhoto().
Das zurückgegebene ImageBitmap lässt sich direkt mit CanvasRenderingContext2D.drawImage() zeichnen, per postMessage() ohne Kopie an einen Worker übertragen oder mit createImageBitmap() weiterverarbeiten. Gib das Bitmap nach der Nutzung mit bitmap.close() frei, damit der Speicher nicht vollläuft.
Rückgabewert
ImageBitmap des aktuellen Videobilds erfüllt wird. Es wird mit einer DOMException abgelehnt: InvalidStateError, wenn der Track beendet ist (readyState ist "ended") oder stummgeschaltet wurde, und UnknownError, wenn die Aufnahme aus anderen Gründen fehlschlägt.Beispiele
Einzelbild der Webcam in ein Canvas zeichnen
const canvas = document.querySelector('#snapshot');
const ctx = canvas.getContext('2d');
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const [track] = stream.getVideoTracks();
const imageCapture = new ImageCapture(track);
try {
const bitmap = await imageCapture.grabFrame();
canvas.width = bitmap.width;
canvas.height = bitmap.height;
ctx.drawImage(bitmap, 0, 0);
console.log(`Bild aufgenommen: ${bitmap.width}×${bitmap.height}`);
bitmap.close(); // Speicher freigeben
} catch (err) {
console.error('Aufnahme fehlgeschlagen:', err.name, err.message);
}
Schnappschuss als PNG herunterladen
const saveSnapshot = async (track) => {
const bitmap = await new ImageCapture(track).grabFrame();
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
canvas.getContext('2d').drawImage(bitmap, 0, 0);
bitmap.close();
const blob = await canvas.convertToBlob({ type: 'image/png' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `snapshot-${Date.now()}.png`;
link.click();
URL.revokeObjectURL(link.href);
};
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
document.querySelector('#save').addEventListener('click', () => {
saveSnapshot(stream.getVideoTracks()[0]);
});
Regelmäßige Bilder an einen Worker zur Analyse schicken (mit Feature-Erkennung)
if (!('ImageCapture' in window)) {
console.warn('ImageCapture wird nicht unterstützt – Fallback über <video> + Canvas nötig.');
} else {
const worker = new Worker('analyse-worker.js');
const stream = await navigator.mediaDevices.getUserMedia({ video: { width: 1280 } });
const [track] = stream.getVideoTracks();
const capture = new ImageCapture(track);
const timer = setInterval(async () => {
if (track.readyState === 'ended') {
clearInterval(timer);
return;
}
try {
const bitmap = await capture.grabFrame();
// Bitmap ohne Kopie übertragen (Transferable)
worker.postMessage({ bitmap }, [bitmap]);
} catch (err) {
console.warn('Bild übersprungen:', err.name);
}
}, 500);
}
// Wichtig · Fallstricke
- Browserunterstützung:
ImageCapturegibt es nur in Chromium-basierten Browsern. Firefox und Safari kennen die API nicht (Stand 2024). Prüfe die Unterstützung mit'ImageCapture' in window. Als Ersatz dient ein<video>-Element, dessen Bild du mitdrawImage()in ein Canvas zeichnest. - Nur Video-Tracks: Der Konstruktor
new ImageCapture(track)braucht einen Track mitkind === "video". Bei einem Audio-Track wirft er einen Fehler. - Zustand des Tracks: Ist der Track beendet (
track.stop()), deaktiviert oder stummgeschaltet, wird das Promise mitInvalidStateErrorabgelehnt. Direkt nachgetUserMedia()kann das erste Bild noch schwarz sein oder fehlen, weil die Kamera noch startet. - Speicher: Jedes
ImageBitmapbelegt Grafikspeicher. Rufe in Schleifen immerbitmap.close()auf. Vermeide außerdem parallele Aufrufe, die sich überschneiden. - Datenschutz und sicherer Kontext: Der Kamerazugriff über
getUserMedia()funktioniert nur über HTTPS (oderlocalhost) und nur, wenn der Nutzer zustimmt. Eine Permissions Policy (camera) kann ihn in iframes sperren. - Die Auflösung entspricht den aktuellen Einstellungen des Tracks. Für höhere Auflösungen setze Vorgaben (Constraints) wie
{ width: 1920 }oder nutzetakePhoto().