html5调用手机相机并压缩、上传 |
近日刚做的一个功能,要在app里使用内嵌页面进行图像的上传。 |
从功能上看,原生的实现应该是最好的。毕竟页面上所有的东西都隔着一个浏览器,所有的实现都要依赖浏览器提供的接口,不同的浏览器对接口的实现又有差异……到最后又会陷入兼容性的大坑! |
吐槽归吐槽,但是折腾的劲头不能丢! |
使用input file[camera]属性调用相机 |
简直So easy! |
<input type= "file" accept= "image/*;" capture= "camera" > |
只需要这么一条简单的代码,在手机浏览器点击就可以打开相机了。 |
capture是什么?其实就是对打开方式的设置。 |
<!-- capture=camcorder,调用手机摄像功能 --> |
<input type= "file" accept= "video/*" capture= "camcorder" > |
<!-- capture=microphone,调用手机录音功能 --> |
<input type= "file" accept= "audio/*" capture= "microphone" > |
魅族MX5测试结果: |
谷歌浏览器可以打开相机和摄像功能,其他方式均为相机、图库、文件管理器等混合选择项。 |
自带浏览器打开均为文件管理器。 |
由此说明此属性兼容性还是个问题。不过这并不能阻止我继续折腾下去! |
图片压缩 |
在如今这个手机普遍千万像素的时代,一张照片动辄5M的大小。作为一个良心的开发者,我们是要为用户的流量负责的。 |
该怎么做?我也不知道。大家都在用canvas实现,我也就用了。 |
document.getElementById( 'file' ).addEventListener( 'change' , function () { |
var reader = new FileReader(); |
reader.onload = function (e) { |
compress(this.result); |
}; |
reader.readAsDataURL(this.files[0]); |
}, false); |
不管文件域是用何种方式打开的,都可以在 change 事件中获取到选择的文件或拍摄的照片。 |
创建一个FileReader对象,我们需要调用readAsDataURL把文件转换为base64图像编码,如data:image/jpeg;base64……这种格式。 |
onload是一个异步回调,当文件读取完执行该方法内代码。this.result记录读取结果,如果读取失败,该值为null。在这里进行图片压缩的具体操作。 |
var compress = function (res) { |
var img = new Image(), |
maxH = 160; |
img.onload = function () { |
var cvs = document.createElement( 'canvas' ), |
ctx = cvs.getContext( '2d' ); |
if (img.height > maxH) { |
img.width *= maxH / img.height; |
img.height = maxH; |
} |
cvs.width = img.width; |
cvs.height = img.height; |
ctx.clearRect(0, 0, cvs.width, cvs.height); |
ctx.drawImage(img, 0, 0, img.width, img.height); |
var dataUrl = cvs.toDataURL( 'image/jpeg' , 0.6); |
// 上传略 |
} |
img.src = res; |
} |
创建一个Image对象,给src属性赋值为读取结果,同样在onload异步回调中编写处理图片的代码。 |
这里就要开始使用canvas进行图片压缩了。 |
首先是尺寸按比例缩放,然后把图片绘到画布上,最后调用toDataURL方法压缩图像质量。 |
context.toDataURL( 'MIME类型' , 图像质量0-1); // 该方法返回base64图像编码 |
代码里省略了一些校监操作,如文件类型约束和文件大小判断(小于一定值可以不压缩)。 |
最后就是把数据发送到后端的操作,这里就不说了。 |
Html5调用摄像头 |
通过以上的代码已经可以实现调用手机相机拍照、压缩、上传这一整套流程了。 |
不过在折腾的过程中也发现了一种调用摄像头的方法。注意,是摄像头!使用input调用的是相机。其中的差别就是摄像头是只捕获画面,相机还包括原生的一些拍照、设置等控件。 |
通过对摄像头的调用可以做很多有趣的事,比如拍照美化、滤镜等。可以说实现一个第三方相机是没问题的。 |
之前下载过一款安卓相机APP,不到100K的大小,可以实现拍照的一些风格化,也许就是Html5实现的呢。 |
需要用到的是 getUserMedia API,具体的实现这里就不贴了。 |
|
【用到的HTML5标签】 |
1 |
<input type= "file" capture= "camera" accept= "image/*" id= "cameraInput" name= "cameraInput" class = "sign_file" /> |
【等比缩放图片】 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
function drawOnCanvas(file) { |
var reader = new FileReader(); |
reader.onload = function (e) { |
var dataURL = e.target.result, |
canvas = document.querySelector( 'canvas' ), |
ctx = canvas.getContext( '2d' ), |
img = new Image(); |
img.onload = function () { |
var square = 320; |
canvas.width = square; |
canvas.height = square; |
var context = canvas.getContext( '2d' ); |
context.clearRect(0, 0, square, square); |
var imageWidth; |
var imageHeight; |
var offsetX = 0; |
var offsetY = 0; |
if (this.width > this.height) { |
imageWidth = Math. round (square * this.width / this.height); |
imageHeight = square; |
offsetX = -Math. round ((imageWidth - square) / 2); |
} else { |
imageHeight = Math. round (square * this.height / this.width); |
imageWidth = square; |
offsetY = -Math. round ((imageHeight - square) / 2); |
} |
context.drawImage(this, offsetX, offsetY, imageWidth, imageHeight); |
var base64 = canvas.toDataURL( 'image/jpeg' , 0.5); |
$( '#j_thumb' ).val(base64. substr (22)); |
}; |
img.src = dataURL; |
}; |
reader.readAsDataURL(file); |
} |
FileReader对象是用来解析file控件获取的本地图片地址的,具体介绍请百度一下。把解析好的地址设置给IMG标签的SRC属性,然后通过canvas对象把图片绘制; 在这过程中就有个等比缩放的算法,再用drawImage方法把图像画到canvas中。 |
【如何获取画好的图片数据传到后端处理】 |
通过 canvas.toDataURL(‘image/jpeg’,0.5)就可以获取到base64编码值,然后你就可以按照传统的POST或者AJAX方式处理了。 |
【让图片显示】 |
1 |
2 |
3 |
4 |
document.querySelector( 'input[type=file]' ).onchange = function () { |
var file = input.files[0]; |
drawOnCanvas(file); |
}; |
【后台处理方式】 |
1 |
2 |
3 |
$base64 = $_POST [ 'formFile' ]; |
$IMG = base64_decode ( $base64 ); |
file_put_contents ( '1.png' , $IMG ); |
根传统的上传图片不同,这时候后台需要用 base64_decode 解码 |
DEMO下载地址 http: //webcodegeeks.javacodegeeks.netdna-cdn.com/wp-content/uploads/2015/03/html5-webcam-example.zip |