[Canvas]依據EXIF旋轉照片

  • 4975
  • 0
  • 2016-03-05

摘要:[Canvas]依據EXIF旋轉照片
之前有介紹過使用Canvas來將照片加上濾鏡的效果,可以讓照片有不同的樂趣。另一個會遇到的場景,則是使用Canvas來將橫的或上下顛倒的照片旋轉成正確的方向。

之前有介紹過使用Canvas來將照片加上濾鏡的效果-使用Canvas處理濾鏡效果,可以讓照片有不同的樂趣。另一個會遇到的場景,則是使用Canvas來將橫的或上下顛倒的照片旋轉成正確的方向。

會有這種需求,是因為在隨手使用智慧型手機拍照時,大家都會隨手地以各種方向拍照。大多數的智慧型手機中有陀螺儀,所以也就會把照片的轉置角度資訊記錄在照片的EXIF中。

而一般的照片檢視器會依據EXIF將照片轉正,但是,透過HTML的img來顯示照片時,卻無法自動轉正。透過Canvas的rotate功能,就可以讓我們依據需求對照片進行旋轉。

取得照片的EXIF資訊

要取得照片的EXIF,可以透過這一個套件-Github-exif-js,它也可以透過npm下載-exif-js on npm。使用方式很簡單,在網頁的Head區塊先載入exif.js,然後就可以使用EXIF.getData()取得照片的EXIF資訊,或是使用EXIF.getTag()取得EXIF中某個屬性,例如Orientation的資訊。

EXIF.getData(document.getElementById('imgElement'), function(){ 
  EXIF.getAllTags(this); 
  EXIF.getTag(this, 'Orientation'); 
}); 

Orientation總共有8個值:1~8,在JPEGClud的網頁-Exif Orientation中詳細的說明。

其中有四個值是鏡像翻轉,所以不需要處理。Orientation為1的話,就是沒有翻轉,所以也不需要處理。因此,只需要處理3,6,8這三個狀況就可以了。

使用Canvas旋轉照片

在Canvas上要旋轉圖片,只要執行Context.rotate()這個function就可以了。不過要注意到,因為圖片的旋轉是依據座標的原點進行旋轉。預設的旋轉座標原點是在畫布的(0,0)的位置,所以旋轉之後,整個圖片的位置會跑掉。所以在旋轉之前,先要把座標圓點設定在圖片的中央,再進行rotate()。使用Context.drawImage()時,還要注意到座標原點要設定回去。

var x = canvas.width / 2;
var y = canvas.height / 2;
var width = image.width;
var height = image.height;

context.translate(x, y);
context.rotate(angleInRadians);
context.drawImage(image, -width / 2, -height / 2, width, height);

完整的Example列出如下:


<!DOCTYPE html>
<html>
<head>
	<title></title>
	<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script> 
    <script type="text/javascript" src="https://raw.githubusercontent.com/exif-js/exif-js/master/exif.js"></script> 
	<script>

    var ImageHelper = {
        resizeAndRotateImage: function(inImageSource,inMaxLength,inSuccessCallback){
            var reader = new FileReader();
            reader.readAsDataURL(inImageSource);
            reader.onload = function(e){   
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext("2d");  
                var img = new Image();
                img.onload = function () {     
                    //設定長邊上限值
                    var max_Length = inMaxLength;

                    var imgWidth = img.width;
                    var imgHeight = img.height;           
                    
                    if (imgWidth > imgHeight) {
                        if (imgWidth > max_Length) {
                            imgHeight = Math.round(imgHeight *= max_Length / imgWidth);
                            imgWidth = max_Length;
                        }
                    } else {
                        if (imgHeight > max_Length) {
                            imgWidth = Math.round(imgWidth *= max_Length / imgHeight);
                            imgHeight = max_Length;
                        }
                    }

                    canvas.width = imgWidth;
                    canvas.height = imgHeight;

					var that = this;
                    EXIF.getData(img, function(){ 
                        var orientation = EXIF.getTag(that, 'Orientation');
                        alert(orientation);

                        if(orientation == 6 || orientation == 8|| orientation == 3)
                        {                            
                            var rotateAngle = 0;

                            switch(orientation){
	                        	case 3:
	                        		rotateAngle = 180;
	                        		break;
	                        	case 6:
	                        		rotateAngle = 90;
	                                canvas.width = imgHeight;
	                                canvas.height = imgWidth;
	                        		break;
	                        	case 8:
	                        		rotateAngle = -90;
	                                canvas.width = imgHeight;
	                                canvas.height = imgWidth;
	                        		break;
	                        }
                            
                            var x = canvas.width / 2;
                            var y = canvas.height / 2;
                            
                            ctx.translate(x, y);
                            ctx.rotate(rotateAngle*Math.PI/180);

                            ctx.drawImage(img, (-imgWidth / 2), (-imgHeight / 2), imgWidth, imgHeight);
                        }
                        else
                        {
                            ctx.drawImage(img, 0, 0, imgWidth, imgHeight);
                        }
                    });

                    
                    var res = canvas.toDataURL("image/jpeg", 1.0);                
                    inSuccessCallback(res);  
                };
                
                img.src = e.target.result;
            };
        }
    };	
	function previewImage() {		
        var file = document.getElementById("uploadImage").files[0];
        ImageHelper.resizeAndRotateImage(file,400,function(resizeImageObj){
                $("#preview").attr("src",resizeImageObj);
            });
    }
	</script>
</head>
<body>
	<input type="file" id="uploadImage"  onchange="previewImage()">
	<hr/>
    <img id="preview" />
</body>
</html>

參考