본문 바로가기

파일 형식 백과사전

아이폰 사진을 PC로 옮겼더니 옆으로 눕습니다, 파일 안에서 달라진 건 1바이트였습니다

여기 사진 파일이 두 개 있습니다. 크기는 둘 다 60,607바이트로 같고, 그림 데이터만 뽑아 지문(SHA-256)을 찍어 보면 그 값도 똑같습니다. 그런데 하나는 화면에서 옆으로 눕고, 하나는 똑바로 섭니다.

폰에서는 멀쩡하던 세로 사진이 컴퓨터로 옮기자마자 눕는 일이 자주 생깁니다. 파일이 옮기다 상한 걸까 싶지만, 두 파일을 바이트 단위로 맞춰 보니 다른 자리는 딱 한 군데였습니다. 그 한 바이트가 무엇인지 직접 만들어 확인했습니다.

 

같은 그림 데이터를 담은 두 JPG를 Microsoft Edge로 연 실제 화면. Orientation 1로 저장한 파일은 건물이 옆으로 누워 보이고 Orientation 6으로 저장한 파일은 똑바로 서 보인다. 두 파일 모두 60,607바이트이고 그림 데이터의 SHA-256도 같으며, 파일 전체에서 다른 바이트는 49번째 하나로 0x01과 0x06이다

 

사진에는 방향을 적어 두는 칸이 따로 있습니다

스마트폰 카메라의 센서는 폰을 어떻게 들고 있든 늘 같은 방향으로 빛을 받습니다. 세로로 들고 찍어도 파일에 저장되는 픽셀은 가로로 누운 상태 그대로입니다.

대신 카메라는 사진 정보(EXIF) 안에 Orientation이라는 칸을 두고 "이 그림은 시계 방향으로 90도 돌려서 보여 주세요" 같은 지시를 적어 둡니다. 그림을 실제로 돌려 저장하는 것보다 숫자 하나만 적는 편이 빠르고 화질 손실도 없기 때문입니다.

그래서 문제가 생기는 지점은 파일이 아니라 여는 쪽입니다. 이 칸을 읽는 프로그램은 알아서 돌려 주고, 안 읽는 프로그램은 저장된 픽셀 그대로 눕혀서 보여 줍니다.


값 1과 값 6, 파일에서 무엇이 달랐나

세로로 찍은 사진을 흉내 내 1200x900 가로 픽셀에 세로 구도를 담고, Orientation 값만 1과 6으로 바꿔 두 장을 저장했습니다. 측정 환경은 윈도우 11, 파이썬 3.14.3, Pillow 12.2.0입니다.

ori_1.jpg 와 ori_6.jpg 파일 크기: 60607 / 60607 B
바이트가 다른 위치 개수: 1 -> [49]
  offset 49 : 0x01 vs 0x06

8개 파일의 그림 데이터가 모두 같은가: True

값 1부터 8까지 여덟 장을 만들어도 그림 데이터는 여덟 장 모두 완전히 같고, 파일 크기도 60,607바이트로 한 글자도 차이가 없었습니다. 방향 값은 그림을 건드리지 않는 메모 한 줄이라는 뜻입니다.

 

값은 1부터 8까지 있고 각각 다른 처리를 뜻합니다. Pillow가 태그를 반영해 읽었을 때 나오는 크기를 값별로 재 봤습니다. 저장된 픽셀은 전부 1200x900입니다.

Orientation 보여 줄 때 처리 태그 반영한 크기
1 그대로 1200x900
2 좌우 뒤집기 1200x900
3 180도 회전 1200x900
4 상하 뒤집기 1200x900
5 뒤집고 시계 270도 900x1200
6 시계 90도 (세로로 찍었을 때 가장 흔함) 900x1200
7 뒤집고 시계 90도 900x1200
8 시계 270도 900x1200

5부터 8까지는 가로세로가 뒤바뀝니다. 내 사진이 어느 값인지는 파이썬 한 줄로 확인됩니다. 274가 Orientation 칸의 번호입니다.

from PIL import Image

