13/ Image 업로드 시 회전에 대하여 (feat. exif 메타데이터 - Orientation)

13/ Image 업로드 시 회전에 대하여 (feat. exif 메타데이터 - Orientation)

웹 브라우저에서 이미지를 업로드 할 때 type이 file인 input을 통해 이미지를 받고, file API를 사용하여 이미지를 read합니다. 이때 핸드폰을 세워서 촬영할 경우 사진 이미지가 멋대로 회전되서 read될때가 있습니다. 이를 잡기 위해서는 사진의 메타정보(exif)에 있는 orientation이라는 정보를 확인해야합니다.
exif가 무엇인지 간략하게 알아보고, 라이브러리를 사용하여 회전 버그를 픽스하는 방법에 대해서 정리해보았습니다.


목차

  1. exif란? 출처
  2. JavaScript 로드 시 회전 픽스방법

1. exif란?

교환 이미지 파일 형식 (Exif; EXchangable Image File format)

디지털 카메라에서 이용되는 이미지 파일 포맷이다.
이 데이터는 JPEG, TIFF 6.0과 RIFF, WAV 파일 포맷에서 이용되며
사진에 대한 정보를 포함하는 메타데이터를 추가한다.
Exif는 JPEG 2000, PNG나 GIF파일에서는 지원하지 않는다.

EXIF의 메타데이터

EXIF 메타데이터는 다음 정보를 포함한다.

  • 날짜와 시간 정보
  • 카메라 설정
  • 저작권 정보에 대한 설명

지리정보 기록

교환 이미지 파일 형식은 위치 정보를 기록하는 표준을 갖고 있다.
기존에는 GPS 수신기를 내장한 극소수의 카메라만이 사진이 찍힌 장소의 정보를 저장할 수 있었다.
니콘 D300이나 니콘 D90, 파인픽스 S5 Pro, (캐논 EOS 6D 는 내부 장착)는 카메라 플래시 연결부에 별도의 GPS 수신기를 장착하여 지리 정보를 기록할 수 있다. 기록된 GPS 데이터는 컴퓨터에서 다른 디지털 사진에도 추가될 수 있다.

그러나 최근에는 GPS 수신기를 장착하고 사진 촬영이 가능한 수많은 휴대폰과 태블릿PC 등이 있어
해당 기기로 사진 촬영을 할 경우 위치 정보를 같이 저장할 수 있는 옵션을 지원하여 위치 정보를 함께 기록하여 촬영하기 쉬워졌다.

Exif : 이미지 정보

Exif 데이터는 이미지 파일 자체에 끼워진다.
많은 그래픽 소프트웨어에서 Exif 데이터를 인식하고,
파일이 변경될 때에도 메타데이터를 보존한다.
단 구버전의 경우에는 해당되지 않는다.
많은 이미지 갤러리 프로그램 역시 Exif 데이터를 인식하고, 이미지 옆에 Exif 정보를 보여 준다.

Exif 메타데이터는

  • 카메라 제조사
  • 카메라 모델
  • 회전 방향
  • 날짜와 시간
  • 색 공간
  • 초점 거리
  • 플래시
  • ISO 속도
  • 조리개
  • 셔터 속도
  • gps
    등의 정보를 제공한다.

포토샵이나 라이트룸에서 사진을 import한 후 info를 확인하면 사진 정보를 바로 확인할 수 있는데, 이 사진이 갖고 있는 exif데이터로 확인하는 듯



2. JavaScript 로드 시 회전 픽스방법

전체 flow는 이렇습니다.

1
2
3
4
5
6
7
8
9
10
1. input file에서 image upload
2. File API중 FileReader를 사용하여 file의 data 확인
3. reader.onload 에서 Image 인스턴스 생성
4. read의 result값 == binary 데이터
5. img src에 result값 삽입
6. binary 데이터에서 orientation 관련 태그값 select => orientation 값 추출
7. orientation 값에 따라 img 회전
8. canvas 생성, img를 canvas에서 다시 그림 (drawImage)
9. 해당 canvas의 toDataURL를 사용하여 dataUrl추출
...

exif 중 - orientation 값

fileList => file => binary Data => exif의 주소값을 찾아서 사진 정보를 get해오기 (exif라는 라이브러리를 들춰보면 재밌는 것이!!많습니다.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
...
// Tiff : Tagged Image File Format
var TiffTags = EXIF.TiffTags = {
0x0100 : "ImageWidth",
0x0101 : "ImageHeight",
0x8769 : "ExifIFDPointer",
0x8825 : "GPSInfoIFDPointer",
0xA005 : "InteroperabilityIFDPointer",
0x0102 : "BitsPerSample",
0x0103 : "Compression",
0x0106 : "PhotometricInterpretation",
0x0112 : "Orientation", <==
0x0115 : "SamplesPerPixel",
0x011C : "PlanarConfiguration",
0x0212 : "YCbCrSubSampling",
0x0213 : "YCbCrPositioning",
0x011A : "XResolution",
0x011B : "YResolution",
0x0128 : "ResolutionUnit",
0x0111 : "StripOffsets",
0x0116 : "RowsPerStrip",
0x0117 : "StripByteCounts",
0x0201 : "JPEGInterchangeFormat",
0x0202 : "JPEGInterchangeFormatLength",
0x012D : "TransferFunction",
0x013E : "WhitePoint",
0x013F : "PrimaryChromaticities",
0x0211 : "YCbCrCoefficients",
0x0214 : "ReferenceBlackWhite",
0x0132 : "DateTime",
0x010E : "ImageDescription",
0x010F : "Make",
0x0110 : "Model",
0x0131 : "Software",
0x013B : "Artist",
0x8298 : "Copyright"
};
...

번거로운 작업이기 때문에.. 아래 라이브러리를 사용합니다.

개인적으로는 load-image-orientation가 좋습니다 :)
orientation값에 따른 회전 이외에도 crop기능도 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// load-image-orientation.js
switch (orientation) {
case 2:
// horizontal flip
ctx.translate(width, 0)
ctx.scale(-1, 1)
break
case 3:
// 180° rotate left
ctx.translate(width, height)
ctx.rotate(Math.PI)
break
case 4:
// vertical flip
ctx.translate(0, height)
ctx.scale(1, -1)
break
case 5:
// vertical flip + 90 rotate right
ctx.rotate(0.5 * Math.PI)
ctx.scale(1, -1)
break
case 6:
// 90° rotate right
ctx.rotate(0.5 * Math.PI)
ctx.translate(0, -height)
break
case 7:
// horizontal flip + 90 rotate right
ctx.rotate(0.5 * Math.PI)
ctx.translate(width, -height)
ctx.scale(-1, 1)
break
case 8:
// 90° rotate left
ctx.rotate(-0.5 * Math.PI)
ctx.translate(-width, 0)
break
}

라이브러리 내부를 보시면, orientation 값에 따라 image를 회전하는 것을 볼 수 있습니다.

이미지 resizing 함수도 따로 작업했었는데, 이번 이슈를 통해서 찾은 load-image 라이브러리에 리사이징관련된 메서드들도 있는 것을 확인했습니다.


참고링크

  1. https://ko.wikipedia.org/wiki/%EA%B5%90%ED%99%98_%EC%9D%B4%EB%AF%B8%EC%A7%80_%ED%8C%8C%EC%9D%BC_%ED%98%95%EC%8B%9D
  2. https://magnushoff.com/jpeg-orientation.html
  3. http://code.flickr.net/2012/06/01/parsing-exif-client-side-using-javaScript-2/