You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测AVIF图像是否为动图?纯JavaScript实现方案咨询

检测AVIF图像是否为动态图及纯JavaScript实现方案

动态AVIF(又称AVIS)本质是包含多帧图像的序列文件,静态AVIF则只有单帧。纯JavaScript可以通过两种核心思路实现检测:解析文件二进制结构,或利用浏览器原生API读取帧信息。

方法一:解析AVIF二进制结构

AVIF基于ISO BMFF格式,动态AVIF会包含avis(AVIF序列标识)Box,或在stbl(样本表)的stts(样本时间信息)中记录多帧条目。通过读取文件二进制并遍历Box结构,即可判断是否为动态图。

async function isAnimatedAVIF(file) {
  const buffer = await file.arrayBuffer();
  const view = new DataView(buffer);
  let offset = 0;

  // 遍历所有顶级Box
  while (offset < view.byteLength) {
    const boxSize = view.getUint32(offset);
    const boxType = String.fromCharCode(
      view.getUint8(offset + 4),
      view.getUint8(offset + 5),
      view.getUint8(offset + 6),
      view.getUint8(offset + 7)
    );

    // 检测动态AVIF专属的avis Box
    if (boxType === 'avis') {
      return true;
    }

    // 解析moov Box内的帧信息
    if (boxType === 'moov') {
      let moovOffset = offset + 8;
      while (moovOffset < offset + boxSize) {
        const innerBoxSize = view.getUint32(moovOffset);
        const innerBoxType = String.fromCharCode(
          view.getUint8(moovOffset + 4),
          view.getUint8(moovOffset + 5),
          view.getUint8(moovOffset + 6),
          view.getUint8(moovOffset + 7)
        );

        if (innerBoxType === 'stbl') {
          let stblOffset = moovOffset + 8;
          while (stblOffset < moovOffset + innerBoxSize) {
            const stblInnerSize = view.getUint32(stblOffset);
            const stblInnerType = String.fromCharCode(
              view.getUint8(stblOffset + 4),
              view.getUint8(stblOffset + 5),
              view.getUint8(stblOffset + 6),
              view.getUint8(stblOffset + 7)
            );

            // stts Box中的条目数大于1表示多帧
            if (stblInnerType === 'stts' && stblOffset + 12 <= stblOffset + stblInnerSize) {
              const entryCount = view.getUint32(stblOffset + 8);
              if (entryCount > 1) return true;
            }

            stblOffset += stblInnerSize || view.byteLength - stblOffset;
          }
        }

        moovOffset += innerBoxSize || view.byteLength - moovOffset;
      }
    }

    offset += boxSize || view.byteLength - offset;
  }

  return false;
}

// 使用示例
document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (file?.type === 'image/avif') {
    const result = await isAnimatedAVIF(file);
    console.log(result ? '动态AVIF' : '静态AVIF');
  }
});

方法二:利用浏览器原生ImageDecoder API

现代浏览器提供的ImageDecoder API可以直接获取图像的帧数量,代码更简洁,无需手动解析二进制。

async function isAnimatedAVIFUsingDecoder(file) {
  if (!window.ImageDecoder) {
    throw new Error('当前浏览器不支持ImageDecoder API');
  }
  const decoder = new ImageDecoder({ data: file });
  await decoder.completed;
  return decoder.tracks.selectedTrack.frameCount > 1;
}

// 使用示例
document.querySelector('input[type="file"]').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  if (file?.type === 'image/avif') {
    try {
      const result = await isAnimatedAVIFUsingDecoder(file);
      console.log(result ? '动态AVIF' : '静态AVIF');
    } catch (err) {
      console.error('检测失败:', err.message);
    }
  }
});

两种方法对比

  • 二进制解析:兼容性好(支持所有能读取ArrayBuffer的浏览器),但需处理复杂的BMFF格式细节,代码量较大。
  • ImageDecoder API:代码简洁、逻辑直观,但仅支持Chrome 94+、Edge 94+等较新的浏览器版本。

内容的提问来源于stack exchange,提问作者John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 09:05:26