Signatur
Beschreibung
Die Eigenschaft repetitionCount des Interfaces ImageTrack gehört zur WebCodecs API. Sie gibt an, wie oft die Animation eines Bild-Tracks nach dem ersten Durchlauf wiederholt werden soll. Der Wert kommt direkt aus den Metadaten der Bilddatei, bei animierten GIFs zum Beispiel aus der Loop-Angabe der NETSCAPE2.0-Erweiterung, bei animierten WebP- oder APNG-Dateien aus dem jeweiligen Loop-Feld.
Die Werte bedeuten Folgendes:
0: Die Animation läuft genau einmal. Das gilt auch für Standbilder ohne Animation.n > 0: Die Animation wirdn-mal wiederholt. Insgesamt läuft sie alson + 1-mal.Infinity: Die Animation läuft in einer Endlosschleife.
Die Eigenschaft ist nützlich, wenn du Animationen selbst abspielst: Du dekodierst die einzelnen Bilder mit ImageDecoder.decode() und zeichnest sie zum Beispiel auf ein <canvas>. Damit dein eigener Player sich wie der Browser verhält, musst du die Wiederholungsangabe der Datei beachten. Den Track erhältst du über decoder.tracks.selectedTrack oder über einen Index in der ImageTrackList. Die Werte stehen erst sicher fest, wenn das Promise decoder.tracks.ready erfüllt ist.
Rückgabewert
0 steht für einen einzigen Durchlauf, Infinity für eine Endlosschleife. Die Eigenschaft ist nur lesbar.Beispiele
Wiederholungsanzahl eines animierten GIFs auslesen
const response = await fetch('/bilder/lade-animation.gif');
const decoder = new ImageDecoder({
data: response.body,
type: 'image/gif'
});
// Warten, bis die Track-Informationen vorliegen
await decoder.tracks.ready;
const track = decoder.tracks.selectedTrack;
console.log('Animiert:', track.animated);
console.log('Wiederholungen:', track.repetitionCount);
if (track.repetitionCount === Infinity) {
console.log('Endlosschleife');
} else {
console.log(`Läuft insgesamt ${track.repetitionCount + 1}-mal`);
}
Eigener Canvas-Player, der repetitionCount beachtet
const playAnimation = async (url, canvas) => {
const ctx = canvas.getContext('2d');
const response = await fetch(url);
const decoder = new ImageDecoder({
data: response.body,
type: response.headers.get('Content-Type') ?? 'image/gif'
});
await decoder.tracks.ready;
const track = decoder.tracks.selectedTrack;
await decoder.completed; // frameCount steht erst jetzt sicher fest
const totalRuns = track.repetitionCount + 1; // Infinity + 1 === Infinity
for (let run = 0; run < totalRuns; run++) {
for (let i = 0; i < track.frameCount; i++) {
const { image } = await decoder.decode({ frameIndex: i });
ctx.drawImage(image, 0, 0);
const delayMs = (image.duration ?? 100_000) / 1000; // Mikrosekunden -> ms
image.close(); // VideoFrame sofort freigeben
await new Promise((r) => setTimeout(r, delayMs));
}
}
decoder.close();
console.log('Animation beendet');
};
playAnimation('/bilder/banner.webp', document.querySelector('canvas'));
Alle Tracks einer Datei auflisten
const inspectTracks = async (blob) => {
const decoder = new ImageDecoder({ data: blob, type: blob.type });
await decoder.tracks.ready;
for (let i = 0; i < decoder.tracks.length; i++) {
const t = decoder.tracks[i];
console.log(`Track ${i}: animiert=${t.animated}, Frames=${t.frameCount}, Wiederholungen=${t.repetitionCount}`);
}
decoder.close();
};
const input = document.querySelector('input[type=file]');
input.addEventListener('change', () => inspectTracks(input.files[0]));
// Wichtig · Fallstricke
- Zählweise: Der Wert zählt die Wiederholungen, nicht die Durchläufe insgesamt. Bei
repetitionCount === 2wird die Animation dreimal abgespielt. - Endlosschleife: Eine Endlosschleife wird als
Infinitygemeldet, nicht als0wie im GIF-Dateiformat. Wenn du den Wert mitJSON.stringify()serialisierst, wird ausInfinitynull. - Zeitpunkt: Lies die Eigenschaft erst, nachdem
decoder.tracks.readyerfüllt ist. Bei gestreamten Daten ist eventuell auch erst nachdecoder.completedalles endgültig bekannt. - Standbilder: Bei Standbildern wie JPEG oder PNG ohne Animation ist der Wert
0. Ob eine Datei animiert ist, prüfst du zusätzlich überImageTrack.animated. - Kompatibilität:
ImageDecoderundImageTrackgibt es in Chromium-basierten Browsern ab Version 94 und in neueren Firefox-Versionen, in Safari aber nicht. Die API funktioniert nur in sicheren Kontexten (HTTPS) und ist auch in Web Workern verfügbar. Prüfe vor der Nutzung mit'ImageDecoder' in globalThis, ob sie vorhanden ist, und frage mitImageDecoder.isTypeSupported()ab, welche Bildformate unterstützt werden. - Speicher: Rufe bei eigenen Playern
image.close()für jeden dekodiertenVideoFrameauf. Sonst wächst bei Endlosschleifen der Speicherverbrauch.