이미지 내에 포함되어 있는 Exif 데이터는 조리개, 셔터속도, 초점 거리, 측광방식, ISO 설정 그리고 출력시 도움을 줄 수 있는 색상 정보등이 들어있다. 이와 더불어 카메라의 모델명, 등록번호, 위치 정보 등 다른 정보도 포함되어 있다.
지오태깅은 웹사이트, 비디오, QR 코드, 이미지 등 다양한 미디어에서 지리적 식별 메타데이터를 추가하는 프로세스를 일컫는다.
이 포스팅에서는 이미지내에 포함되어 있는 지오태깅 메타데이터를 간단히 제거하는 방법에 대해서 살펴본다. 이 포스팅을 읽기전에 이전 Exif와 관련된 포스팅을 먼저 읽고 오시는 것을 권장합니다.
이미지에 포함된 GPS 정보들
위 이미지는 iPhone 14 Pro 기기로 촬영한 heic 포맷 이미지다. 별도 처리 없이 이미내에 포함된 GPS 정보들을 확인하면 고도, 위도,경도 등 개인정보와 연관된 내용들이 포함되어 있다. 사진에 포함된 이런 민감한 정보들을 사용자가 일일이 지워가며 앱 및 서비스를 이용하기는 어렵다.
GPS 정보 제거
ExifInterface에 정의된 GPS와 관련된 태그 목록은 다음과 같다.
val tags = listOf( ExifInterface.TAG_GPS_VERSION_ID, ExifInterface.TAG_GPS_LATITUDE_REF, ExifInterface.TAG_GPS_LATITUDE, ExifInterface.TAG_GPS_LONGITUDE_REF, ExifInterface.TAG_GPS_LONGITUDE, ExifInterface.TAG_GPS_ALTITUDE_REF, ExifInterface.TAG_GPS_ALTITUDE, ExifInterface.TAG_GPS_TIMESTAMP, ExifInterface.TAG_GPS_SATELLITES, ExifInterface.TAG_GPS_STATUS, ExifInterface.TAG_GPS_MEASURE_MODE, ExifInterface.TAG_GPS_DOP, ExifInterface.TAG_GPS_SPEED_REF, ExifInterface.TAG_GPS_SPEED, ExifInterface.TAG_GPS_TRACK_REF, ExifInterface.TAG_GPS_TRACK, ExifInterface.TAG_GPS_IMG_DIRECTION_REF, ExifInterface.TAG_GPS_IMG_DIRECTION, ExifInterface.TAG_GPS_MAP_DATUM, ExifInterface.TAG_GPS_DEST_LATITUDE_REF, ExifInterface.TAG_GPS_DEST_LATITUDE, ExifInterface.TAG_GPS_DEST_LONGITUDE_REF, ExifInterface.TAG_GPS_DEST_LONGITUDE, ExifInterface.TAG_GPS_DEST_BEARING_REF, ExifInterface.TAG_GPS_DEST_BEARING, ExifInterface.TAG_GPS_DEST_DISTANCE_REF, ExifInterface.TAG_GPS_DEST_DISTANCE, ExifInterface.TAG_GPS_PROCESSING_METHOD, ExifInterface.TAG_GPS_AREA_INFORMATION, ExifInterface.TAG_GPS_DATESTAMP, ExifInterface.TAG_GPS_DIFFERENTIAL, ExifInterface.TAG_GPS_H_POSITIONING_ERROR )
이 태그들을 반복문으로 순회하며 Exif 속성값을 제거하면 된다.
val exif:ExifInterface = ...
tags.forEach { tag->
exif.setAttribute(tag, null) // 태그와 관련된 속성 제거
}
exif.saveAttributes() // 저장
리플렉션을 활용한 GPS 정보 제거
또 다른 방법으로는 리플렉션을 통해 ExifInterface에서 태그 필드들을 가져 온 뒤 제거 하는 것이다.
val exif = ...
for (field in ExifInterface::class.java.fields) { // ExifInterface에 정의 된 필드 목록 순회
val name = field.name // 필드 이름
if (!name.startsWith("TAG_")) { // 필드 상수 이름은 항상 TAG_로 시작한다. 그렇지 않으면 통과
continue
}
val tag: String = try {
field?.get(null) as? String // 필드 상수 값을 가져 온다.
} catch (e: Exception) {
continue
} ?: continue
if (tag.startsWith("GPS")) { // GPS와 관련된 태그명은 GPS로 시작한다.
exif.setAttribute(tag, null) // GPS와 연관된 속성 값은 null로 초기화 한다.
}
}
exif.saveAttributes() // 저장
리플렉션을 활용하면 첫번째 방법보다 코드 라인수는 줄어들고, 좀 더 유연하게 다양한 케이스에 대해서 활용할 수 있다. 하지만 여러가지 상황에서 예외가 발생할 수 있기 때문에 이에 대한 위험요소 인지와 예외처리는 필수다.
0개의 댓글