Html 在移动网络浏览器中使用 input[type='file'] 捕获照片后,如何在画布中以正确的方向绘制照片?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19463126/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to draw photo with correct orientation in canvas after capture photo by using input[type='file'] in mobile web browser?
提问by Rock Yip
I am making a simple web app in mobile which allow visitor to capture photo by using html5 input[type=file] element. Then I will display it on the web for preview, and then visitor can choose to upload the photo to my server for other purpose(ie: upload to FB)
我正在移动设备中制作一个简单的网络应用程序,它允许访问者使用 html5 input[type=file] 元素捕获照片。然后我将它显示在网络上进行预览,然后访问者可以选择将照片上传到我的服务器以用于其他目的(即:上传到FB)
I find a problem on the orientation of photo when I take photo using my iPhone and hold vertically.The photo is in a correct orientation in tag. However, when I try to draw it into canvas by using drawImage() method, it is drawn 90 degree rotated.
当我使用 iPhone 拍照并垂直握住照片时,我发现照片方向有问题。照片在标签中的方向正确。但是,当我尝试使用 drawImage() 方法将其绘制到画布中时,它被旋转了 90 度。
I have tried to take photo in 4 orientations, only one of them can draw a correct image in canvas, others are rotated or even flipped upside down.
我尝试了 4 个方向的照片,其中只有一个可以在画布上绘制正确的图像,其他方向旋转甚至倒置。
Well, I am confused to get the correct orientation to fix this problem... Thanks for helping...
好吧,我很困惑获得正确的方向来解决这个问题......谢谢你的帮助......
here is my code, mostly copy from MDN
这是我的代码,主要是从 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>
采纳答案by Ben Wong
You'll need to read the exif data and check if exif.Orientation is one of the following:
您需要阅读 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;
}
};
回答by gburning
Ben's great answer pointed me in the right direction but as far as I can tell the actual rotations are incorrect (at least they were for me) and don't cover all possible cases. The solution below worked for me. It is based on the one found in the JavaScript-Load-Image library(which I found via this great SO question). Note that I also had to translate the Canvas context to the center as it originates from the top left corner when rotating).
Ben 的出色回答为我指明了正确的方向,但据我所知,实际旋转是不正确的(至少对我来说是这样)并且没有涵盖所有可能的情况。下面的解决方案对我有用。它基于在JavaScript-Load-Image 库中找到的库(我通过这个很棒的 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;
}
};
回答by Andy Lorenz
add exif.jsto your project, then:
将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);
});
The orientation block (using translate and rotate) is copied from https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image-orientation.jsand so I consider it well proven. It certainly worked perfectly for me, whereas other approaches didn't.
方向块(使用平移和旋转)是从https://github.com/blueimp/JavaScript-Load-Image/blob/master/js/load-image-orientation.js复制的,所以我认为它得到了很好的证明。它当然对我很有效,而其他方法则不然。
回答by Felix Turner
回答by gonnavis
Based on your answers, I created a function to auto rotate iphone photo to right direction.
Just pass in an input.files[0] and an optional max width or height, it'll output a blob used for form submit.
https://github.com/gonnavis/iphone_photo_rotation_adjust
根据您的回答,我创建了一个功能来自动将 iphone 照片旋转到正确的方向。
只需传入一个 input.files[0] 和一个可选的最大宽度或高度,它会输出一个用于表单提交的 blob。
https://github.com/gonnavis/iphone_photo_rotation_adjust