How to draw a photo with the correct orientation in the canvas after taking a photo using the input [type = 'file'] in a mobile browser?

I am making a simple web application on a mobile device that allows a visitor to take a photo using the [type = file] html5 input element. Then I will show it on the Internet for preview, and then the visitor can choose to upload the photo to his server for other purposes (for example: upload to FB)

I find the problem with the orientation of the photo when I take a photo using my iPhone and keep it upright. The photo is in the correct orientation in the tag. However, when I try to draw it in the canvas using the drawImage () method, it rotates 90 degrees.

I tried to take a photo in 4 directions, only one of them can draw the correct image in the canvas, the others are turned or even turned upside down.

Well, I'm confused to get the right orientation to fix this problem ... Thanks for helping ...

here is my code, basically a copy from 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 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> 
+50
javascript html5 html5-canvas canvas drawimage
Oct 19 '13 at 6:27
source share
5 answers

You will need to read exif data and check if exif.Orientation is one of the following:

 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; } }; 
+39
Oct 19 '13 at 6:40
source share

Ben's big answer pointed me in the right direction, but as far as I can tell, the actual rotations are wrong (at least they were for me) and do not cover all possible cases. The solution below worked for me. It is based on the library found in JavaScript-Load-Image (which I found through this big SO question ). Note that I also had to translate the Canvas context to the center, as it arises from the upper left corner during rotation).

 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; } }; 
+35
May 14 '15 at 16:54
source share

add exif.js to your project and then:

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

The orientation block (using translation and rotation) is copied from https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image-orientation.js , so I think this is well proven. This certainly worked fine for me, while there were no other approaches.

+15
Jun 10 '16 at 14:12
source share

If you only need the Orientation tag, exif.js :

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

In my tests, the iOS camera returns only 1,3,6 or 8.

+3
Apr 04 '16 at 1:13
source share

Based on your answers, I created a function to automatically rotate iphone photos in the right direction.
Just pass the file input.files [0] and an extra maximum width or height, it will output the blob used to submit the form.
https://github.com/gonnavis/iphone_photo_rotation_adjust

0
Sep 07 '17 at 14:27
source share