[JavaScript] 휴대폰 사진 업로드시 회전 방지[JavaScript] 휴대폰 사진 업로드시 회전 방지

Posted at 2020. 3. 30. 16:11 | Posted in JavaScript & jQuery/JavaScript






■ 휴대폰 사진 업로드시, 사진이 원하는 방향으로 올라가지 않는경우





사실 해당 포스팅의 제목인 「 휴대폰 사진 업로드시 회전 방지 」 라고 적었지만 이건 사실 어그로를 끌기위한 그런 제목이고


해당 포스팅은 그 해결방법을 제시하기 위한 


휴대폰, 스마트폰의 카메라로 찍은 사진을 웹 브라우저를 통해 업로드 할경우,


이미지의 가로, 세로가 변경되어 등록되는 경우가 존재한다.


이러한 이유는 EXIF( Exchangeable Image File Format )의 회전값 변경이 반영되지 않기에 생기는 이유인데.


아래 이미지는 초기 스마트 폰에서 자주 볼 수 있었던 문제이다.

( 자이로 센서( Gyro Sensor ) 등의 기술 발전으로 이런 문제는 많이 해결 되었지만, 이미지의 편집등 다른 작업 과정으로 현재에도 이런 문제를 맏닥드릴 수 있다. )









가로로 찍은 이미지의 경우 스마트폰 상에서는 분명 정상적으로 보여주지만.


실제 이미지의 EXIF 값을 보면 회전정보( Orientation )가 90° CW 가 적용되어 있는것을 알 수 있다.


이를 회전정보 값을 브라우저에서는 인식하지 않고 보여지는 문제이다.







   # EXIF( Exchangeable Image File Format ) 란?



   디지털 카메라 등에서 사용되는 이미지 파일 메타데이터 포맷으로,


   카메라가 촬영한 사진, 녹음파일에 시간 등의 각종 정보를 담기 위해 개발되었다. 즉, 


   JPEG, TIFF 6.0과 RIFF, WAV 포맷에 이미지나 소리에 대한 정보를 추가로 기록할 수 있다.


   디지털카메라의 보급으로 널리 활성화되었고 이미지 메타데이터의 사실상 표준 지위에 있다.


   EXIF 데이터는 이미지 파일의 일부로 저장되며,


   EXIF 데이터를 지원하는 소프트웨어 사용 시 이미지를 변경해도 데이터를 보존한다.



   출처 : 나무위키( https://namu.wiki/w/EXIF )






간단하게 이미지 파일 하나를 선택하여 마우스 오른쪽 버튼을 클릭하고


오른쪽으로 회전( T ) 을 선택해 보자.







회전 정보 : 90° CW 로 반영된 것을 확인할 수 있다.


이 렇게 회전된 파일을 <img src="스토브리그.jpg">로 올려서 브라우저로 확인을 해 본다면.



# 소스코드

<html>

<head>

<title>:: 스토브리그 ::</title>

<style type="text/css">

/* image-orientation:from-image; */

/* 포스팅 작성일 기준으로 파이어 폭스만 가능 */

</style>

</head>

<body>

<img src="stoveleague.jpg"/>

</body>

</html> 




# 출력결과




회전 정보 : 90° CW가 반영이 <img> 태그를 사용한 경우


브라우저에서 다시 정방향으로 돌려서 출력하는 모습을 확인 할 수 있다.


그렇지만 그냥 브라우저상에서 이미지 경로를 직접 입력하여 호출하는 경우


위 출력결과처럼 




현재 파이어 폭스 브라우저의경우 CSS에 image-orientation:from-image; 를 넣어주는 것만으로도


회전정보 값을 읽어들여 <img> 태그에 반영할 수 있지만


아직까지 크롬등의 다른 브라우저에서는 CSS4의 실험적 기능이기에 적용되어 있지 않다고 한다.


결국 자동으로 이러한 상황을 해결 할 수는 없는 상황이기에


사용자의 폰, 찍은 각도에 따라 업로드시 문제가 발생할 수 있다.









GitHub : https://github.com/exif-js/exif-js





■ EXIF-JS를 이용하여, 이미지 파일의 EXIF 정보 가져오기




예제 진행하기에 앞서 아래와 같이 스마트폰으로 촬영한 이미지 파일 하나의


ORIENTATION( 회전 정보 )를 변경하여 아예 이미지를 뒤집어 보자.





해당 포스팅의 예제와 바로 이어지는 예제는


위와 같이 준비한 이미지로 진행을 해보자.




# 소스코드

<html>
<head>
<title>:: JavaScript 이미지 EXIF 정보 추출 ::</title>
<style type="text/css">
    table {
        border-collapse:collapse;
        border:1px #000000 solid;
        width:100%;
    }

    table > thead > tr > th {
        background-color:#FFC0CB;
    }

    table > tbody > tr > td:nth-child(odd) {
        text-align:center;
    }

    table > tbody > tr > td:nth-child(even) {
        padding-left:10px;
    }

    #thumbnailImg {
        width:100%;
        height:auto;
    }
