HTML5无法原生识别图片格式,需通过FileReader或fetch读取文件头字节(magic bytes)检测:JPEG(FF D8)、PNG(89 50 4E 47)、GIF(47 49 46)、WebP(RIFF...WEBP),且必须用ArrayBuffer而非Text或Blob。

HTML5 本身不提供图片格式识别能力
HTML5 标准没有定义任何原生 API 来读取或解析图片文件头、提取 MIME 类型或判断 .jpg 和 .webp 的实际编码格式。浏览器加载 标签时会自动解码并渲染,但这个过程对 JS 完全黑盒——你无法通过 img.naturalWidth 或 img.currentSrc 反推出原始格式。
用 FileReader + Uint8Array 检查文件头(magic bytes)
这是最可靠、无需服务端介入的客户端检测方式。原理是读取文件前几个字节,比对已知图片格式的 magic number:
-
JPEG:以0xFF 0xD8开头 -
PNG:以0x89 0x50 0x4E 0x47(即\x89PNG)开头 -
GIF:以0x47 0x49 0x46(即GIF)开头 -
WebP:以0x52 0x49 0x46 0x46 ?? ?? ?? ?? 0x57 0x45 0x42 0x50开头(RIFF....WEBP)
注意:必须用 FileReader.readAsArrayBuffer(),不能用 readAsText()(二进制会被破坏);且只需读前 12 字节足矣,避免大图阻塞。
function detectImageFormat(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onload = () => {
const buf = new Uint8Array(reader.result);
if (buf[0] === 0xFF && buf[1] === 0xD8) resolve('jpeg');
else if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4E && buf[3] === 0x47) resolve('png');
else if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) resolve('gif');
else if (buf[0] === 0x52 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x46 &&
buf[8] === 0x57 && buf[9] === 0x45 && buf[10] === 0x42 && buf[11] === 0x50) resolve('webp');
else resolve('unknown');
};
reader.readAsArrayBuffer(file.slice(0, 12));
});
}
用 fetch + Response.arrayBuffer() 检测远程图片格式
如果图片来自 URL(比如用户粘贴的链接),不能直接用 FileReader,需发起请求并读取响应体前若干字节。关键点:
立即学习“前端免费学习笔记(深入)”;
- 必须设置
mode: 'cors'(若跨域)且目标服务器允许Access-Control-Allow-Origin - 用
response.arrayBuffer()获取原始字节,不要用response.blob()(Blob 不保证可读头信息) - 部分 CDN 或图片服务(如 Cloudinary)会在响应头返回
Content-Type,但不可信——它可能被伪造或降级为image/jpeg即使实际是 WebP
示例中只取前 12 字节,与本地检测逻辑一致:
async function detectRemoteImage(url) {
try {
const res = await fetch(url, { method: 'HEAD' }); // 先试 HEAD,更快
if (res.headers.get('content-type')?.includes('image/')) {
// 若 HEAD 支持且有准确 Content-Type,可直接用(但非强制)
return res.headers.get('content-type').split('/')[1];
}
const fullRes = await fetch(url);
const buf = await fullRes.arrayBuffer();
const view = new Uint8Array(buf, 0, Math.min(12, buf.byteLength));
// 同上 magic bytes 判断逻辑...
return 'unknown';
} catch (e) {
return 'error';
}
}
为什么不能只依赖
的 load 事件或 naturalHeight?
很多开发者误以为监听 img.onload 后检查 img.naturalWidth > 0 就能确认格式,其实完全不行:
-
加载失败时,
onerror触发,但你仍不知道它是 JPEG 还是 WebP -
能成功加载,但 SVG 不是位图,magic bytes 检测也不适用 - 浏览器可能对损坏图片做容错处理(如自动补全 JPEG SOI),导致渲染成功但格式已非原始
-
naturalWidth/naturalHeight在 CORS 图片上可能为 0,即使图片真实存在
真正需要格式识别的场景(如上传校验、格式转换、CDN 参数生成),必须回到文件头或响应体原始字节层面。别绕开这一步。











