개발 노트

Java EXIF 읽기 — metadata-extractor로 GPS·촬영시간·기기정보 추출해봤다

nocklock 2026. 9. 28. 08:30

사진 정보 읽기

Security Lens를 만들면서 처음에는 사진 속 글자만 보면 된다고 생각했다.

OCR로 이미지의 텍스트를 읽고, 그 안에서 전화번호나 이메일 같은 개인정보를 찾는 게 핵심이었다.

그런데 테스트하다 보니 한 가지가 더 눈에 들어왔다.

사진에 보이지 않는 정보도 개인정보가 될 수 있었다.

사진 파일에는 EXIF 메타데이터가 들어갈 수 있고, 여기에는 GPS 위치, 촬영 시간, 촬영 기기 같은 정보가 남아 있을 수 있다.

그래서 Security Lens에도 이미지의 EXIF 정보를 읽는 기능을 추가했다.

이번 글은 그때 Java에서 실제로 사용했던 metadata-extractor를 기준으로 정리해본다.

Java에서 EXIF를 읽기 위해 metadata-extractor를 사용했다

Security Lens에서는 metadata-extractor 라이브러리를 사용했다.

당시 프로젝트에 들어간 버전은 2.19.0이었다.

Gradle 기준으로는 이런 형태다.

 
implementation 'com.drewnoakes:metadata-extractor:2.19.0'
 

이 라이브러리는 Java에서 이미지 파일의 EXIF, GPS 같은 메타데이터를 읽을 수 있게 해준다. JPEG뿐 아니라 여러 이미지·미디어 형식의 메타데이터를 지원한다.

처음에는 EXIF를 직접 파싱해야 하나 생각했는데, 실제로는 이미 잘 만들어진 라이브러리를 사용하는 편이 훨씬 간단했다.

Security Lens에서는 별도 서비스로 분리했다

나는 EXIF 분석 부분을

ImageMetadataService
 

라는 서비스로 따로 분리했다.

전체 흐름은 대략 이런 구조였다.

이미지 업로드
      ↓
ImageAnalysisService
      ↓
ImageMetadataService.extract(image)
      ↓
MetadataResult
      ↓
GPS / 촬영시간 / 기기정보
 

OCR과 개인정보 탐지 로직 안에 EXIF 처리까지 전부 넣어버리면 코드가 금방 복잡해질 것 같았다.

그래서 이미지 메타데이터만 읽는 역할을 따로 분리했다.

결과는 MetadataResult로 만들어서 최종 분석 응답에 합쳤다.

먼저 이미지의 Metadata를 읽는다

metadata-extractor의 기본적인 시작점은 이미지에서 Metadata 객체를 읽는 것이다.

구조를 단순화하면 이런 느낌이다.

 
Metadata metadata =
        ImageMetadataReader.readMetadata(inputStream);
 

이 Metadata 안에 여러 종류의 Directory가 들어 있다.

예를 들면

GPS
Exif SubIFD
Exif IFD0
JPEG
 

같은 식이다.

처음에는 EXIF가 그냥 하나의 덩어리라고 생각했는데, 실제로 사용해보니 필요한 정보에 따라 확인하는 Directory가 달랐다.

GPS 위치정보 읽기

가장 먼저 확인한 건 GPS였다.

GPS 정보는 GpsDirectory에서 읽을 수 있다.

실제 구현 구조를 단순화하면 이런 식이다.

 
GpsDirectory gpsDirectory =
        metadata.getFirstDirectoryOfType(GpsDirectory.class);

if (gpsDirectory != null) {

    GeoLocation geoLocation =
            gpsDirectory.getGeoLocation();

    if (geoLocation != null) {

        double latitude =
                geoLocation.getLatitude();

        double longitude =
                geoLocation.getLongitude();
    }
}
 

여기에서 얻을 수 있는 값이

latitude
longitude
 

다.

Security Lens 테스트에서는 실제 사진에서 GPS 좌표가 추출됐다.

예를 들어 당시 테스트 결과 중 하나에서는 이런 값이 확인됐다.

latitude  : 37.476247299722225
longitude : 127.0032532
 

이미지만 보고 있을 때는 전혀 보이지 않는 정보였다.