</style>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/exif-js"></script>
<script type="text/javascript">
    function uploadImgPreview() {

        // @breif 업로드 파일 읽기
        const fileInfo = document.getElementById( "upImgFile" ).files[0];
        const reader = new FileReader();

        // @details readAsDataURL( )을 통해 파일을 읽어 들일때 onload가 실행
        reader.onload = function() {

            EXIF.getData(fileInfo, () => {

                const tags = EXIF.getAllTags( fileInfo );

                for( let key in tags ) {

                    // @details 화면에 출력할 메타데이터 정보 테이블 행( row )을 만든다.
                    document.querySelector( "tbody" ).appendChild( document.createElement( "tr" ) );

                    // @breif 메타 데이터 : 키
                    let colKey = document.createElement( "td" );
                    colKey.innerText = key;
                    document.querySelector( "tbody > tr:last-child" ).appendChild( colKey );

                    // @breif 메타 데이터 : 값
                    let colData = document.createElement( "td" );
                    colData.innerText = JSON.stringify( tags[key], null, "\t" );
                    document.querySelector( "tbody > tr:last-child" ).appendChild( colData );
                }
            });

            // @details 파일의 URL을 Base64 형태로 가져온다.
            document.getElementById("thumbnailImg").src = reader.result;
        };

        if( fileInfo ) {

            // @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.
            reader.readAsDataURL( fileInfo );
        }
    }
</script>
</head>
<body>
    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->
    <input type="file" id="upImgFile" onChange="uploadImgPreview();" accept="image/*">
    <hr/>
    <img id="thumbnailImg" src="">
    <hr/>
    <table border="1">
        <thead>
            <tr>
                <th>메타</th>
                <th>값</th>
            </tr>
        </thead>
        <tbody></tbody>
    </talbe>
</body>
</html>




# 출력결과










참고 : https://www.impulseadventure.com/photo/exif-orientation.html





■ <IMG> TAG에 ORIENTATION 으로 축 보정하기





그럼 이제 이미지 EXIF 정보에서 Orientation 정보를 가지고 와서 이미지를 처음 사진이 적용되었을 때와 같은 결과를 만들어보자.








내가 변경한 ORIENTATION 정보에 맞추어서 강제로 변경을 해보는 것이다.





# 소스코드

<html>
<head>
<title>:: JavaScript 이미지 EXIF 정보 추출 ::</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/exif-js"></script>

<script type="text/javascript">
    function uploadImgPreview() {

        // @breif 업로드 파일 읽기
        const fileInfo = document.getElementById( "upImgFile" ).files[0];
        const reader = new FileReader();

        // @details readAsDataURL( )을 통해 파일을 읽어 들일때 onload가 실행
        reader.onload = function() {

            console.log( reader.result );
            document.getElementById( "thumbnailImg" ).src = reader.result;

            EXIF.getData( fileInfo, () => {

                const orientation = EXIF.getTag( fileInfo, "Orientation" );
                console.log( orientation );

                switch( orientation ) {

                    // @details 이미지 회전값이 0인경우 ( 정방향 )
                    case 1 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 0deg )";
                        break;

                    // @details 이미지 회전값이 180 기운 경우
                    case 3 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 180deg )";
                        break;

                    // @details 이미지 회전값이 270 기운 경우 ( 왼쪽으로 90 기운 경우 )
                    case 6 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 90deg )";
                        break;

                    // @details 이미지 회전값이 90 기운 경우
                    case 8 :
                        document.getElementById( "thumbnailImg" ).style.transform = "rotate( 270deg )";
                        break;
                }
            });
        };

        if( fileInfo ) {


            // @details readAsDataURL( )을 통해 파일의 URL을 읽어온다.
            reader.readAsDataURL( fileInfo );
        }
    }
</script>
</head>
<body>
    <!-- @breif accept 태그는 파일 업로드시 그것을 이미지 파일로 제한한다. -->
    <input type="file" id="upImgFile" onChange="uploadImgPreview();" accept="image/*">
    <h3># EXIF - Orientation 값 적용 </h3>
    <hr/>
    <img id="thumbnailImg" src="" style="width:100%;height:auto;">
    <hr/>
    <h3># 다이렉트로 띄우기</h3>
    <img src="./DSC_IMG.jpg" style="width:100%;height:auto;">
</body>
</html>





# 출력결과









Name __

Password __

Link (Your Website)

Comment

SECRET | 비밀글로 남기기