2013-10-19 11 views
50

我正在製作一個簡單的網絡應用程序,允許訪問者通過使用html5 input [type = file]元素捕獲照片。然後,我將顯示它在網絡上進行預覽,然後訪問者可以選擇將照片上傳到我的服務器用於其他目的(即:上傳到FB)如何在移動網絡瀏覽器中使用輸入[type ='file']捕獲照片後在畫布中以正確的方向繪製照片?

我在拍照時發現照片的方向有問題使用我的iPhone和垂直舉行。照片是在一個正確的方向標籤。 但是,當我嘗試使用drawImage()方法將其繪製到畫布中時,它會繪製90度旋轉。

我試圖以4個方向拍照,只有其中一個可以在畫布上繪製正確的圖像,其他人可以旋轉甚至翻轉。

嗯,我很困惑,以獲得正確的方向來解決這個問題... 感謝您的幫助......

這裏是我的代碼,其中大部分來自MDN

複製
<div class="container"> 
      <h1>Camera API</h1> 

      <section class="main-content"> 
       <p>A demo of the Camera API, currently implemented in Firefox and Google Chrome on Android. Choose to take a picture with your device's camera and a preview will be shown through createObjectURL or a FileReader object (choosing local files supported too).</p> 

       <p> 
        <form method="post" enctype="multipart/form-data" action="index.php"> 
         <input type="file" id="take-picture" name="image" accept="image/*"> 
         <input type="hidden" name="action" value="submit"> 
         <input type="submit" > 
        </form> 
       </p> 

       <h2>Preview:</h2> 
       <div style="width:100%;max-width:320px;"> 
        <img src="about:blank" alt="" id="show-picture" width="100%"> 
       </div> 

       <p id="error"></p> 
       <canvas id="c" width="640" height="480"></canvas> 
      </section> 

     </div> 


     <script> 
      (function() { 
       var takePicture = document.querySelector("#take-picture"), 
        showPicture = document.querySelector("#show-picture"); 

       if (takePicture && showPicture) { 
        // Set events 
        takePicture.onchange = function (event) { 
         showPicture.onload = function(){ 
          var canvas = document.querySelector("#c"); 
          var ctx = canvas.getContext("2d"); 
          ctx.drawImage(showPicture,0,0,showPicture.width,showPicture.height); 
         } 
         // Get a reference to the taken picture or chosen file 
         var files = event.target.files, 
          file; 
         if (files && files.length > 0) { 
          file = files[0]; 
          try { 
           // Get window.URL object 
           var URL = window.URL || window.webkitURL; 

           // Create ObjectURL 
           var imgURL = URL.createObjectURL(file); 

           // Set img src to ObjectURL 
           showPicture.src = imgURL; 

           // Revoke ObjectURL 
           URL.revokeObjectURL(imgURL); 
          } 
          catch (e) { 
           try { 
            // Fallback if createObjectURL is not supported 
            var fileReader = new FileReader(); 
            fileReader.onload = function (event) { 
             showPicture.src = event.target.result; 

            }; 
            fileReader.readAsDataURL(file); 
           } 
           catch (e) { 
            // Display error message 
            var error = document.querySelector("#error"); 
            if (error) { 
             error.innerHTML = "Neither createObjectURL or FileReader are supported"; 
            } 
           } 
          } 
         } 
        }; 
       } 
      })(); 
     </script> 

回答

39

你」會需要讀取EXIF數據,並檢查是否exif.Orientation是下列之一:

fileReader.onloadend = function() { 

    var exif = EXIF.readFromBinaryFile(new BinaryFile(this.result)); 

    switch(exif.Orientation){ 

     case 8: 
      ctx.rotate(90*Math.PI/180); 
      break; 
     case 3: 
      ctx.rotate(180*Math.PI/180); 
      break; 
     case 6: 
      ctx.rotate(-90*Math.PI/180); 
      break; 


    } 
}; 
+1

它工作完美。非常感謝。 fileReader的讀取方法需要從readAsDataURL(文件)更改爲readAsBinaryString(文件) –

+1

感謝您的偉大答案,本!但是,我不太確定輪換是否正確。請參閱下面的答案。 – gburning

+1

@gburning我確實同意你的回答比較好,涵蓋了大多數場景!請使用下面的答案而不是我的答案。 –

35

