×

exif-js 怎么用?一份实用文档式问答帮你搞懂

作者:Terry2025.10.01来源:Web前端之家浏览:28评论:0
关键词:exif-js使用教程

exif-js

不少做前端开发的朋友,碰到处理图片元数据(比如拍照时间、设备型号、方向信息)时,总会好奇 exif-js 咋用,这篇文章用问答形式,把 exif-js 文档里的关键知识点、实际开发坑点拆解开,帮你快速上手处理图片 EXIF 信息~

exif-js 是干啥的?

简单说,exif-js 是个专门处理图片 EXIF 数据的 JavaScript 库,EXIF 是“可交换图像文件格式”里藏的元数据,手机拍照、专业相机拍的图里,会悄悄存着拍摄时间、设备型号、GPS 定位、照片方向这些信息,前端场景里,上传图片时想自动识别这些信息(比如让用户知道照片哪台设备拍的、自动纠正旋转问题),exif-js 就能帮你把这些隐藏数据读出来。

怎么把 exif-js 加到项目里?

分两种常用方式:

  • npm 安装:如果项目用 Vue/React 这类工程化方案,先在终端执行 npm install exif-js,再在需要的文件里引入:import EXIF from 'exif-js'(注意名字要和库导出一致)。

  • CDN 直接引入:如果是静态页面,直接插 script 标签,<script src="https://cdn.jsdelivr.net/npm/exif-js@2.3.0/dist/exif.js"></script>,这样全局就有 EXIF 对象可用。

不管哪种方式,核心是让 EXIF 这个对象能在代码里调用~

咋读取一张图片的 EXIF 信息?

步骤分“获取文件”和“调用读取方法”,举个用户上传图片的例子:

<input type="file" id="upload" />
<script>
  document.getElementById('upload').addEventListener('change', function(e) {
    const file = e.target.files[0]; // 用户选的文件
    if (!file) return;
    const reader = new FileReader();
    reader.onload = function(event) {
      // event.target.result 是文件的二进制字符串
      EXIF.readFromBinaryFile(event.target.result, function(exifData) {
        console.log(exifData); // 这里就是读取到的EXIF对象
        // exifData.Orientation 是照片方向,exifData.DateTime 是拍摄时间
      });
    };
    reader.readAsBinaryString(file); // 关键:要转成二进制字符串给exif-js读
  });
</script>

关键点:必须把文件转成二进制字符串(用 readAsBinaryString),再传给 EXIF.readFromBinaryFile,回调里的 exifData 就是所有能读到的元数据,没数据的话会是空对象~

能拿到哪些 EXIF 数据?常见字段有啥用?

不同设备、场景存的 EXIF 字段不一样,但核心常用的有这些:

  • Orientation(方向):数值 1 - 8,代表照片拍摄时的旋转方向,比如手机竖拍可能存 Orientation: 6,前端显示时要转 90 度才正常,解决“图片上传后自动旋转”问题全靠它。

  • DateTime(拍摄时间):格式像 2024:08:15 14:20:30,记录照片拍摄的时间点,做“按拍摄时间排序图片”功能时能用到。

  • Make & Model:设备厂商(Canon)和型号(EOS R5),社交平台“这张照片用啥相机拍的?”功能就靠这俩字段。

  • GPSInfo:如果照片开了定位,会有经纬度信息(但格式是度分秒,需要转成十进制),做“显示照片拍摄地点”功能要解析这个。

实际开发里,先打印 exifData 看有哪些字段,再针对性处理~

手机拍照图片旋转问题,exif-js 咋解决?

很多同学碰到“手机拍的图,在电脑/网页上看是歪的”,根源是 Orientation 字段。

Orientation 值含义要旋转的角度
1正常(不需要旋转)
6顺时针转了 90°拍摄逆时针转 90°(或顺时针 270°)
3上下颠倒拍摄180°
8逆时针转了 90°拍摄顺时针转 90°

处理逻辑大概这样:

function fixImageOrientation(img, orientation) {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  let width = img.width;
  let height = img.height;
  let rotate = 0;
  // 根据orientation设置旋转角度和画布尺寸
  if (orientation === 6) {
    rotate = 90 * Math.PI / 180;
    width = img.height;
    height = img.width;
  } else if (orientation === 3) {
    rotate = 180 * Math.PI / 180;
  } else if (orientation === 8) {
    rotate = 270 * Math.PI / 180;
    width = img.height;
    height = img.width;
  }
  canvas.width = width;
  canvas.height = height;
  ctx.translate(width / 2, height / 2);
  ctx.rotate(rotate);
  ctx.drawImage(img, -img.width / 2, -img.height / 2);
  return canvas.toDataURL('image/jpeg'); // 转成base64,也能转成blob上传
}
// 结合exif读取的流程:
// 1. 读exif拿到orientation → 2. 用img标签加载图片 → 3. 调用fixImageOrientation处理

核心思路:先读 Orientation,再用 canvas 旋转图片,最后输出正常的图片地址或文件~

exif-js 对浏览器兼容性咋样?

现代浏览器(Chrome、Firefox、Edge、Safari 最新版)基本都支持,因为它依赖 FileReader APIBlob 处理,但要注意:

  • IE 系列(IE11 及以下)对 FileReader 支持不好,readAsBinaryString 在 IE 里可能有兼容问题,得用 polyfill 或者放弃 IE 支持(现在很多项目已经不考虑 IE 了)。

  • Safari 里,如果图片是跨域的(比如从其他域名加载),要确保服务端返回了 Access-Control-Allow-Origin: * 这类响应头,否则读取会失败(浏览器安全策略限制)。

