웹 서비스를 개발하다 보면 사용자가 업로드한 이미지에서 촬영 장소(GPS), 촬영 기기, 혹은 사진의 회전 방향(Orientation) 정보를 추출해야 할 때가 있습니다. 특히 Next.js 환경에서는 클라이언트(브라우저)와 서버(API Route/Server Components) 양쪽에서 이미지를 다뤄야 하므로 상황에 맞는 라이브러리 선택이 매우 중요합니다.
오늘은 Next.js 프로젝트에서 이미지 EXIF 메타데이터를 처리하는 가장 효율적인 방법을 비교 분석해 보겠습니다.
📊 EXIF 라이브러리 3종 비교
현재 생태계에서 주로 사용되는 라이브러리들의 장단점을 한눈에 비교해 보세요.
| 라이브러리 | 환경 | 주요 특징 | 추천 상황 |
|---|---|---|---|
| exif-js | 브라우저 전용 | 가장 오래된 라이브러리, 업데이트 저조 | 레거시 프로젝트 유지보수 |
| exif-reader | Node.js 중심 | sharp와 연동성 우수, 버퍼 파싱 전용 | 서버사이드 전용 처리 |
| exifr | Isomorphic | 가장 빠름, 거의 모든 포맷 지원, 브라우저/서버 공용 | 대부분의 신규 프로젝트 |
1. 클라이언트와 서버를 아우르는 'exifr'
현재 가장 추천하는 라이브러리는 exifr입니다. 브라우저의 File, Blob뿐만 아니라 Node.js의 Buffer도 완벽하게 지원하며 속도가 압도적으로 빠릅니다.
주요 장점
- 다양한 포맷 지원: JPEG는 물론 HEIC, AVIF, PNG, TIFF까지 지원합니다.
- 부분 파싱: 파일 전체를 읽지 않고 메타데이터 세그먼트만 골라 읽어 성능을 극대화합니다.
- 유용한 유틸리티: GPS 좌표 변환(
exifr.gps())이나 회전 값 계산(exifr.rotation()) 기능을 내장하고 있습니다.
사용 예시 (Next.js 클라이언트 컴포넌트)
import exifr from "exifr";
const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
// 모든 EXIF 데이터 파싱
const data = await exifr.parse(file);
console.log(`기기: ${data.Make} ${data.Model}`);
// GPS 정보만 따로 추출 (도 단위 변환 완료)
const gps = await exifr.gps(file);
console.log(`위도: ${gps?.latitude}, 경도: ${gps?.longitude}`);
};2. 서버사이드 최강 조합: 'sharp' + 'exifr'
Next.js API Route나 Server Actions에서 이미지를 리사이징하면서 메타데이터를 추출해야 한다면, 이미지 처리 라이브러리의 표준인 sharp와 exifr를 함께 사용하는 것이 실무 정석 패턴입니다.
왜 이 조합인가요?
- sharp: 이미지 최적화(WebP 변환 등)와 EXIF 기반 자동 회전(
rotate())에 탁월합니다. - exifr:
sharp가 제공하는 원시 EXIF 버퍼를 가장 정밀하게 객체화해줍니다.
실무 추천 코드 (Next.js API Route)
import sharp from "sharp";
import exifr from "exifr";
export async function POST(req: Request) {
const formData = await req.formData();
const file = formData.get("image") as File;
const buffer = Buffer.from(await file.arrayBuffer());
// 1. sharp로 이미지 기본 정보 및 EXIF 버퍼 추출
const image = sharp(buffer);
const metadata = await image.metadata();
// 2. exifr로 상세 EXIF 정보 파싱
const detailedExif = await exifr.parse(buffer);
// 3. 이미지 최적화 (EXIF 유지하며 리사이징)
const optimizedImage = await image
.resize(1200)
.withMetadata() // 이 함수를 호출해야 EXIF가 유지됩니다!
.toBuffer();
return Response.json({ exif: detailedExif });
}3. 추출 가능한 데이터 종류
exifr을 사용하면 다음과 같은 정보들을 손쉽게 가져올 수 있습니다.
① 카메라 및 촬영 정보 (TIFF/EXIF)
Make,Model: 제조사 및 기기명DateTimeOriginal: 실제 사진이 찍힌 시간ExposureTime,FNumber,ISO: 노출 값
② 위치 정보 (GPS)
latitude,longitude: 위경도 좌표GPSAltitude: 고도 정보
③ 이미지 방향 (Orientation)
- 사진이 가로로 찍혔는지, 세로로 찍혔는지 혹은 뒤집혔는지 나타내는 1~8 사이의 값입니다.
⚠️ 실무 주의사항
- 개인정보 보호: EXIF에는 상세한 위치 정보가 포함될 수 있습니다. 커뮤니티나 SNS 서비스를 만든다면, 서버에서 처리 후 사용자에게 보여줄 때는 메타데이터를 제거(
sharp에서withMetadata()제외)하는 보안 절차가 필요합니다. - 포맷별 제한: PNG나 WebP는 JPEG에 비해 메타데이터 지원이 제한적입니다. 라이브러리가 해당 포맷의 어떤 세그먼트(XMP 등)를 지원하는지 확인하세요.
- 번들 사이즈:
exifr은 기능이 많은 만큼 용량이 있을 수 있습니다. 브라우저에서 사용할 때는exifr/dist/lite.umd.js같은 라이트 버전을 고려해 보세요.
결론
Next.js 프로젝트에서 이미지 메타데이터를 다룬다면 고민하지 말고 **exifr**을 선택하세요. 서버사이드 이미지 가공이 동반된다면 **sharp**와의 조합이 최고의 퍼포먼스를 보여줍니다.
혹시 특정 기기(iPhone HEIC 등)에서 발생하는 메타데이터 이슈를 겪고 계신가요? 상황을 알려주시면 더 자세한 해결 방법을 찾아드릴 수 있습니다!
