Start · Sprachen · JavaScript · Referenz · ImageCapture.grabFrame()

ImageCapture.grabFrame()

Methode

Nimmt einen Schnappschuss des aktuellen Videobilds eines <code>MediaStreamTrack</code> auf und liefert ein Promise, das mit einem <code>ImageBitmap</code> erfüllt wird.

seit JavaScript Chrome 59+, Edge 79+, Opera 46+; nicht in Firefox Kategorie: webapi

Signatur

ImageCapture.prototype.grabFrame()

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

Typ
Promise<ImageBitmap>
Beschreibung
Ein Promise, das mit einem 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);
}
Bild aufgenommen: 640×480

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: ImageCapture gibt 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 mit drawImage() in ein Canvas zeichnest.
  • Nur Video-Tracks: Der Konstruktor new ImageCapture(track) braucht einen Track mit kind === "video". Bei einem Audio-Track wirft er einen Fehler.
  • Zustand des Tracks: Ist der Track beendet (track.stop()), deaktiviert oder stummgeschaltet, wird das Promise mit InvalidStateError abgelehnt. Direkt nach getUserMedia() kann das erste Bild noch schwarz sein oder fehlen, weil die Kamera noch startet.
  • Speicher: Jedes ImageBitmap belegt Grafikspeicher. Rufe in Schleifen immer bitmap.close() auf. Vermeide außerdem parallele Aufrufe, die sich überschneiden.
  • Datenschutz und sicherer Kontext: Der Kamerazugriff über getUserMedia() funktioniert nur über HTTPS (oder localhost) 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 nutze takePhoto().