Ben的偉大回答我指出了正確的方向,但據我可以告訴實際的旋轉是不正確的(至少它們是我的),並沒有涵蓋所有可能的情況。下面的解決方案爲我工作。它基於JavaScript-Load-Image library(我通過this great SO question找到)中找到的那個。請注意,我還必須將Canvas上下文轉換爲中心,因爲它在旋轉時從左上角開始)。

fileReader.onloadend = function() { 

    var exif = EXIF.readFromBinaryFile(new BinaryFile(this.result)); 

    switch(exif.Orientation){ 

     case 2: 
      // horizontal flip 
      ctx.translate(canvas.width, 0); 
      ctx.scale(-1, 1); 
      break; 
     case 3: 
      // 180° rotate left 
      ctx.translate(canvas.width, canvas.height); 
      ctx.rotate(Math.PI); 
      break; 
     case 4: 
      // vertical flip 
      ctx.translate(0, canvas.height); 
      ctx.scale(1, -1); 
      break; 
     case 5: 
      // vertical flip + 90 rotate right 
      ctx.rotate(0.5 * Math.PI); 
      ctx.scale(1, -1); 
      break; 
     case 6: 
      // 90° rotate right 
      ctx.rotate(0.5 * Math.PI); 
      ctx.translate(0, -canvas.height); 
      break; 
     case 7: 
      // horizontal flip + 90 rotate right 
      ctx.rotate(0.5 * Math.PI); 
      ctx.translate(canvas.width, -canvas.height); 
      ctx.scale(-1, 1); 
      break; 
     case 8: 
      // 90° rotate left 
      ctx.rotate(-0.5 * Math.PI); 
      ctx.translate(-canvas.width, 0); 
      break; 


    } 
}; 
+1

本文提出的解決方案是否適合所有類型的圖像,肖像,風景...我主要面對與EXIF.Orientation = 6的肖像圖像的問題。圖像從頂部或底部切割。我在ctx.drawImage方法中嘗試了多個值的選項: ctx.drawImage(img,0,0); ctx.drawImage(img,-img.width/2,-img.length/2); ctx.drawImage(img,0,-img.length/2); ctx.drawImage(img,-img.width/2,0); 但不能正確。在這裏添加新的問題:http://stackoverflow.com/questions/32968805/javascript-exif-based-rotation-using-canvas-element –

+2

將是一個更好的答案,如果它是一個完整的例子 –

+1

@ShammelLee足夠公平。 :)完成。 – gburning

3

如果你只想方向標籤,使用exif.js

EXIF.getData(file, function() { 
    alert(this.exifdata.Orientation); 
}); 

在我的測試中,iOS的相機只返回1,3,6或8

15

添加exif.js到項目,則:

EXIF.getData(file,function() { 
    var orientation = EXIF.getTag(this,"Orientation"); 
    var can = document.createElement("canvas"); 
    var ctx = can.getContext('2d'); 
    var thisImage = new Image; 
    thisImage.onload = function() { 
    can.width = thisImage.width; 
    can.height = thisImage.height; 
    ctx.save(); 
    var width = can.width; var styleWidth = can.style.width; 
    var height = can.height; var styleHeight = can.style.height; 
    if (orientation) { 
     if (orientation > 4) { 
     can.width = height; can.style.width = styleHeight; 
     can.height = width; can.style.height = styleWidth; 
     } 
     switch (orientation) { 
     case 2: ctx.translate(width, 0);  ctx.scale(-1,1); break; 
     case 3: ctx.translate(width,height); ctx.rotate(Math.PI); break; 
     case 4: ctx.translate(0,height);  ctx.scale(1,-1); break; 
     case 5: ctx.rotate(0.5 * Math.PI); ctx.scale(1,-1); break; 
     case 6: ctx.rotate(0.5 * Math.PI); ctx.translate(0,-height); break; 
     case 7: ctx.rotate(0.5 * Math.PI); ctx.translate(width,-height); ctx.scale(-1,1); break; 
     case 8: ctx.rotate(-0.5 * Math.PI); ctx.translate(-width,0); break; 
     } 
    } 

    ctx.drawImage(thisImage,0,0); 
    ctx.restore(); 
    var dataURL = can.toDataURL(); 

    // at this point you can save the image away to your back-end using 'dataURL' 
    } 

    // now trigger the onload function by setting the src to your HTML5 file object (called 'file' here) 
    thisImage.src = URL.createObjectURL(file); 

}); 

取向塊(使用平移和旋轉)從複製,所以我認爲它很好的證明。它對我來說無疑是完美的,而其他方法則不然。

相關問題