如何在移动网页浏览器中使用input捕获照片后在canvas上以正确的方向绘制照片?

我正在制作一个简单的移动应用程序,允许访客通过使用html5 input [type = file]元素捕捉照片。 然后,我将显示在网上预览,然后访问者可以select将照片上传到我的服务器用于其他目的(即:上传到FB)

当我用iPhone拍照并垂直放置时,我发现照片的方向有问题。照片的标签方向正确。 但是,当我尝试使用drawImage()方法将其绘制到canvas中时,它将绘制90度旋转。

我试图用4个方向拍照,其中只有一个可以在canvas上画出正确的图像,有些则是旋转的,甚至是倒过来的。

那么,我很困惑,得到正确的方向来解决这个问题…感谢您的帮助…

这里是我的代码,主要是从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> 

您需要阅读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; } }; 

本杰出的回答指出了我的正确方向,但据我所知,实际的轮换是不正确的(至less他们是为我而言),并没有涵盖所有可能的情况。 下面的解决scheme为我工作。 它基于JavaScript-Load-Image库 (通过这个伟大的SO问题find )中find的一个。 请注意,我还必须将Canvas上下文转换为中心,因为它在旋转时从左上angular开始)。

 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; } }; 

将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); }); 

方向块(使用翻译和旋转)是从https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image-orientation.js复制,所以我认为它很好的certificate。; 它对我来说当然是完美的,而其他的方法却没有。

如果你只是想要方向标签,使用exif.js :

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

在我的testing中,iOS相机只返回1,3,6或8。

基于你的答案,我创build了一个function,以自动旋转iphone照片正确的方向。
只需传入一个input.files [0]和一个可选的最大宽度或高度,它将输出一个用于表单提交的blob。
https://github.com/gonnavis/iphone_photo_rotation_adjust