H5移動端調(diào)用攝像頭拍照闷愤、壓縮上傳圖片

這周產(chǎn)品提出了新的需求整葡,要求前端H5頁面調(diào)起移動設(shè)備攝像頭,并實現(xiàn)拍照功能讥脐。完成之后來記錄一下開發(fā)經(jīng)歷遭居,希望對之后遇到同樣問題開發(fā)者有所幫助!

首先H5要調(diào)起設(shè)備攝像頭需要使用 input 標(biāo)簽攘烛,借助標(biāo)簽的 capture 屬性來完成調(diào)起操作。上代碼:

<label>照相機(jī)</label>
    <input type="file" id='image' accept="image/*" capture='camera'> 
<label>圖片多選</label>
    <input type="file" accept="image/*" multiple>
<label>調(diào)起前置攝像頭</label>
    <input type="file" accept="image/*" capture="user">

拍照完成之后镀首,需要讀取文件坟漱,這就需要使用 FileReader 對象來完成相應(yīng)操作。上代碼:

// 創(chuàng)建 FileReader 對象
var reader = new FileReader();
    reader.onload = function() {
        that.compress(this.result, file);
    };
reader.readAsDataURL(file);
this.fileUrl = window.URL.createObjectURL(file);

// this.result 既是讀取文件結(jié)果更哄,是一個Base64形式的文件流芋齿,類似data:image/png;base64,*****
// file 是獲去到的文件對象
file.png

that.compress 這個方法是用來處理圖片壓縮,是否旋轉(zhuǎn)等功能成翩。
this.fileUrl 是用來做 選定照片 / 拍攝照片 回顯觅捆,就是 img 的 src 屬性值。

到這里就可以實現(xiàn)簡單的H5調(diào)起相冊麻敌、攝像頭操作栅炒。但是測試的時候會發(fā)現(xiàn)像素好的手機(jī)拍出來的照片非常大,就造成了上傳接口相應(yīng)超時問題,此時不要慌赢赊,接下來就說一說關(guān)于照片壓縮問題乙漓。

這里的圖片壓縮就需要 canvas 來配合實現(xiàn)。

        let that = this;
        var width, height;
        var MAX_WH = 800;
        var image = new Image();

        image.onload = function() {
          if (image.height > MAX_WH) {
            // 寬度等比例縮放 *=
            image.width *= MAX_WH / image.height;
            image.height = MAX_WH;
          }
          if (image.width > MAX_WH) {
            // 寬度等比例縮放 *=
            image.height *= MAX_WH / image.width;
            image.width = MAX_WH;
          }
          //壓縮
          var quality = 80;
          var cvs = document.createElement("canvas");
          var context = cvs.getContext("2d");
          cvs.width = width = image.width;
          cvs.height = height = image.height;

          switch (orientation) {
            case 6:
            case 8:
              cvs.width = height;
              cvs.height = width;
              break;
          }
          context.clearRect(0, 0, cvs.width, cvs.height);
          context.drawImage(image, 0, 0, image.width, image.height);
          that.readerResult = cvs.toDataURL("image/jpeg", quality / 100);
          that.getBankcardFn(); // 調(diào)用上傳接口
        };
        image.src = res;

首先释移,創(chuàng)建Image對象叭披,給imagesrc屬性賦值加載完之后,調(diào)用onload玩讳。在onload中進(jìn)行圖片的壓縮操作涩蜘。
cvs.toDataURL() 方法返回的就是壓縮之后的圖片的 Base64 編碼,這時候就可以把編碼上傳至服務(wù)器了熏纯。

到了這里已經(jīng)就完成了一大半同诫,功能已經(jīng)基本實現(xiàn),現(xiàn)在就可以開始考慮優(yōu)化豆巨、提高用戶體驗了剩辟。經(jīng)過測試,會發(fā)現(xiàn)iOS部分機(jī)型會莫名造成圖片旋轉(zhuǎn)往扔,不要慌贩猎。

