文档章节

HTML5 实现手机拍照上传

Reya滴水心
 Reya滴水心
发布于 2016/06/24 14:18
字数 1517
阅读 18727
收藏 295

背景:移动端H5项目,需要实现调用手机拍照,并将图片压缩上传功能。

  1. 页面样式:
    1. 上传图片有原生的方法<input type="file" accept="image/*">,如果只想要拍照上传,不希望用户选择图片上传,可以通过添加capture属性,该属性值有camcorder/microphone/camera...,此处选择camera。PS:该属性存在浏览器兼容性问题,不是所有的浏览器都支持。
      <input type="file" accept="image/*" capture="camera" >
    2. 因为原生file样式不满足要求,需要进行相应的处理,此时使用定位,在input上面放置我们想要的页面效果。然后当点击上面的元素,就可以触发我们的input进行图片上传。此时的问题是:当点击input上面的元素,需要事件穿透,即相当于点击input。则借助于css3新属性pointer-events。
      //使用cursor进行事件穿透,来阻止元素成为鼠标事件的目标
      button{
           cursor:pointer;
           pointer-events:none;
      }
      

      ----此时图片上传的样式已经处理好了----

      代码片段:
      <style >
          *{
              padding: 0;
              margin: 0;
          }
          .wrapper{
              width: 320px;
              height: 50px;
              margin: 20px auto;
              position: relative;
              border: 1px solid #f0f0f0;
          }
          input{
              width: 100px;
              height: 30px;
          }
          button{
              position: absolute;
              cursor: pointer;
              pointer-events: none;
              width: 100px;
              height: 30px;
              left: 0;
              top: 0;
          }
          a{
              pointer-events: none;
          }
          .img{
              border: 1px solid #ccc;
              padding: 10px;
          }
      </style >
      
      <div class = "wrapper">
           <input type = "file" accept= "image/*" capture= "camera" id= "img" />
           <button >上传照片 </button >
      </div >
      
  2. 图片压缩处理:
    1. 因为要做的是手机拍照上传,现在的手机拍照片都很大,比如小米4S,大小在3M以上,如果原图上传,太消耗用户流量,于是要解决图片压缩的问题。
    2.   通过change事件,监听图片上传,通过readerAsDataURL获取上传的图片。

      document.getElementById( 'img').addEventListener( 'change', function () {
           var reader = new FileReader();
           reader.onload = function (e) {
                //调用图片压缩方法:compress();
           };
           reader.readAsDataURL(this.files[0]);
           console.log(this.files[0]);
           var fileSize = Math.round( this.files[0].size/1024/1024) ; //以M为单位
           //this.files[0] 该信息包含:图片的大小,以byte计算 获取size的方法如下:this.files[0].size;
      }, false);
      
    3.   对上传的图片进行压缩,需要借助于canvas API,调用其中的canvas.toDataURL(typeencoderOptions); 将图片按照一定的压缩比进行压缩,得到base64编码。重点来了:压缩策略:先设置图片的最大宽度 or 最大高度,一般设置其中一个就可以了,因为所有的手机宽高比差别不是很大。然后设置图片的最大size,allowMaxSize,根据图片的实际大小和最大允许大小,设置相应的压缩比率。

      //最终实现思路:
      1、设置压缩后的最大宽度 or 高度;
      2、设置压缩比例,根据图片的不同size大小,设置不同的压缩比。
      
      function compress(res,fileSize) { //res代表上传的图片,fileSize大小图片的大小
          var img = new Image(),
              maxW = 640; //设置最大宽度
      
          img.onload = function () {
              var cvs = document.createElement( 'canvas'),
                  ctx = cvs.getContext( '2d');
      
              if(img.width > maxW) {
                  img.height *= maxW / img.width;
                  img.width = maxW;
              }
      
              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 compressRate = getCompressRate(1,fileSize);
      
              var dataUrl = cvs.toDataURL( 'image/jpeg', compressRate);
      
              document.body.appendChild(cvs);
              console.log(dataUrl);
          }
      
          img.src = res;
      }
      
      function getCompressRate(allowMaxSize,fileSize){ //计算压缩比率,size单位为MB
            var compressRate = 1;
      
            if(fileSize/allowMaxSize > 4){
                 compressRate = 0.5;
            } else if(fileSize/allowMaxSize >3){
                 compressRate = 0.6;
            } else if(fileSize/allowMaxSize >2){
                 compressRate = 0.7;
            } else if(fileSize > allowMaxSize){
                 compressRate = 0.8;
            } else{
                 compressRate = 0.9;
            }
      
            return compressRate;
      }
      
  3. 图片上传给服务器:
    1. 图片已经压缩完成了,但是压缩后的图片不是File,而是一个base64编码,于是乎两个选择:1、以String的形式将base64编码上传给服务器,服务器转存base64为img图片;2、前端将base64转为File图片类型,上传给服务器。
    2. 方法一:压缩之后直接上传base64给后台,实现简单。
    3. 方法二:前端自己转存base64位File图片,这个对于前端 压力比较大。

      原因:html5 canvas属于客户端API,没有权限去保存图片到硬盘,只有canvas.toDataURL()这一接口可导出画布的base64编码,以提供给服务器进行处理保存。所以如果要将base64编码转成图片需要借助于nodeJs。因为nodeJS有相关文件处理的API。

      //使用nodeJS将base64转化成图片
      var express = require('express');
      var fs = require("fs");
      var app = module.exports = express();
      
      function dataToImage(dataUrl){
          var base64Data = dataUrl.replace(/^data:image\/\w+;base64,/,'');
          var dataBuffer = new Buffer(base64Data,'base64');
      
          fs.writeFile('out.jpg',dataBuffer,function(err){
              if(err){
                  console.log(err);
              }else{
                  console.log('Success...');
              }
          });
      }
      
      dataToImage('data:image/jpeg;base64,/9...'); //图片完整base64过长,所以省略...
      
      if(!module.parent){
          app.listen(8000);
          console.log('Express started on port 8000');
      }
      

      Summary:如果使用nodeJS,需要单独部署nodeJS代码到服务器,整个逻辑会比较麻烦。综合比较两种方法,推荐使用第一种方法,直接传base64给服务器,后台处理相应的转化!

