files/en-us/web/api/imagedecoder/index.md
{{securecontext_header}}{{APIRef("WebCodecs API")}}{{AvailableInWorkers("window_and_dedicated")}}
The ImageDecoder interface of the {{domxref('WebCodecs API','','','true')}} provides a way to unpack and decode encoded image data.
ImageDecoder object.complete is true.decode() operations.Given a {{HTMLElement("canvas")}} element:
<canvas></canvas>
the following code decodes and renders an animated image to that canvas:
let imageDecoder = null;
let imageIndex = 0;
function renderImage(result) {
const canvas = document.querySelector("canvas");
const canvasContext = canvas.getContext("2d");
canvasContext.drawImage(result.image, 0, 0);
const track = imageDecoder.tracks.selectedTrack;
// We check complete here since `frameCount` won't be stable until all
// data has been received. This may cause us to receive a RangeError
// during the decode() call below which needs to be handled.
if (imageDecoder.complete) {
if (track.frameCount === 1) return;
if (imageIndex + 1 >= track.frameCount) imageIndex = 0;
}
// Decode the next frame ahead of display so it's ready in time.
imageDecoder
.decode({ frameIndex: ++imageIndex })
.then((nextResult) =>
setTimeout(() => {
renderImage(nextResult);
}, result.image.duration / 1000.0),
)
.catch((e) => {
// We can end up requesting an imageIndex past the end since
// we're using a ReadableStream from fetch(), when this happens
// just wrap around.
if (e instanceof RangeError) {
imageIndex = 0;
imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);
} else {
throw e;
}
});
}
function decodeImage(imageByteStream) {
imageDecoder = new ImageDecoder({ data: imageByteStream, type: "image/gif" });
imageDecoder.decode({ frameIndex: imageIndex }).then(renderImage);
}
fetch("fancy.gif").then((response) => decodeImage(response.body));
{{Specifications}}
{{Compat}}