手机html5页面进行拍照和照片处理
背景
利用html5的API,在手机上也能够调起摄像头进行拍照、并对照片进行编辑。APP能做的h5也能做到,而且也不复杂。本文就介绍一下如何实现。
调起系统相机
使用type值为file,并设置accept属性的input标签,用户点击该元素即可唤起系统的摄像头/图库的菜单。如下:
<input id="camera" type="file" accept="image/*">
需要注意的是,在安卓的WebView中,改功能默认是关闭的,需要在程序中打开该功能。
拍完照片后,可以将照片当作文件进行表单提交,但手机拍的照片文件大小一般比较大,要占用不少的宝贵的移动流量,同时也需要用户长时间的等待,所以我们对照片进行一定的压缩再提交。首先,我们需要读取拍到的照片。
读取拍到的图片
html5提供了FileReader对象来读取本地文件,使用readAsDataURL读取文件的base64编码数据
$('#camera').change(function(evt) { if (evt.target.files.length>0) { var file = evt.target.files[0]; var reader = new FileReader(); reader.onload = function(e) { var image = new Image(); image.onload = function() { processImage(image); }; image.src = e.target.result; }; reader.readAsDataURL(file); } });
处理照片
使用canvas进行图片处理,我们将图片按比例缩小绘制在canvas上。例如我们将图片的尺寸缩小到0.1
var canvas = document.getElementById('canvas'); var ratio = 0.1; function processImage(image) { var ctx = canvas.getContext(‘2d’); canvas.width = image.width*ratio; canvas.height = image.height*ratio; ctx.clearRect(0,0,canvas.width,canvas.height); ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height); }
导出处理后的照片
使用canvas的toDataURL方法导出处理后的图片的base64编码数据。可以在方法的参数中设定图片格式,默认值为image/png。
canvas.toDataURL('image/jpeg')
由于base64格式的数据带有 data:image/jpeg;base64, 这类的头,后端解析的时候需要把这个头去掉,这可以在前端做,也可以在后端做。
不得不提的坑
整个图片的处理流程并不是很复杂,但当我们实际操作的时候,却发现事实远没有那么简单。我们遇到两个大坑:
1. iphone拍的照片绘制出来会被压扁
2. 照片的旋转方向不正确
好在这两个问题有不少开发者也遇到过,我们在网上找到答案:
- 照片被压扁的问题可以参考http://stackoverflow.com/questions/11929099/html5-canvas-drawimage-ratio-bug-ios ,利用答案中的detectVerticalSquash函数来对缩放比例进行修正。(这个函数出自https://github.com/stomita/ios-imagefile-megapixel,感谢stomita的工作)
ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio, sw * vertSquashRatio, sh * vertSquashRatio, dx, dy, dw, dh );
2. 利用Exif.js(https://github.com/jseidelin/exif-js)读取照片的旋转方向,并对Canvas进行旋转
$('#camera').change(function(evt) { if (evt.target.files.length>0) { var file = evt.target.files[0]; var rotation = 0; EXIF.getData(file, function() { var orientation = EXIF.getTag(this,'Orientation'); switch (orientation) { //根据exif中照片的旋转信息对图片进行旋转 case 3: rotation=180; break; case 6: rotation=90; break; case 8: rotation=-90; break; default : rotation=0; } var reader = new FileReader(); reader.onload = function(e) { var image = new Image(); image.onload = function() { processImage(image, rotation); }; image.src = e.target.result; }; reader.readAsDataURL(file); }); } }); //修改processImage函数 var canvas = document.getElementById('canvas'); var ratio = 0.1; function processImage(image,rotation) { var ctx = canvas.getContext('2d'); var imageWidthOrigin = image.width; var imageHeightOrigin = image.height; var imageWidth = imageWidthOrigin*ratio; var imageHeight = imageHeightOrigin*ratio; canvas.width = imageWidth ; canvas.height = imageHeight ; var startX = 0; var startY = 0; if (rotation==90) { canvas.width = imageHeight ; canvas.height = imageWidth ; startX = 0; startY = -imageHeight; } else if (rotation==-90) { canvas.width = imageHeight ; canvas.height = imageWidth ; startX = -imageWidth; startY = 0; } else if (rotation==180 || rotation==-180) { startX = -imageWidth; startY = -imageHeight; } ctx.clearRect(0,0,canvas.width,canvas.height); ctx.rotate(rotation*Math.PI/180); var vertSquashRatio = detectVerticalSquash(image); ctx.drawImage(image, 0, 0, imageWidthOrigin*vertSquashRatio, imageHeightOrigin*vertSquashRatio, startX, startY, imageWidth, imageHeight); }