Start · Sprachen · JavaScript · Referenz · ImageDecoder.decode()

ImageDecoder.decode()

Methode

Reiht eine Steuerungsnachricht zum Dekodieren eines Bild-Frames ein und liefert ein Promise mit einem <code>VideoFrame</code> und der Info, ob die Dekodierung vollständig ist.

seit JavaScript WebCodecs API – Chrome/Edge 94+, Opera 80+, Firefo Kategorie: webapi

Signatur

ImageDecoder.prototype.decode(options)

Beschreibung

Die Methode decode() des ImageDecoder-Interfaces aus der WebCodecs API dekodiert einen einzelnen Frame eines Bildes, etwa ein JPEG, PNG, WebP, AVIF oder einen einzelnen Frame aus einem animierten GIF. Der Aufruf wird intern in eine Warteschlange eingereiht und asynchron abgearbeitet. Das zurückgegebene Promise wird mit einem Objekt erfüllt, das den dekodierten Frame als VideoFrame enthält (image) und über complete angibt, ob das Bild vollständig dekodiert ist.

Gebraucht wird decode(), wenn man mehr Kontrolle braucht als mit <img> oder createImageBitmap(). Man kann zum Beispiel einzelne Frames einer Animation gezielt abrufen, Bilder in einem Worker dekodieren oder Frames direkt in ein <canvas>, in WebGL/WebGPU oder in einen VideoEncoder weitergeben.

Mit der Option frameIndex wählt man den Frame bei animierten Formaten. Setzt man completeFramesOnly auf false, liefert der Decoder bei progressiven Formaten (z. B. progressives JPEG) aus einem gestreamten ReadableStream schon Zwischenstufen, deren Qualität schrittweise steigt. Jeder zurückgegebene VideoFrame belegt Ressourcen, zum Teil auf der GPU, und muss nach der Nutzung mit close() freigegeben werden.

Parameter

Name Typ Default Beschreibung
$options object {} Optionales Konfigurationsobjekt mit den Eigenschaften:
  • frameIndex (number, Standard 0): Index des zu dekodierenden Frames.
  • completeFramesOnly (boolean, Standard true): Bei false werden bei progressiven Bildern auch unvollständige Zwischenstufen geliefert.

Rückgabewert

Typ
Promise<{ image: VideoFrame, complete: boolean }>
Beschreibung
Ein Promise, das mit einem Objekt erfüllt wird. image enthält den dekodierten Frame als VideoFrame, complete ist true, wenn das Bild in voller Detailstufe vorliegt. Bei Fehlern wird das Promise abgelehnt, etwa mit RangeError bei ungültigem frameIndex, EncodingError bei defekten Daten oder InvalidStateError, wenn der Decoder geschlossen ist.

Beispiele

Einzelbild dekodieren und auf ein Canvas zeichnen

const response = await fetch('/bilder/foto.jpg');
const decoder = new ImageDecoder({
  data: response.body,
  type: 'image/jpeg'
});

const { image, complete } = await decoder.decode();
console.log(image.displayWidth, image.displayHeight, complete);

const canvas = document.querySelector('canvas');
canvas.width = image.displayWidth;
canvas.height = image.displayHeight;
canvas.getContext('2d').drawImage(image, 0, 0);

// Ressourcen freigeben
image.close();
decoder.close();
1920 1080 true

Alle Frames eines animierten GIFs abspielen

const response = await fetch('/bilder/animation.gif');
const decoder = new ImageDecoder({ data: response.body, type: 'image/gif' });

// Warten, bis die Track-Informationen vorliegen
await decoder.tracks.ready;
await decoder.completed; // sicherstellen, dass alle Daten geladen sind
const frameCount = decoder.tracks.selectedTrack.frameCount;

const ctx = document.querySelector('canvas').getContext('2d');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

for (let i = 0; i < frameCount; i++) {
  const { image } = await decoder.decode({ frameIndex: i });
  ctx.drawImage(image, 0, 0);
  // duration ist in Mikrosekunden angegeben
  const delay = (image.duration ?? 100_000) / 1000;
  image.close();
  await sleep(delay);
}
console.log(`${frameCount} Frames abgespielt`);
24 Frames abgespielt

Progressives JPEG schrittweise anzeigen

const response = await fetch('/bilder/progressiv.jpg');
const decoder = new ImageDecoder({ data: response.body, type: 'image/jpeg' });
const ctx = document.querySelector('canvas').getContext('2d');

let complete = false;
while (!complete) {
  const result = await decoder.decode({ completeFramesOnly: false });
  ctx.drawImage(result.image, 0, 0);
  result.image.close();
  complete = result.complete;
  console.log(complete ? 'fertig' : 'Zwischenstufe');
}
decoder.close();
Zwischenstufe Zwischenstufe fertig

Unterstützung und Format vorab prüfen

const type = 'image/avif';

if (!('ImageDecoder' in window)) {
  console.log('WebCodecs ImageDecoder nicht verfügbar');
} else if (!(await ImageDecoder.isTypeSupported(type))) {
  console.log(`${type} wird nicht unterstützt`);
} else {
  const blob = await (await fetch('/bilder/bild.avif')).blob();
  const decoder = new ImageDecoder({ data: await blob.arrayBuffer(), type });
  try {
    const { image } = await decoder.decode({ frameIndex: 0 });
    console.log('Dekodiert:', image.codedWidth, 'x', image.codedHeight);
    image.close();
  } catch (err) {
    console.error('Dekodierung fehlgeschlagen:', err.name);
  } finally {
    decoder.close();
  }
}
Dekodiert: 800 x 600

// Wichtig · Fallstricke

  • Speicher freigeben: Jeder gelieferte VideoFrame muss mit image.close() freigegeben werden. Tut man das nicht, sammeln sich Speicher- und GPU-Ressourcen an, und der Browser gibt Warnungen aus.
  • Frame-Anzahl: frameIndex muss kleiner als tracks.selectedTrack.frameCount sein, sonst wird das Promise mit RangeError abgelehnt. Bei gestreamten Daten kann frameCount noch steigen. Auf decoder.tracks.ready bzw. decoder.completed warten.
  • Geschlossener Decoder: Nach close() oder reset() werden ausstehende decode()-Promises abgelehnt (AbortError bzw. InvalidStateError).
  • Zeitangaben: VideoFrame.duration und timestamp sind in Mikrosekunden angegeben, nicht in Millisekunden.
  • Kompatibilität: ImageDecoder ist nur in sicheren Kontexten (HTTPS) verfügbar, auch in Workern. Chromium-Browser unterstützen es ab Version 94, Firefox ab 133. Safari unterstützt es derzeit nicht. Vorher per Feature-Detection und ImageDecoder.isTypeSupported() prüfen und als Ausweichlösung createImageBitmap() verwenden.
  • CORS: Bilder von fremden Domains lassen sich nur dekodieren, wenn die Daten per fetch() mit gültigen CORS-Headern geladen wurden.