그런데 파일을 분석하면 좌표가 그대로 나왔다.

이걸 보고 EXIF를 개인정보 분석에 포함해야겠다는 생각이 더 확실해졌다.

그런데 GPS가 있다는 것만 확인하면 문제가 생겼다

EXIF 기능을 붙인 뒤 테스트하면서 한 번 문제가 있었다.

GPS Directory는 존재하는데 실제 좌표가 정상적이지 않은 이미지가 있었다.

그런데 단순히

 
gpsDirectory != null
 

만 보고 GPS가 있다고 판단하면

0, 0
 

같은 값도 GPS가 탐지된 것처럼 처리될 수 있었다.

처음에는 API 결과에서 GPS가 있다고 나오는데 좌표를 보니 이상했다.

그래서 이후에는 Directory 존재 여부만 보는 게 아니라 실제 좌표가 유효한지도 확인하도록 바꿨다.

이 부분은 직접 테스트하지 않았다면 그냥 지나갔을 것 같다.

대략 이런 기준이 필요했다.

GPS Directory 존재
        +
GeoLocation 존재
        +
정상적인 위도/경도
 

그 후에야

gps.detected = true
 

로 처리했다.

이게 EXIF 기능을 만들면서 가장 기억에 남았던 작은 오류 중 하나다.

촬영시간 읽기

다음은 사진을 찍은 시간이었다.

촬영 시간은 EXIF 안에서도 여러 값이 있을 수 있다.

나는 먼저

DateTimeOriginal
 

을 확인했다.

이 값은 실제 촬영 시점을 나타내는 데 주로 사용된다.

구조를 단순화하면 이런 형태다.

 
ExifSubIFDDirectory subIFD =
        metadata.getFirstDirectoryOfType(
                ExifSubIFDDirectory.class
        );

String capturedAt = null;

if (subIFD != null) {
    capturedAt =
        subIFD.getString(
            ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL
        );
}
 

그런데 사진에 따라 DateTimeOriginal이 없는 경우도 있었다.

그래서 Security Lens에서는 원본 촬영 시간이 없을 때 다른 EXIF 날짜 정보를 확인하는 식으로 fallback을 두었다.

내가 사용한 흐름은 대략

DATETIME_ORIGINAL 확인
        ↓
없으면
        ↓
DATETIME 확인
 

이었다.

실제 테스트 이미지에서는

2026:09:15 23:51:36
 

같은 촬영 시간이 반환됐다.

사진 파일 하나에서 이렇게 구체적인 시간이 바로 나오는 게 꽤 인상적이었다.

어떤 기기로 찍었는지도 읽을 수 있었다

기기 정보도 확인했다.

사진에 따라 EXIF에는

Make
Model
 

값이 들어 있다.

예를 들어

Make  → samsung
Model → Galaxy S25 Ultra
 

같은 정보다.

Java에서는 ExifIFD0Directory에서 확인할 수 있다.

구조를 단순하게 쓰면 이런 식이다.

 
ExifIFD0Directory directory =
        metadata.getFirstDirectoryOfType(
                ExifIFD0Directory.class
        );

if (directory != null) {

    String make =
        directory.getString(
            ExifIFD0Directory.TAG_MAKE
        );

    String model =
        directory.getString(
            ExifIFD0Directory.TAG_MODEL
        );
}
 

Security Lens의 실제 테스트에서도

make  : samsung
model : Galaxy S25 Ultra
 

가 정상적으로 추출됐다.

GPS만큼 민감하게 느껴지는 정보는 아니었지만,

사진 하나에서

언제 찍었는지
어디에서 찍었는지
무슨 기기로 찍었는지
 

를 동시에 알 수 있다는 게 재미있었다.

최종 응답에서는 이렇게 정리했다

Security Lens에서는 EXIF 정보를 그대로 던지기보다는 필요한 정보만 정리해서 반환했다.

형태는 이런 식이다.

 
{
  "metadata": {
    "gps": {
      "detected": true,
      "latitude": 37.476247299722225,
      "longitude": 127.0032532
    },
    "capturedAt": "2026:09:15 23:51:36",
    "device": {
      "detected": true,
      "make": "samsung",
      "model": "Galaxy S25 Ultra"
    }
  }
}
 