demo: http://www.zhangyixia.com/image-upload/  

可直接扫描二维码:
                               

相关知识科普:

  1. 图像一般由两部分组成:一部分是数据本身,他记录了每个像素的颜色值,另一部分是文件头,这里记录着形如图像的宽度,高度等信息。
  2. 不同图片类型及适用场景:
    1. 不同图片类型:
      1. GIF:无损压缩,体积小,支持透明效果,缺点:色彩效果最低,用gif保存鲜艳的图片的话会让网站看上去非常可怕。
      2. PNG:无损压缩,可渐变透明,缺点:不如JPG颜色丰富,同样的图片体积也比JPG略大。
      3. JPG/JPEG:色彩还原性好,可以在照片不明显失真的情况下,大幅度压缩图片格式,所以体积不会很大。缺点:不支持透明
    2. 适用场景:
      1. 当图片色彩鲜艳,基本没有透明效果的时候,选择jpg/jpeg。
      2. 当图片色彩鲜艳,透明效果较多的情况下,选择png;
      3. 当图片色彩比较单一情况下,可以选择gif;
  3. toDataURL,查找原生压缩图片的方法。type支持image/webp格式
    canvas.toDataURL(type, encoderOptions);
  4. Base64编码:将三个8Bit的字节转换为四个6Bit的字节。

 

参考资料:

http://www.imys.net/20150916/webapp-input-use-camera.html

http://www.oxxostudio.tw/articles/201409/pointer-events.html

https://segmentfault.com/a/1190000005364299

© 著作权归作者所有

共有 人打赏支持
Reya滴水心
粉丝 38
博文 88
码字总数 31966
作品 0
深圳
前端工程师
加载中

评论(22)

s
szygb
HTML5 实现手机拍照上传完整代码能发我邮箱吗?228619800@qq.com
八粥php
八粥php
能录像吗??
hhcat
hhcat
这个方案可以滴!我就是用此办法,图片可以无限张数,每张图片处理好大小,1200px的照片也就是180-200K,可以接受。
Reya滴水心
Reya滴水心

引用来自“JohnnieFucker”的评论