這里搭配EXIF對象來拿到圖片的原信息。

      var orientation = 0;
      EXIF.getData(file, function() {
          orientation = EXIF.getTag(file, "Orientation");
      });
        //解決ios圖片旋轉(zhuǎn)問題
        switch (orientation) {
          //iphone橫屏拍攝萍膛,此時home鍵在左側(cè)
          case 3:
            // 180度向左旋轉(zhuǎn)
            context.translate(width, height);
            context.rotate(Math.PI);
            break;
          //iphone豎屏拍攝吭服,此時home鍵在下方(正常拿手機(jī)的方向)
          case 6:
             context.rotate(0.5 * Math.PI);
            context.translate(0, -height);
            break;
          //iphone豎屏拍攝,此時home鍵在上方
          case 8:
            // 逆時針旋轉(zhuǎn)90度
            context.rotate(-0.5 * Math.PI);
             context.translate(-width, 0);
            break;
        }

這里的EXIF對象是(Exchangeable Image File)是“可交換圖像文件”的縮寫蝗罗,當(dāng)中包含了專門為數(shù)碼相機(jī)的照片而定制的元數(shù)據(jù)艇棕,可以記錄數(shù)碼照片的拍攝參數(shù)、縮略圖及其他屬性信息串塑,簡單來說沼琉,Exif信息是鑲嵌在 JPEG/TIFF 圖像文件格式內(nèi)的一組拍攝參數(shù),需要注意的是EXIF信息是不支持png,webp等圖片格式的桩匪。
可以引入CDN 也可以 npm install exif-js --save

到了這里功能就可以交付了打瘪。下面附上完整代碼粘貼即用:

<!-- 詳情操作頁面 -->
<template>
  <div class="wrapper Detial">
    <div class="title">
      {{ this.$route.query.group }}
    </div>
    <div class="content">
      <div v-if="!mutually" class="cont">
        <input @change="fileChoose" type="file" id="image" accept="image/*" />
        上傳銀行卡照片
        <img src="../assets/upload.png" alt="" />
      </div>
      <div v-if="mutually" class="conte">
        <img :src="fileUrl" alt="" />
      </div>
    </div>
    <div class="inputGroup">
      <label v-for="(item, index) in detialData" :key="index">
        <span class="text">{{ item.name }}</span>
        <span class="cardNumber">{{ item.value }}</span>
      </label>
    </div>
    <div class="button">
      <button @click="getBactFn" class="btn">返回首頁</button>
    </div>
    <div v-if="maskType" class="mask box">
      <div class="loader-15"></div>
      <span class="ideng">正在識別,請稍后傻昙!</span>
    </div>
  </div>
</template>