如果项目要兼容老浏览器,得额外处理 File API 的兼容,或者换更重的 polyfill 方案~

读取 EXIF 失败,常见原因是啥?咋排查?

碰到 exifData 是空对象,或者回调没触发,先查这几点:

  • 图片本身没 EXIF 数据:比如截图、用 PS 保存时去掉元数据的图片,天然没 EXIF,这种读不到很正常,可以换张手机直拍的原图试试。

  • 文件读取方式错了:必须用 readAsBinaryString,如果用 readAsDataURL 或者 readAsText,传进去的格式不对,exif-js 解析不了。

  • 跨域问题:如果图片是从其他域名加载(<img src="https://别人的域名/图.jpg">),想读它的 EXIF,得满足:① 服务端设置了 CORS 响应头 ② 图片标签要加 crossorigin="anonymous",否则浏览器会因为安全策略,阻止脚本读取元数据。

  • 库没正确引入:检查 EXIF 对象是否存在,CDN 引入时路径错了,或者 npm 引入时没正确 import。

排查时,先控制台打印 EXIF 看是否存在,再看文件读取步骤对不对,最后换张确定有 EXIF 的图测试~

exif-js 能修改或写入 EXIF 信息不?

exif-js 核心能力是读取,想修改/写入 EXIF,它本身不支持,因为 EXIF 是图片二进制数据里的一段,修改需要解析整个图片结构(JPEG 的段结构),再重新生成二进制,如果需求是“给图片加自定义元数据”,得结合其他库(piexifjs 这类专门处理 EXIF 写入的工具),流程会复杂很多:先读原有 EXIF,修改后再写回图片二进制。

所以如果只是读,用 exif-js 足够;要写,得换方案~

在 Vue/React 这些框架里咋整合 exif-js?

以 Vue 为例,写个“图片上传时读 EXIF”的组件:

<template>
  <input type="file" @change="handleUpload" />
</template>
<script>
import EXIF from 'exif-js'; // npm安装后引入
export default {
  methods: {
    handleUpload(e) {
      const file = e.target.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onload = (event) => {
        EXIF.readFromBinaryFile(event.target.result, (exifData) => {
          console.log('Vue里拿到的EXIF:', exifData);
          // 这里处理exifData,比如存到组件data里
        });
      };
      reader.readAsBinaryString(file);
    }
  }
};
</script>

React 的话,用 hooks 管理状态:

import React, { useState } from 'react';
import EXIF from 'exif-js';
function ImageUpload() {
  const [exifInfo, setExifInfo] = useState({});
  const handleChange = (e) => {
    const file = e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = (event) => {
      EXIF.readFromBinaryFile(event.target.result, (exifData) => {
        setExifInfo(exifData);
      });
    };
    reader.readAsBinaryString(file);
  };
  return <input type="file" onChange={handleChange} />;
}

核心逻辑和原生 JS 一样,只是套了框架的组件化语法,处理文件、调用 EXIF 方法、存数据这几步~

有没有实际项目里的应用案例?

举几个常见场景:

  • 社交 APP 图片上传:用户发照片时,自动读取拍摄设备(Make+Model)、时间(DateTime)、GPS(如果有),显示在发布页“这张照片用 XX 手机拍于 XX 时间,地点 XX”,提升内容丰富度。

  • 图片管理系统:用户上传大量照片后,按拍摄时间(EXIF 里的 DateTime)自动分组,2024 年 8 月的照片”“2023 年旅行照片”,不用用户手动分类。

  • 摄影作品展示站:摄影师上传作品时,自动提取相机型号、镜头参数(EXIF 里的 FocalLength 等),展示“技术参数”板块,专业感拉满。

  • 图片处理工具(在线 P 图):用户上传图片后,自动根据 Orientation 纠正旋转,避免“修好图发现是歪的”尴尬。

这些场景里,exif-js 负责“把隐藏的元数据挖出来”,后续功能全靠这些数据延伸~

最后补点拓展知识

除了 exif-js,还有些工具能互补:比如处理 GPS 经纬度,exif 里的格式是度分秒(比如北纬 30°12′34″),得转成十进制(30.2094°)才能用地图 API 展示;再比如想批量处理 EXIF,Node.js 环境下可以用 exiftool 这类命令行工具,但前端场景里,exif-js 是轻量又好用的选择~

看完这些问答,是不是对 exif-js 咋用更有数了?实际开发时,先明确“要读哪些元数据、解决什么问题(比如旋转、展示设备信息)”,再对照步骤调库,碰到报错先查文件读取、跨域、兼容性这几个点,基本能搞定大多数场景~要是你还有其他冷门需求(比如解析 RAW 格式图片?但 exif-js 主要支持 JPEG/PNG 这类常见格式),可能得换工具链,但日常前端开发,exif-js 足够 cover~

您的支持是我们创作的动力!
温馨提示:本文作者系Terry ,经Web前端之家编辑修改或补充,转载请注明出处和本文链接:
https://www.jiangweishan.com/article/exif-js.html

网友评论文明上网理性发言 已有0人参与

发表评论: