[TIL] 모바일 환경에서 업로드한 이미지 회전 방지

minami·2025년 5월 31일

일개미

목록 보기
7/13
post-thumbnail

📸 이미지가 자꾸 90도 돌아가는 이유 (feat. EXIF)

최근 갑자기 회사 서비스 사용자가 몰리는 일이 있었는데, 감사하게도 일시적으로나마 사용자가 많아지니까 이용후기를 남겨주는 사용자들도 좀 있었다. 그래서 나름 흐뭇한 마음이 있었는데, 사용자가 작성한 후기를 보다 보니 어떤 이미지는 멀쩡한데 어떤 이미지는 왼쪽으로 90도 돌아가는 현상이 있었다.

업로드하는 과정에서 프론트 문제인가 싶어서 찾아봤는데 EXIF Orientation이라는 게 문제가 될 수 있다는 점을 알게 되었다.

사실 결론을 미리 말하자면, 서버에서 따로 이미지 리사이징이나 썸네일 등을 처리해주고 있어서 후기 기능을 개발하던 당시에도 서버에서 이미지 회전 문제를 해결하느라 골머리를 앓았던 적이 있었다. 그런데 최근에 이미지 처리를 Cloud Run과 Cloud Function으로 하도록 바꾸면서 어딘가 다시 문제가 생겼던 모양이다. 그래서 서버에서 다시 관련 처리를 해주도록 하면서 해결되긴 했다.

하지만 프론트에서도 이미지 회전을 막기 위한 처리가 필요하다면 방법을 알아두는 것이 좋을 것 같아서 알아낸 방법을 대충 정리하여 남긴다.


🤔 도대체 왜 이미지가 돌아가는 거지?

모바일로 사진을 찍으면, 우리가 보는 화면은 '정방향'이지만 실제 이미지 파일은 회전되어 있을 수도 있다. 대신 그 정보를 이미지 안의 EXIF 메타데이터에 담아둔다. 대표적인 게 Orientation 값이다.

근데 문제는 여기서 시작된다.

  • 대부분의 브라우저는 이 Orientation 값을 제대로 읽지 못한다.
  • 그래서 이미지가 돌아가 있는 채로 업로드되거나, 미리보기에서도 돌아가 보이게 되는 거다.

🛠️ 해결하는 방법

이런 문제를 막으려면, 이미지를 업로드하기 전에 Orientation 값을 읽어서 canvas에 올바른 방향으로 다시 그려주는 작업이 필요하다.

예를 들어 exif-js 같은 라이브러리를 써서 Orientation 값을 읽고, canvas를 이용해 회전 처리를 할 수 있다.

간단한 예시는 이런 식이다:

import EXIF from 'exif-js';

function fixImageOrientation(file, callback) {
  const reader = new FileReader();
  reader.onload = function (e) {
    const img = new Image();
    img.onload = function () {
      EXIF.getData(img, function () {
        const orientation = EXIF.getTag(this, 'Orientation');
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        // orientation 값에 따라 canvas 크기랑 회전 방향 설정
        // 예: orientation === 6이면 90도 회전
        // 자세한 로직은 상황에 맞게 커스터마이징 필요

        callback(canvas.toDataURL('image/jpeg'));
      });
    };
    img.src = e.target.result;
  };
  reader.readAsDataURL(file);
}

귀찮다면 compressorjs, pica, browser-image-compression 같은 라이브러리를 써도 된다. 요즘엔 orientation까지 알아서 처리해주는 고마운 도구들이 꽤 많다.


✅ 정리하자면

  • 스마트폰은 사진을 회전시키지 않고, EXIF에 방향 정보를 남긴다.
  • 웹에서는 이걸 잘 못 읽는다. 특히 WebView에선 더 심하다.
  • 업로드 전에 orientation 값 확인해서 canvas로 방향 맞춰주자.
profile
함께 나아가는 개발자💪

0개의 댓글