<script>
import EXIF from "exif-js";
export default {
  name: "Detial",
  data() {
    return {
      fileUrl: null,
      mutually: false,
      readerResult: "",
      detialData: [],
      maskType: false
    };
  },
  //生命周期 - 創(chuàng)建完成(訪問當(dāng)前this實例)
  created() {},
  //生命周期 - 掛載完成(訪問DOM元素)
  mounted() {},
  //存放自定義方法
  methods: {
    // 讀取圖片
    fileChoose(ifile) {
      this.maskType = true;
      this.mutually = true;
      let that = this;
      let file = ifile.target.files[0];
      console.log(file);
      var reader = new FileReader();
      reader.onload = function() {
        that.compress(this.result, file);
      };
      reader.readAsDataURL(file);
      this.fileUrl = window.URL.createObjectURL(file);
    },
    // 調(diào)用OCR銀行卡識別接口
    getBankcardFn() {
      const params = {
        image_data: this.readerResult,
        detect_direction: "true"
      };
      this.$api.OCRServerDetial.getBankcardPort(params).then(res => {
        if (res.code === 200) {
          this.maskType = false;
          this.detialData = [
            {
              name: "銀行卡號:",
              value: res.result.bank_card_number
            },
            {
              name: "有 效 期:",
              value: res.result.valid_date
            },
            {
              name: "銀行名稱:",
              value: res.result.bank_name
            },
            {
              name: "卡片類型:",
              value:
                res.result.bank_card_type == 0
                  ? "不能識別"
                  : res.result.bank_card_type == 1
                  ? "借記卡"
                  : "信用卡"
            }
          ];
        } else if (res.code === -1) {
          this.maskType = false;
          this.mutually = false;
          alert("請上傳銀行卡照片,或?qū)D片旋轉(zhuǎn)90°重試!");
        }
      });
    },
    // 壓縮圖片
    compress(res, file) {
      let that = this;
      var orientation = 0;
      if (file && /^image\//i.test(file.type)) {
        EXIF.getData(file, function() {
          orientation = EXIF.getTag(file, "Orientation");
        });
        var width, height;
        var MAX_WH = 800;
        var image = new Image();

        image.onload = function() {
          if (image.height > MAX_WH) {
            // 寬度等比例縮放 *=
            image.width *= MAX_WH / image.height;
            image.height = MAX_WH;
          }
          if (image.width > MAX_WH) {
            // 寬度等比例縮放 *=
            image.height *= MAX_WH / image.width;
            image.width = MAX_WH;
          }
          //壓縮
          var quality = 80;
          var cvs = document.createElement("canvas");
          var context = cvs.getContext("2d");
          cvs.width = width = image.width;
          cvs.height = height = image.height;

          switch (orientation) {
            case 6:
            case 8:
              cvs.width = height;
              cvs.height = width;
              break;
          }
          //解決ios圖片旋轉(zhuǎn)問題
          switch (orientation) {
            //iphone橫屏拍攝闺骚,此時home鍵在左側(cè)
            case 3:
              // 180度向左旋轉(zhuǎn)
              context.translate(width, height);
              context.rotate(Math.PI);
              break;
            //iphone豎屏拍攝,此時home鍵在下方(正常拿手機(jī)的方向)
            case 6:
              context.rotate(0.5 * Math.PI);
              context.translate(0, -height);
              break;
            //iphone豎屏拍攝妆档,此時home鍵在上方
            case 8:
              // 逆時針旋轉(zhuǎn)90度
              context.rotate(-0.5 * Math.PI);
              context.translate(-width, 0);
              break;
          }
          context.clearRect(0, 0, cvs.width, cvs.height);
          context.drawImage(image, 0, 0, image.width, image.height);
          that.readerResult = cvs.toDataURL("image/jpeg", quality / 100);
          that.getBankcardFn(); // 調(diào)用上傳接口
        };
        image.src = res;
      }
    },
    // 點(diǎn)擊返回首頁
    getBactFn() {
      this.$router.push({ path: "/ocrList" });
    }
  },
  //生命周期 - 頁面銷毀前
  beforeDestroy() {}
};
</script>

