HTML5 實現手機拍照上傳

 

  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(type, encoderOptions); 將圖片按照一定的壓縮比進行壓縮,得到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給服務器,後臺處理相應的轉化!

 

發佈了19 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章