HTML5如何识别图片格式_HTML5识别图片格式途径【检测】

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.naturalWidthimg.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 参数生成),必须回到文件头或响应体原始字节层面。别绕开这一步。