Javascript 如何在移动web浏览器中使用输入[type=';file';]在捕获照片后在画布中绘制方向正确的照片?
我正在手机上制作一个简单的web应用程序,允许访问者使用html5输入[type=file]元素捕捉照片。然后我会在网上展示预览,然后访问者可以选择将照片上传到我的服务器,用于其他用途(即:上传到FB) 当我使用iPhone拍照并垂直握住时,我发现照片的方向有问题。照片在标签中的方向正确。 然而,当我尝试使用drawImage()方法将其绘制到画布中时,它被旋转了90度 我试着在4个方向上拍照,其中只有一个方向可以在画布上画出正确的图像,其他方向旋转甚至翻转 嗯,我很困惑如何找到正确的方向来解决这个问题。。。 谢谢你的帮助 这是我的代码,大部分是从MDN复制的Javascript 如何在移动web浏览器中使用输入[type=';file';]在捕获照片后在画布中绘制方向正确的照片?,javascript,html,canvas,html5-canvas,drawimage,Javascript,Html,Canvas,Html5 Canvas,Drawimage,我正在手机上制作一个简单的web应用程序,允许访问者使用html5输入[type=file]元素捕捉照片。然后我会在网上展示预览,然后访问者可以选择将照片上传到我的服务器,用于其他用途(即:上传到FB) 当我使用iPhone拍照并垂直握住时,我发现照片的方向有问题。照片在标签中的方向正确。 然而,当我尝试使用drawImage()方法将其绘制到画布中时,它被旋转了90度 我试着在4个方向上拍照,其中只有一个方向可以在画布上画出正确的图像,其他方向旋转甚至翻转 嗯,我很困惑如何找到正确的方向来解决
<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>
照相机应用程序接口
摄像头API的演示,目前在Android上的Firefox和Google Chrome中实现。选择使用设备的照相机拍照,预览将通过createObjectURL或FileReader对象显示(也选择支持的本地文件)
预览:
(功能(){
var takePicture=document.querySelector(“拍摄”),
showPicture=document.querySelector(#show picture”);
if(拍摄照片和放映照片){
//设置事件
takePicture.onchange=函数(事件){
showPicture.onload=函数(){
var canvas=document.querySelector(“#c”);
var ctx=canvas.getContext(“2d”);
ctx.drawImage(showPicture,0,0,showPicture.width,showPicture.height);
}
//获取对拍摄的照片或所选文件的引用
var files=event.target.files,
文件
如果(files&&files.length>0){
file=文件[0];
试一试{
//获取window.URL对象
var URL=window.URL | | window.webkitURL;
//创建对象URL
var imgURL=URL.createObjectURL(文件);
//将img src设置为ObjectURL
showPicture.src=imgURL;
//撤销对象URL
revokeObjectURL(imgURL);
}
捕获(e){
试一试{
//不支持createObjectURL时的回退
var fileReader=newfilereader();
fileReader.onload=函数(事件){
showPicture.src=event.target.result;
};
fileReader.readAsDataURL(文件);
}
捕获(e){
//显示错误消息
var error=document.querySelector(“错误”);
如果(错误){
error.innerHTML=“不支持createObjectURL或FileReader”;
}
}
}
}
};
}
})();
您需要读取exif数据,并检查exif.方向是否符合以下条件之一:
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;
}
};
Ben伟大的回答为我指明了正确的方向,但就我所知,实际的旋转是不正确的(至少对我来说是这样),并且没有涵盖所有可能的情况。下面的解决方案对我有效。它基于在中找到的一个(我通过找到)。请注意,我还必须将画布上下文转换为中心,因为旋转时它从左上角开始)
如果只需要方向标记,请使用: 在我的测试中,iOS摄像头仅返回1、3、6或8。添加到项目中,然后:
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);
});
定向块(使用平移和旋转)被复制,因此我认为它被证明是正确的。当然,它对我来说非常有效,而其他方法则不行。
基于您的回答,我创建了一个功能,可以将iphone照片自动旋转到正确的方向。只要传入一个input.files[0]和一个可选的最大宽度或高度,它就会输出一个用于表单提交的blob。
非常好用。非常感谢。fileReader的读取方法需要从readAsDataURL(文件)更改为readAsBinaryString(文件)。感谢您的回答,Ben!然而,我不太确定旋转是否正确。请参阅下面的我的答案。@gburning我同意您下面的答案更好,并且涵盖了大多数情况!请使用下面的答案,而不是我的答案。这个答案缺少的是到EXIF库的链接!我遇到一个错误,无法找到“BinaryFile”,这是从哪里来的?Ben Wong和gburning提出的解决方案适用于所有类型的图像,即。肖像、风景。。。我面临的主要问题是EXIF.Orientation=6的肖像图像。图像从顶部或底部被剪切。我在ctx.drawI中用多个值尝试了这些选项
EXIF.getData(file, function () {
alert(this.exifdata.Orientation);
});
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);
});