近日刚做的一个功能,要在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,具体的实现这里就不贴了。