im = Image.open("IMG_0001.jpg")
print(im.size)                    # 저장된 픽셀: (1200, 900)
print(im.getexif().get(274))      # 방향 값: 6

윈도우 11은 읽습니다, 그런데도 눕는다면

같은 파일을 세 군데에서 확인해 봤습니다. 결과가 갈렸습니다.

확인한 곳 방향 값 반영 보이는 크기
윈도우 탐색기 속성 읽음 900 x 1200
웹브라우저(Edge) 읽음 세로로 바로 섬
파이썬 Pillow 기본 읽기 안 읽음 1200 x 900

윈도우 11 탐색기는 저장된 픽셀이 1200x900인데도 속성에 900x1200이라고 표시했습니다. 요즘 브라우저와 윈도우 기본 앱은 이 칸을 읽는다는 뜻입니다.

그런데도 사진이 눕는다면 대개 파일을 한 번 거쳐 온 경우입니다. 오래된 뷰어, 문서 프로그램에 끼워 넣기, 이미지 처리 스크립트를 지나면서 태그가 떨어져 나간 것입니다.

 

가장 흔한 함정은 용량 줄이기입니다

세로 사진(값 6)을 놓고 세 가지 처리를 해 본 결과입니다.

처리 결과 픽셀 방향 값 이후 보이는 모습
열었다가 그대로 저장 1200x900 사라짐 가로로 누움
크기만 절반으로 줄여 저장 600x450 사라짐 가로로 누움
태그대로 돌려서 저장 900x1200 사라짐 세로로 바로 섬

세 경우 모두 태그가 사라졌습니다. 앞의 두 개는 돌리라는 지시만 없어지고 누운 픽셀은 그대로라서, 이때부터는 어떤 프로그램에서 열어도 영영 눕습니다. 사진 용량을 줄이고 나서 갑자기 눕기 시작했다면 이 경우입니다.

제대로 고치려면 태그를 믿지 말고 픽셀을 실제로 돌려 저장해야 합니다. Pillow의 exif_transpose가 방향 값을 읽어 그만큼 회전시켜 줍니다.

 

from PIL import Image, ImageOps

im = ImageOps.exif_transpose(Image.open("IMG_0001.jpg"))
im.save("fixed.jpg", quality=95)   # 900x1200 으로 저장됨

사진 앱에서 회전 버튼을 눌러 저장하는 것도 같은 일을 합니다. 여러 장을 한꺼번에 정리해야 한다면 위 코드를 폴더 단위로 돌리면 됩니다.


자주 묻는 질문

Q. 눕는 사진은 화질이 상한 건가요?
아닙니다. 여덟 개 값으로 저장한 파일의 그림 데이터가 전부 같았습니다. 방향 값은 그림을 손대지 않습니다.

Q. 돌려서 저장하면 화질이 나빠지나요?
JPG는 저장할 때마다 조금씩 손실이 생깁니다. 90도 단위 회전만 하는 무손실 회전 기능을 쓰는 편이 안전하고, 여의치 않으면 품질을 95 이상으로 두세요.

Q. 폰에서는 똑바로 보이는데 카톡으로 보내면 눕습니다.
전송 과정에서 사진을 다시 저장하며 태그가 떨어지는 경우입니다. 원본 보내기로 전송하거나, 보내기 전에 회전해서 저장해 두면 방향이 유지됩니다.

Q. 방향 값을 지우면 되나요?
지우면 누운 픽셀만 남아 상황이 나빠집니다. 지울 것이 아니라 픽셀을 돌려 맞춰야 합니다.

 

 

사진에는 방향 말고도 찍은 날짜와 장소가 같은 방식으로 적혀 있습니다. 그래서 사진을 한 번 다시 저장할 때 촬영 날짜가 통째로 사라지는 일도 같은 자리에서 벌어지고, 위치 정보를 지우는 방법 역시 이 EXIF를 다루는 이야기입니다.

 

위 바이트 값과 크기는 윈도우 11에서 파이썬 3.14.3과 Pillow 12.2.0으로 파일을 직접 만들어 저장하고 다시 읽어 얻은 값이며, 화면 비교는 Microsoft Edge로 같은 파일을 열어 캡처한 것입니다.