如何检测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
相关产品推荐
相关产品推荐

