**EXIF(Exchangeable Image File Format)**๋ ์ฌ์ง ์ด๋ฏธ์ง ๋ฐ์ดํฐ ์์ฒด ์ธ์, ๊ทธ ์ฌ์ง์ด ์ด๋ป๊ฒ, ์ธ์ , ์ด๋์, ๋ฌด์์ผ๋ก ์ฐํ๋์ง์ ๋ํ ๊ตฌ์ฒด์ ์ธ **๋ฉํ๋ฐ์ดํฐ(๋ฐ์ดํฐ์ ๋ํ ๋ฐ์ดํฐ)**๋ฅผ ๋ด๊ณ ์๋ค.
- ์นด๋ฉ๋ผ ์ ๋ณด: ์ด๋ค ์ฅ๋น๋ก ์ฌ์ง์ ์ฐ์๋์ง ์๋ ค์ค๋ค.
- ์นด๋ฉ๋ผ ์ ์กฐ์ฌ ๋ฐ ๋ชจ๋ธ: ์) SAMSUNG, Apple, SM-S928N, iPhone 15 Pro
- ๋ ์ฆ ์ ๋ณด: ์ฌ์ฉ๋ ๋ ์ฆ์ ์ข ๋ฅ, ์ด์ ๊ฑฐ๋ฆฌ ๋ฑ
- ์ดฌ์ ์ค์ ๊ฐ: ์ฌ์ง์ ์ด๋ค ์ค์ ์ผ๋ก ์ฐ์๋์ง์ ๋ํ ๊ธฐ์ ์ ์ธ ์ ๋ณด.
- ISO ๊ฐ๋: ๋น์ ์ผ๋ง๋ ๋ฏผ๊ฐํ๊ฒ ๋ฐ์ํ๋์ง
- ์กฐ๋ฆฌ๊ฐ ๊ฐ (F-stop): ๋ ์ฆ๋ฅผ ์ผ๋ง๋ ์ด์๋์ง (์ฌ๋ ํํ๊ณผ ๊ด๋ จ)
- ์ ํฐ ์๋: ์ผ๋ง๋ ๋น ๋ฅธ ์๋๋ก ๋น์ ๋ฐ์๋ค์๋์ง (์์ง์ ํํ๊ณผ ๊ด๋ จ)
- ๋ ธ์ถ ๋ณด์ , ํ์ดํธ ๋ฐธ๋ฐ์ค, ํ๋์ ์ฌ์ฉ ์ฌ๋ถ ๋ฑ
- ์๊ฐ ๋ฐ ์์น ์ ๋ณด: ์ฌ์ง ์ฐ์ ์๊ฐ, ์๊ฒฝ๋
- ์ดฌ์ ๋ ์ง ๋ฐ ์๊ฐ: ์ฌ์ง์ ์ฐ์ ์ ํํ ๋ ์ง์ ์๊ฐ.
- GPS ์ขํ (์๋, ๊ฒฝ๋): ์นด๋ฉ๋ผ์ ์์น ์ ๋ณด ๊ธฐ๋ก ๊ธฐ๋ฅ์ด ์ผ์ ธ ์์ด์ผ ํจ.
๋ด๊ฐ ํ์ํ ๊ฑด ์๊ฐ ๋ฐ ์์น ์ ๋ณด๊ฐ ๋จ๊ธฐ๋ฅผ ๋ฐ๋๋ค.
webview ํ๊ทธ๋ฅผ ํตํด์ ์ ๋ก๋ ์
๋ธ๋ผ์ฐ์ ์์ <input type="file"> ๋ฅผ ํตํด ํ์ผ์ ์ ํํ๋ฉด, ์๋๋ก์ด๋์ ํ์ผ ์ ํ๊ธฐ๊ฐ ์ด๋ฆฌ๊ณ , ๋ธ๋ผ์ฐ์ ๋ ํ์ผ์ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด๋๋ค. ์ด ๊ณผ์ ์์ ๋ธ๋ผ์ฐ์ ๋ ๊ฐ์ธ์ ๋ณด ์ ์ถ์ ๋ง๊ธฐ ์ํด์ EXIF ๋ฐ์ดํฐ๋ฅผ ์๋์ ์ผ๋ก ์ญ์ ํ๋ค.
์น๋ทฐ์ ๊ฒฝ์ฐ onShowFileChooser ์์ ๊ฐ๋ฐ์๊ฐ EXIF ์ ๋ณด๊ฐ ๋ณด์กด๋๊ฒ ํ ์ ์๋ค. ACCESS_MEDIA_LOCATION ๊ถํ์ ์ฌ์ฉ์์๊ฒ ํ๊ฐ๋ฐ์ผ๋ฉด ํ์ผ์ ์์น ์ ๋ณด๋ฅผ ๋ณด์กดํ ์ ์๋ค
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
onShowFileChooser ์์ ํ์ผ ์ ํ ๊ฒฐ๊ณผ๋ฅผ ActivityResultLauncher ๋ก ๋ฐ๋๋ฐ, ์ด๋ Uri ๋ฅผ ๊ฐ๊ณตํ์ง ์๊ณ ๊ทธ๋๋ก filePathCallback.onReceiveValue() ์ ์ ๋ฌํ๋ฉด ๋๋ค.
// EXIF ์ ๋ณด ๋๋ฒ๊ทธ ์ถ๋ ฅ
try {
val uri = data?.data
if (uri != null) {
activity.contentResolver.openInputStream(uri)?.use { inputStream ->
val exif = ExifInterface(inputStream)
Log.d(TAG, "Single File EXIF Info:")
Log.d(TAG, " DateTime: ${exif.getAttribute(ExifInterface.TAG_DATETIME)}")
Log.d(TAG, " GPS Latitude: ${exif.getAttribute(ExifInterface.TAG_GPS_LATITUDE)}")
Log.d(TAG, " GPS Longitude: ${exif.getAttribute(ExifInterface.TAG_GPS_LONGITUDE)}")
Log.d(TAG, " Make: ${exif.getAttribute(ExifInterface.TAG_MAKE)}")
Log.d(TAG, " Model: ${exif.getAttribute(ExifInterface.TAG_MODEL)}")
Log.d(TAG, " Orientation: ${exif.getAttribute(ExifInterface.TAG_ORIENTATION)}")
}
}
} catch (e: Exception) {
Log.e(TAG, "EXIF ์ ๋ณด ์ฝ๊ธฐ ์คํจ", e)
}
Single File EXIF Info:
DateTime: 2025:07:18 08:43:28
GPS Latitude: 37/1,0/1,0/100000
GPS Longitude: 127/1,0/1,0/00000
Make: samsung
Model: SM-N960N
Orientation: 6
ACCESS_MEDIA_LOCATION ๊ถํ์ ๋ถ์ฌํ๋ฉด GPS ์ ๋ณด๊ฐ ์ ์์ ์ผ๋ก ๊ธฐ๋ก๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด 0/1๊ณผ ๊ฐ์ ํํ๋ก ๊ธฐ๋ก๋๋ค. ๋ฐ๋ผ์ ์ฌ์ฉ์์๊ฒ ๊ถํ์ ๋ช
์์ ์ผ๋ก ๋ฐ์์ผ ํ๋ค.
์น์์ exif ์ ๋ณด ๊ฐ์ ธ์ค๊ธฐ
online-metadata.com
์จ๋ผ์ธ ๋ฉํ๋ฐ์ดํฐ ๋ฐ EXIF ๋ฌด๋ฃ ๋ทฐ์ด
์จ๋ผ์ธ ๋ฉํ๋ฐ์ดํฐ ๋ฐ EXIF๋ ๋์์, ์ค๋์ค, ์ด๋ฏธ์ง, ์์นด์ด๋ธ ๋ฐ ๋ฌธ์ ํ์ผ์์ ๋น๋ฐ ๋ฉํ๋ฐ์ดํฐ ๋ฐ EXIF ์ ๋ณด๋ฅผ ๋ฌด๋ฃ๋ก ์ถ์ถํ๋ ์จ๋ผ์ธ ๋๊ตฌ์ ๋๋ค. ๋ค์ํ ํ์ผ ๋ฐ ๋ฉํ๋ฐ์ดํฐ ํ์์ ์ง์ํฉ๋๋ค.
์น์์ ํ์ผ ์ ๋ก๋๋ฅผ ํ์ ๋ EXIF ์ ๋ณด๊ฐ ๋๋ฝ๋๋ ํ์์ด ์๋ค. ํ์ง๋ง ์ ์ฌ์ดํธ์์๋ ์ ์์ ์ผ๋ก ์๋ํ๋ค. ๋ฌด์จ ์ฐจ์ด๊ฐ ์์๊น?
์ ํ์ด์ง๋ ํ์ผ์ <form> ํ๊ทธ๋ฅผ ํตํด ๊ทธ๋๋ก ์๋ฒ๋ก ์ ๋ฌํ๊ธฐ ๋๋ฌธ์ EXIF ๋ฐ์ดํฐ์ ์์ค ์์ด ์ ๋ฌ๋์ด ๋ถ์์ด ๊ฐ๋ฅํ ๊ฒ์ด๋ค. ๋ฐ๋ฉด ๋ธ๋ผ์ฐ์ JavaScript์์ ํ์ผ ๋ฐ์ดํฐ์ ์ง์ ์ ๊ทผํ๋ ค๊ณ ํ๋ฉด ๋ธ๋ผ์ฐ์ ๋ณด์ ์ ์ฑ
์ ์ผ๋ถ ์ ๋ณด(EXIF ๋ฑ)๊ฐ ์ฐจ๋จ๋ ์ ์๋ค.
์น๋ทฐ์์ native ๋ก์ง์ ํตํด ์ ๋ฌ๋ ๊ฒฝ์ฐ
์ฑ์ด OS ๊ถํ์ ์ป์ด์ ๋ธ๋ผ์ฐ์ ๊ธฐ๋ณธ ์ ์ฑ ์ด ์๋ ์ฑ์ ๊ถํ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ง์ ์ ๋ฌํ๋ค. ๋ฐ๋ผ์ ์ฑ์ ํตํด ํ์ผ์ ์ ํํ ๊ฒฝ์ฐ ์น์์๋ EXIF ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๊ณ ๋ค๋ฃฐ ์ ์๊ฒ ๋๋ค.
๋ค๋ง EXIF ๋ ๊ฐ์ธ์ ๋ณด๋ก ์ทจ๊ธํ ์ ์๊ธฐ ๋๋ฌธ์ ์ ์ฅ๊ณผ ๋ ธ์ถ์ ์ฃผ์๋ฅผ ํด์ผํ๋ค. ์๋ฒ์ ์ ์ฅํ ๊ฒฝ์ฐ ์ ๋ง ํ์ํ ๋งํผ๋ง ํน์ ๋์ง ์์ ์ ๋์ ์ ๋ณด๋ง ์ทจ๊ธํ๊ฑฐ๋, ์ ์ฅํ์ง ์๋ ๊ฒ ์ข๋ค.
www.innovation.go.kr
ํ์ 24 - ์ ๋ถํ์ ํํ์ด์ง
์ ๋ถํ์ ๋ณด๋ค๋์์ ๋ถ
์ ๋ถ ํ์ด์ง์์ EXIF ๋ฐ์ดํฐ์ ์ํ์ฑ๊ณผ ๋์๋ฒ๋ ํ๋ณดํ๊ณ ์๋ค.
๋ฐ์ดํฐ ํ์
fileList.forEach((file) => {
exifr.parse(file)
.then((metadata: any) => {
console.log(`[EXIF] ${file.name}`, metadata);
})
.catch((error: any) => {
console.error(`[EXIF] Failed to parse EXIF for ${file.name}`, error);
});
});
exifr ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํด์ EXIF ๋ฐ์ดํฐ๋ฅผ ๋ถ์ํ๋ค. parse ๊ฒฐ๊ณผ๊ฐ์์ ์ํ๋ ์ ๋ณด๋ฅผ ํ์ฉํ๋ฉด ๋๋ค.
exif ๋ฐ์ดํฐ ์ฝ์ ํ๊ธฐ (piexif ๋ผ์ด๋ธ๋ฌ๋ฆฌ)
github.com
GitHub - hMatoba/piexifjs: Read and modify exif in client-side or server-side JavaScript.
Read and modify exif in client-side or server-side JavaScript. - hMatoba/piexifjs
์ด๋ฏธ์ง๋ฅผ ํ์ฒ๋ฆฌํ๋ค๊ฐ EXIF ๋ฐ์ดํฐ๊ฐ ์์ค๋๋ ๊ฒฝ์ฐ๋ ์๋ค. ์๋ฅผ ๋ค์ด ์บ๋ฒ์ค(Canvas)์ ์ด๋ฏธ์ง๋ฅผ ๊ทธ๋ฆฌ๊ณ ์ถ๊ฐ์ ์ธ ์ฒ๋ฆฌ๋ฅผ ํ ๋ค ๋ค์ ์ด๋ฏธ์ง๋ก ์ถ์ถํ์ ๋๋ EXIF ๋ฐ์ดํฐ๊ฐ ์๋ ์ํ๊ฐ ๋๋ค. ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ๋ฏธ๋ฆฌ ๊ฐ์ง๊ณ ์๋ EXIF ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด๋์๋ค๊ฐ ๊ฒฐ๊ณผ ์ด๋ฏธ์ง์ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์๋ค.
exifr ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ฝ๊ธฐ ์ ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ฏ๋ก, EXIF ๋ฐ์ดํฐ๋ฅผ ํ์ผ์ ์ฐ๋ ๊ธฐ๋ฅ์ ์๋ค. piexif ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด๋ณด์.
// EXIF ์ ์ฅ
let exifStr: string | null = null;
try {
const originalDataURL = await fileToDataURL(origFile);
const exifObj = piexif.load(originalDataURL);
exifStr = piexif.dump(exifObj);
} catch (e) { ... }
// EXIF ์ฝ์
try {
finalDataURL = piexif.insert(exifStr, resizeResult.dataURL);
} catch (e) { ... }
์๋ณธ์ exif ๊ฐ ๊ทธ๋๋ก ์ฃผ์ ๋๋ค.
๋๊ธ 0๊ฐ