반대로 EXIF 정보가 없는 이미지라면

 
{
  "metadata": {
    "gps": {
      "detected": false
    },
    "capturedAt": null,
    "device": {
      "detected": false,
      "make": null,
      "model": null
    }
  }
}
 

처럼 처리했다.

모든 EXIF 값을 API에 전부 노출할 필요는 없다고 생각했다.

Security Lens에서 필요한 건

“이 사진에 개인정보가 될 만한 메타데이터가 존재하는가?”

였기 때문이다.

EXIF가 없다고 오류는 아니다

개발하면서 한 가지 중요하게 봤던 부분도 있다.

사진에 EXIF가 없다고 해서 분석 실패로 처리하면 안 된다.

인터넷에서 저장한 이미지나 메신저를 거친 이미지처럼 EXIF가 제거된 파일도 흔히 있을 수 있기 때문이다.

그래서

EXIF 없음
 

은 오류가 아니라

분석 결과 없음
 

으로 처리하는 게 맞았다.

즉,

GPS 없음 → detected false
촬영시간 없음 → null
기기정보 없음 → detected false
 

처럼 결과만 반환했다.

반면 실제 이미지 파싱 자체에 문제가 생긴 경우에는 분석 예외로 구분했다.

이 차이를 만들어두니까 이후 로직도 훨씬 단순해졌다.

결국 OCR만으로는 부족했다

처음 Security Lens를 만들 때 내가 생각한 개인정보는 대부분 사진에 보이는 정보였다.

전화번호가 찍혀 있거나,

이메일 주소가 있거나,

문서에 이름이나 주소가 있는 경우였다.

그런데 EXIF를 붙이면서 한 단계 더 생각하게 됐다.

사진에 보이는 정보
        +
사진 파일 안에 숨어 있는 정보
 

둘 다 확인해야 했다.

그래서 Security Lens의 Fast Scan에서는 OCR 개인정보 탐지와 함께 EXIF 메타데이터도 분석하도록 만들었다.

사진 속 글자를 가렸다고 끝나는 게 아니라, 원본 파일에 위치정보가 남아 있을 수도 있기 때문이다.

직접 구현하면서 가장 크게 배운 건 이것이었다

Java에서 EXIF를 읽는 코드 자체는 생각보다 어렵지 않았다.

오히려 어려웠던 건

어떤 정보를 개인정보로 볼 것인지
 

그리고

어떤 상태를 detected=true로 판단할 것인지
 

였다.

GPS Directory가 있다고 무조건 GPS가 있는 것으로 판단했더니 0, 0 같은 값이 들어오기도 했다.

촬영 시간도 하나의 태그만 보면 없는 사진이 있었다.

사진마다 EXIF 구조도 조금씩 달랐다.

결국 라이브러리를 붙이는 것보다 중요한 건

실제 이미지를 여러 장 넣어보고 결과를 확인하는 것이었다.

이번 프로젝트에서도 코드를 작성했을 때보다 테스트 이미지를 계속 넣어봤을 때 더 많은 문제가 보였다.

그 과정에서

GPS
촬영시간
기기정보
 

가 실제로 제대로 추출되는 것까지 확인했고,

Security Lens의 개인정보 분석 항목 하나로 사용할 수 있게 됐다.


같이 읽으면 좋은 글

사진에는 왜 위치정보가 남을까?

EXIF와 GPS 정보가 일반 사용자 입장에서 왜 신경 쓰이는지 먼저 정리한 글이다.

👉 예약한 「사진 위치정보(EXIF·GPS) 확인·삭제 방법 — 내가 찍은 사진엔 어디까지 남을까?」가 발행되면 이 자리에 그 글 링크를 연결.

사진 한 장에는 생각보다 많은 정보가 들어 있다

사진에 들어 있는 메타데이터와 개인정보를 처음 생각하게 됐던 글이다.

👉 사진 한 장은 생각보다 많은 것을 알고 있다.

OCR에서 개인정보를 찾기 시작했던 과정

Security Lens에서 이미지 분석 기능을 만들면서 OCR과 개인정보 탐지를 붙여간 개발 과정이다.

👉 OCR로 개인정보를 찾기 시작했다, 하드코딩을 걷어낸 날 | RE:개발자 #6