微信上ios可以,安卓只能选图片不能呼出照相机。
主要看你使用的是什么手机,我这边使用的小米4S,微信最新版本,可以正常操作。需要注意的是:微信Android调起来的应该既有相机,又有图库...,需要专门点击相机。也就是需要两步操作!
J
JohnnieFucker
微信上ios可以,安卓只能选图片不能呼出照相机。
x7LoveLin
x7LoveLin
不错。 可以提供参考
Reya滴水心
Reya滴水心

引用来自“采女孩的小蘑菇”的评论

微信游览器不行

我这边Android,IOS微信测试都OK,具体可以提供一下你使用机器型号以及微信版本号
一位极其不愿意透漏姓名的马先生
一位极其不愿意透漏姓名的马先生
微信游览器不行
南漂一卒
南漂一卒

引用来自“Riya滴水心”的评论

引用来自“_Elvis”的评论

客户端图片压缩有个烦人的问题,就是iPhone拍的图片的方向是存在exif里的,不知道博主是否考虑过?

引用来自“Riya滴水心”的评论

这个问题我也遇见了,竖向图片会逆时针旋转90°横向显示,但是对产品影响不大,所以暂时未进行处理!有时间可以探讨一下

引用来自“_Elvis”的评论

http://www.jqueryscript.net/demo/jQuery-Plugin-for-Client-Side-Image-Resizing-canvasResize/
可以用这个库
63有时间去试试,谢啦~

http://code.ciaoca.com/javascript/exif-js/
Reya滴水心
Reya滴水心

引用来自“房一飞”的评论

自动对焦怎么实现
自动聚焦,这个前端目前不能实现。可是我觉得基本上也不需要自动聚焦呀,你在怎样的业务场景下要用到?
HTML5定稿一周年,你必须要重新认识HTML5了

作者简介:王安,DCloud CEO,HTML5产业专家,W3C会员。 去年此时,W3C定稿了HTML5。我曾发表一篇文章《HTML 5终于定稿,为什么原生App世界将被颠覆》,这文章转载量很大,它阐述了HTML5的来...

SomaLihq
06/27
0
0
HTML5 Video/Canvas拍照初级

通过HTML5 Video和Canvas实现拍照的功能,功能很简单;另外,因为用到了getUserMedia()函数,目前只能在Chrome和Opera里使用,详见:Can I use getUserMedia/Stream API? 演示地址:HTML5 W...

Xiaopeng
2012/10/30
0
1
HTML5视频教程之canvas合成海报所遇问题及解决方案

本篇文章扣丁学堂HTML5培训小编大家分享HTML5开发方面的问题:canvas合成海报所遇问题及解决方案,HTML5不论是现在还是今后的发展相信很多人都是很看好的,下面和小编一起来了解一下HTML5开发...

扣丁学堂
08/29
0
0
初识html5 File API实现带有进度提示的文件上传

Html5终于解决了上传文件的同时显示文件上传进度的老问题。现在大部分的网站用Flash去实现这一功能,还有一些网站继续采用Html <form>with enctype=multipart/form-data,但是需要修改服务器...

miscellanea
2014/06/27
0
3
HTML5从入门到精通,零基础学员必看

学习html5从入门到精通,零基础新手也能看懂,无论你是唱歌,画画的艺术生,还是学习机械专业的工科生,或者大学读的文学学科。先了解HTML5可以实现的功能有哪儿些? 1. HTML5可以同时在多种...

课工场CC老师
2017/11/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 识别慢性能的宏

Page Profiling 给你了有关页面在载入的时候操作缓慢的邪教,你可以将下面的内容添加到调试(debug)级别: Version 3.1 及其后续版本 设置包名字为 com.atlassian.renderer.v2.components.M...

honeymose
13分钟前
0
0
day93-20180920-英语流利阅读-待学习

时尚之觞:外表光鲜靓丽,其实穷得要命 Lala 2018-09-20 1.今日导读 讲到时尚界,我们脑海里浮现的可能都是模特和设计师光鲜靓丽、从容潇洒的模样。可是,最近在法国出版的一本书却颠覆了我们...

飞鱼说编程
28分钟前
0
0
maven的pom.xml用解决版本问题

maven管理库依赖,有个好处就是连同库的依赖的全部jar文件一起下载,免去手工添加的麻烦,但同时也带来了同一个jar会被下载了不同版本的问题,好在pom的配置里面允许用<exclusion>来排除一些...

JAVA码猿
52分钟前
1
0
20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
42
11

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部