본문 바로가기
개발이야기/js

왜 사진을 옆으로 찍니..

by 박제아성 2023. 5. 17.

이번 주제는 웹뷰 개발을 하다가 발생한 사소한 문제 기억하기 위함이다!

 

문제상황

이미지 업로드를 웹뷰로 개발했는데, 업로드된 이미지가 회전되어 나오는 기이한 현상이 발생했다..

 

 

왜?

 

답은 구글에서 검색하면 나와 있어서 쉽게 파악할 수 있었다.

 

이유는 이미지의 메타데이터 때문이었다. 사진에는 컴퓨터가 알면 좋을 다양한 정보를 담고 있다. 단순히 사진을 구성하는 픽셀에 따른 색상 값이 아니라 찍힌 사진을 인간이 이해할 수 있는 정보들을 담고 있다.

예를 들어, 카메라 제조사, 카메라 모델, 촬영날짜, 실제 크기, 렌즈, 조리개, EXIF 등 생각보다 많은 정보들이 있다. 

 

그중에! 이미지가 돌아간 이유는 핸드폰을 이용해서 가로로 사진을 찍어서 그렇다~

 

우리가 갤러리를 볼 때는 가로로 찍은 사진도 똑바로 보고 있다. 왜냐? 정확하지는 않지만 갤러리가 자동으로 보정을 하고 있기 때문이다. 그래서 돌아간 사진을 웹에 업로드하니 누워있는 모습을 볼 수 있는 것이다!

 

해결방법

라이브러리를 통해 메타데이터를 변경해서 서버에 업로드해주면 된다. 한 줄로 끝나는 방법이지만 해당 코드를 만드는데 시간이 좀 오래 걸렸다.. 라이브러리 사용보다는 이미지를 업로드하는 폼 형식에 혼란을 느껴서 그랬다 ㅠ

 

 

자 일단 라이브러리부터 받아보자.

 

npm install blueimp-load-image

 

 

마지막 퍼블리시가 2년 전이지만 해당 로직을 처리하는데 많은 시간을 들이는 것보다.. 빠르게 끝내는 게 건강에 더 좋을 것 같다..ㅎ

깃허브에 가이드를 읽으면서 쭉쭉 내리다 보면 우리가 원하는 orientation을 찾을 수 있다. 값에 따라서 사진의 방향이 바뀌는 걸 볼 수 있고, 우리가 원하는 값은 1인 것도 알 수 있다. 

 

하지만 항상 1이 옳은 것은 아니다. 어떤 사람에 따라서는 사진을 옆으로 찍고 싶어할 수도 있고.. 그런데 모든 경우를 고려하는 것은 굉장히 어려운 일이기 때문에 일단 한 방향으로 고정하는 방향으로 했다.

 

(인스타그램 사진 업로드를 웹으로 실험해 보니, 사진 올리기 전에 편집기능을 제공하면 방향 따위 올리는 사람이 정해랏 할 수 있다.)

 

하지만! 그정도의 노력을 투입할 게 아니었기 때문에 방향을 고정하는 방법으로..!

 

아무튼 간략하게 코드를 확인해 보면

 

// 공식문서
loadImage(
  fileOrBlobOrUrl,
  function (img, data) {
    if (data.imageHead && data.exif) {
      // Reset Exif Orientation data:
      loadImage.writeExifData(data.imageHead, data, 'Orientation', 1)
      img.toBlob(function (blob) {
        loadImage.replaceHead(blob, data.imageHead, function (newBlob) {
          // do something with newBlob
        })
      }, 'image/jpeg')
    }
  },
  { meta: true, orientation: true, canvas: true, maxWidth: 800 }
)

 

이렇게 제공하는데, 우리는 타입스크립트를 쓰기 때문에 이대로 코드를 작성하면 타입스크립트는 에러를 낼 것이다. 설정파일이나 린트에 따라 다를 수 있지만 중간중간 타입 에러에 타입체크를 해주면 에러를 지울 수 있다..

 

원리는 간단하다.

 

exif는 메타데이터이다. exif 데이터에 'Orientation' 값을 자유롭게 변경하고, 파라미터로 받은 이미지를 blob 형태로 바꾼 후에 위에서 바꾼 메타데이터를 교체하는 로직이다. 

 

교체 후에는 개발자가 원하는 방법으로 코드를 짜면 된다. 나는 미리 보기를 보여주고 확인을 누르면 서버에 전송을 해야했기에 newBlob을 상태에 담아서 미리보기를 구현했다.

 

굉장히 쉬워 보이지만 나는 삽질을 조금 했다. 기존의 미리보기를 만드는 로직이 File을 넘겨서 URL.createIbjectURL을 사용했는데, blob형태를 FIle 객체로 바꿔서 넘기려고 하다가 엄청난 시간 낭비를 하게 됐다. 

 

구글링을 해보면 'convert blob to File'의 답이 나와 있는데 가능하지 않았다.. 둘의 개념도 정확하지 않은 상태에서 구현만 하려고 하니 밑바닥이 드러난 것..!

 

Blob??

blob은 binary large object이다. 이름에서 풍겨오지 않나요? 큰 데이터를 저장할 수 있을 것 같은 느낌이 듭니다. 웹에서 큰 데이터는 이미지, 비디오, 소리와 같은 멀티데이터이겠지요

( 검색해 보니 blob은 4294967295 bytes (4GB) 만큼 저장이 가능하다고 합니다. )

 

여기서 가장 중요한 점!!

 

File 객체는 Blob객체를 상속받은 객체

 

File과 Blob은 완전히 동일한 객체는 아니지만 Blob을 같이 쓸 수 있겠네? 하는 생각이 들었습니다. 그래서 Blob 객체를 File 객체로 변환하는 것이 아니라 loadImage를 통해 만들어진 newBlob을 상태에 담아서 렌더링을 해보니 File과 같은 결과가 나온 것!

 

이걸 못해서 끙끙 앓던 제가 밉습니다...

 

마무리이

때문에 정말 무조건 알아야 하는 지식은 아닐 수 있지만 File API에 대해서 자세하게 알면 다양한 콘텐츠를 개발하는데 도움이 될 것 같습니다.

유튜브, 인스타, 메타, 틱톡 등등 거대 회사들이 웹 내에서 컨텐츠를 어떻게 처리하는지 공부해 보면 도움이 될 것 같습니다..! 해외 유명 사이트도 참고하기 좋지만 국내 기업들도 개발하면서 참고할 곳이 많은 것 같아요..! 웹뷰 개발을 많이 하다 보니 웹뷰를 많이 쓴 앱들을 찾는데.. 다들 리스펙 합니다..!

고작 파일 하나에 한숨을 쉬어버린 멍충이지만,, 일단 진행하고 결과를 얻는 게 성장이다..!

댓글