<style lang="scss" scoped>
/* @import url(); 引入css類 */
.mask {
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.6);
  position: absolute;
  top: 0;
  left: 0;
}
.box {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 30px;
  color: rgba(200, 200, 200, 1);
  padding: 0 1em;
  -webkit-transition: 0.3s color, 0.3s border;
  transition: 0.3s color, 0.3s border;
  box-sizing: border-box;
}
[class*="loader-"] {
  display: inline-block;
  width: 1em;
  height: 1em;
  color: inherit;
  vertical-align: middle;
  pointer-events: none;
}
.ideng {
  font-size: 0.3rem;
  margin-top: 0.5rem;
}
.loader-15 {
  background: currentcolor;
  position: relative;
  -webkit-animation: loader-15 1s ease-in-out infinite;
  animation: loader-15 1s ease-in-out infinite;
  -webkit-animation-delay: 0.4s;
  animation-delay: 0.4s;
  width: 0.25em;
  height: 0.5em;
}
.loader-15:after,
.loader-15:before {
  content: "";
  position: absolute;
  width: inherit;
  height: inherit;
  background: inherit;
  -webkit-animation: inherit;
  animation: inherit;
}
.loader-15:before {
  right: 0.5em;
  -webkit-animation-delay: 0.2s;
  animation-delay: 0.2s;
}
.loader-15:after {
  left: 0.5em;
  -webkit-animation-delay: 0.6s;
  animation-delay: 0.6s;
}
@-webkit-keyframes loader-15 {
  0%,
  100% {
    box-shadow: 0 0 0 currentcolor, 0 0 0 currentcolor;
  }
  50% {
    box-shadow: 0 -0.25em 0 currentcolor, 0 0.25em 0 currentcolor;
  }
}
@keyframes loader-15 {
  0%,
  100% {
    box-shadow: 0 0 0 currentcolor, 0 0 0 currentcolor;
  }
  50% {
    box-shadow: 0 -0.25em 0 currentcolor, 0 0.25em 0 currentcolor;
  }
}
.button {
  margin-top: 0.5rem;
  text-align: center;
  .btn {
    color: #39a1ec;
    background: none;
    border: 1px solid #ccc;
  }
}
.title {
  font-size: 0.4rem;
  color: #333333;
  padding: 0.2rem;
}
.content {
  width: 100%;
  height: 4.5rem;
  position: relative;
  box-sizing: border-box;
  padding: 0 0.2rem 0.6rem;
  border-bottom: 0.3rem solid #f5f5f5;
  .conte {
    width: 100%;
    height: 100%;
    border-radius: 8px;
    overflow: hidden;
    img {
      width: 100%;
      height: 100%;
      display: block;
    }
  }
  .cont {
    width: 100%;
    height: 100%;
    color: #333;
    text-align: center;
    line-height: 3.6rem;
    font-size: 0.4rem;
    background: url("../assets/5.png") no-repeat;
    background-size: 100% 100%;
    img {
      width: 0.7rem;
      height: 0.5rem;
    }
    input {
      width: 100%;
      height: 100%;
      outline: none;
      opacity: 0;
      position: absolute;
      top: 0;
      left: 0;
    }
  }
}
.inputGroup {
  padding: 0 0.2rem;
  label {
    display: flex;
    padding: 0.24rem 0;
    align-items: center;
    justify-content: center;
    border-bottom: 1px solid #eeeeee;
    span {
      font-size: 0.3rem;
      color: #333333;
      font-family: STHeitiSC-Medium;
    }
    .text {
      width: 1.6rem;
      color: #999999;
      margin-right: 0.1rem;
    }
    .cardNumber {
      flex: 1;
      padding-left: 0.3rem;
    }
  }
}
</style>

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末僻爽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子贾惦,更是在濱河造成了極大的恐慌胸梆,老刑警劉巖敦捧,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乳绕,居然都是意外死亡绞惦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門洋措,熙熙樓的掌柜王于貴愁眉苦臉地迎上來济蝉,“玉大人,你說我怎么就攤上這事菠发⊥趼耍” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵滓鸠,是天一觀的道長雁乡。 經(jīng)常有香客問我,道長糜俗,這世上最難降的妖魔是什么踱稍? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮悠抹,結(jié)果婚禮上珠月,老公的妹妹穿的比我還像新娘。我一直安慰自己楔敌,他們只是感情好啤挎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著卵凑,像睡著了一般庆聘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勺卢,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天伙判,我揣著相機(jī)與錄音,去河邊找鬼黑忱。 笑死宴抚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的杨何。 我是一名探鬼主播酱塔,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼沥邻,長吁一口氣:“原來是場噩夢啊……” “哼危虱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唐全,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤埃跷,失蹤者是張志新(化名)和其女友劉穎蕊玷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弥雹,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垃帅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了剪勿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贸诚。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖厕吉,靈堂內(nèi)的尸體忽然破棺而出酱固,到底是詐尸還是另有隱情,我是刑警寧澤头朱,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布运悲,位于F島的核電站,受9級特大地震影響项钮,放射性物質(zhì)發(fā)生泄漏班眯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一烁巫、第九天 我趴在偏房一處隱蔽的房頂上張望署隘。 院中可真熱鬧,春花似錦程拭、人聲如沸定踱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽崖媚。三九已至,卻和暖如春恤浪,著一層夾襖步出監(jiān)牢的瞬間畅哑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工水由, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荠呐,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓砂客,卻偏偏與公主長得像泥张,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鞠值,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容