faceSea.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <template>
  2. <!-- 人脸识别页面 -->
  3. <view class="content">
  4. <!-- 拍照区域 -->
  5. <view class="cameraField">
  6. <!-- 上传的人脸图片 -->
  7. <canvas
  8. canvas-id="canvas"
  9. id="canvas"
  10. type="2d"
  11. style="width: 100%; height: 100%"
  12. ></canvas>
  13. <!-- 提示框 -->
  14. <view class="hint" v-if="isShow3">
  15. <image :src="hintImage" />
  16. {{ hintWord }}
  17. </view>
  18. <!-- 头像限制框 -->
  19. <image
  20. class="head"
  21. src="../../static/images/head1.png"
  22. mode="scaleToFill"
  23. />
  24. </view>
  25. <!-- 控件区域 -->
  26. <view class="controlField">
  27. <!-- 拍照控件 -->
  28. <view class="control1" v-if="isShow1">
  29. <view class="light">
  30. <!-- <image class="light" src="../../static/images/light.png" /> -->
  31. </view>
  32. <view @click="takePhoto()">
  33. <image class="take" src="../../static/images/take.png" />
  34. </view>
  35. <view class="change">
  36. <!-- <image class="change" src="../../static/images/change.png" /> -->
  37. </view>
  38. </view>
  39. <!-- 重拍/上传控件 -->
  40. <view class="control2" v-if="isShow2">
  41. <view @click="resetPhoto">重拍</view>
  42. <view @click="upload">使用照片</view>
  43. </view>
  44. </view>
  45. </view>
  46. </template>
  47. <script>
  48. import { EXIF } from "../../node_modules/exif-js/exif"; //引入exif.js判断图片旋转方向
  49. import { mapState, mapMutations } from "vuex"; //引入vuex
  50. import {
  51. pathToBase64,
  52. base64ToPath,
  53. } from "../../js_sdk/mmmm-image-tools/index.js";
  54. export default {
  55. data() {
  56. return {
  57. isShow1: true, //拍照控件
  58. isShow2: false, //重拍/上传控件
  59. isShow3: true, //提示框
  60. // isShow4: false, //“上传中”提示框
  61. hintImage: "../../static/images/hint@2x.png", //提示图标
  62. hintWord: "请勿遮挡面部", //提示文字
  63. imgPath: "", //上传的人脸图片本地路径
  64. tipFlag: "", //手机机型
  65. maxWidth: "", //手机屏幕宽度
  66. maxHeight: "", //手机屏幕高度
  67. };
  68. },
  69. computed: mapState(["position", "userData"]), //vuex.state
  70. onLoad(options) {
  71. //判断设备机型
  72. let that = this;
  73. (function () {
  74. var u = navigator.userAgent;
  75. var isAndroid = u.indexOf("Android") > -1 || u.indexOf("Linux") > -1; //android终端或者uc浏览器
  76. var isiOS = u.indexOf("iPhone") > -1; //苹果手机
  77. if (isiOS) {
  78. that.tipFlag = "ios";
  79. }
  80. if (isAndroid) {
  81. that.tipFlag = "Android";
  82. }
  83. })();
  84. },
  85. methods: {
  86. ...mapMutations(["getPosition", "getUserData"]), //vuex.mutations
  87. //拍照控件变重拍上传控件
  88. takeToReset() {
  89. this.isShow1 = !this.isShow1;
  90. this.isShow2 = !this.isShow2;
  91. },
  92. //拍照
  93. takePhoto() {
  94. this.photo();
  95. },
  96. //重拍
  97. resetPhoto() {
  98. this.isShow1 = !this.isShow1;
  99. this.isShow2 = !this.isShow2;
  100. this.photo();
  101. },
  102. //照片
  103. photo() {
  104. let that = this;
  105. uni.chooseImage({
  106. count: 1,
  107. sourceType: ["camera"],
  108. sizeType: ["compressed"],
  109. success: (res) => {
  110. //压缩所选图片
  111. // let path = res.tempFilePaths[0]; //压缩图路径
  112. // let targetWidth = 150;
  113. // let targetHeight = 200;
  114. // let ctx = uni.createCanvasContext("canvas");
  115. // ctx.drawImage(path, 0, 0, 300, 400); //x设置成1000是因为不让压缩图出现在屏幕
  116. // ctx.draw(false, () => {
  117. // // canvas导出为图片路径
  118. // uni.canvasToTempFilePath({
  119. // canvasId: "canvas",
  120. // fileType: "jpg", //支持jpg或png
  121. // quality: 0.92, //图片质量
  122. // success(res3) {
  123. // let path1 = res3.tempFilePath;
  124. // that.toBase64(path1); //转base64图片
  125. // },
  126. // });
  127. // }),
  128. //绘制图片到页面
  129. //获取设备屏幕尺寸
  130. that.imgPath = res.tempFilePaths[0]; //这就是要的blod
  131. uni.getSystemInfo({
  132. success: function (res2) {
  133. that.maxWidth = res2.windowWidth;
  134. let base = 4 / 3;
  135. that.maxHeight = that.maxWidth * base;
  136. //判断设备机型
  137. if (that.tipFlag == "ios") {
  138. let canvas = uni.createCanvasContext("canvas");
  139. // canvas.drawImage(that.imgPath, 0, 0, 150, 200); //x设置成1000是因为不让压缩图出现在屏幕
  140. // canvas.draw(false, () => {
  141. // canvas导出为图片路径
  142. // uni.canvasToTempFilePath({
  143. // width: that.maxWidth,
  144. // height: that.maxHeight,
  145. // destWidth: that.maxWidth,
  146. // destHeight: that.maxHeight,
  147. // canvasId: "canvas",
  148. // fileType: "jpg", //支持jpg或png
  149. // quality: 1, //图片质量
  150. // success(res3) {
  151. // let path1 = res3.tempFilePath;
  152. // console.log(path1);
  153. // this.$store.state.imageBase = path1;
  154. // // that.toBase64(path1); //转base64图片
  155. // },
  156. // });
  157. // });
  158. canvas.drawImage(
  159. that.imgPath,
  160. 0,
  161. 0,
  162. that.maxWidth,
  163. that.maxHeight
  164. ); //苹果机图片显示
  165. canvas.draw();
  166. uni.canvasToTempFilePath({
  167. width: that.maxWidth,
  168. height: that.maxHeight,
  169. destWidth: that.maxWidth,
  170. destHeight: that.maxHeight,
  171. canvasId: "canvas",
  172. fileType: "jpg", //支持jpg或png
  173. quality: 1, //图片质量
  174. success(res3) {
  175. let path1 = res3.tempFilePath;
  176. console.log(path1);
  177. that.$store.state.imageBase = path1;
  178. // that.toBase64(path1); //转base64图片
  179. },
  180. });
  181. that.takeToReset(); //图片显示后显示重拍控件
  182. } else {
  183. // let ctx = uni.createCanvasContext("canvas");
  184. // ctx.drawImage(that.imgPath, 0, 0, 150, 200); //x设置成1000是因为不让压缩图出现在屏幕
  185. // ctx.draw(false, () => {
  186. // // canvas导出为图片路径
  187. // uni.canvasToTempFilePath({
  188. // canvasId: "canvas",
  189. // fileType: "jpg", //支持jpg或png
  190. // quality: 0.92, //图片质量
  191. // success(res3) {
  192. // let path1 = res3.tempFilePath;
  193. // that.toBase64(path1); //转base64图片
  194. // },
  195. // });
  196. // }),
  197. that.detail(that.imgPath); //安卓机图片绘制
  198. }
  199. },
  200. });
  201. },
  202. });
  203. },
  204. //安卓机图片修正
  205. async detail(url) {
  206. let Orientation = 1;
  207. //获取图片META信息
  208. await this.getImageTag(url, "Orientation", function (e) {
  209. if (e != undefined) Orientation = e;
  210. });
  211. var img = null;
  212. var canvas = null;
  213. await this.comprossImage(url, function (e) {
  214. img = e.img;
  215. canvas = e.canvas;
  216. });
  217. // console.log(Orientation,"Orientation")
  218. //如果方向角不为1,都需要进行旋转
  219. switch (Orientation) {
  220. case 6: //需要顺时针(向右)90度旋转
  221. this.rotateImg(img, "right", canvas);
  222. break;
  223. case 8: //需要逆时针(向左)90度旋转
  224. this.rotateImg(img, "left", canvas);
  225. break;
  226. case 3: //需要180度旋转 转两次
  227. this.rotateImg(img, "right", canvas, 2);
  228. break;
  229. default:
  230. this.rotateImg(img, "", canvas);
  231. break;
  232. }
  233. },
  234. async comprossImage(imgSrc, func) {
  235. if (!imgSrc) return 0;
  236. return new Promise((resolve, reject) => {
  237. uni.getImageInfo({
  238. src: imgSrc,
  239. success(res) {
  240. let img = new Image();
  241. img.src = res.path;
  242. // console.log(img);
  243. let canvas = uni.createCanvasContext("canvas");
  244. let obj = new Object();
  245. obj.img = img;
  246. obj.canvas = canvas;
  247. resolve(func(obj));
  248. },
  249. });
  250. });
  251. },
  252. getImageTag(file, tag, suc) {
  253. if (!file) return 0;
  254. return new Promise((resolve, reject) => {
  255. /* eslint-disable func-names */
  256. // 箭头函数会修改this,所以这里不能用箭头函数
  257. let imgObj = new Image();
  258. imgObj.src = file;
  259. // console.log(imgObj);
  260. uni.getImageInfo({
  261. src: file,
  262. success(res) {
  263. EXIF.getData(imgObj, function () {
  264. EXIF.getAllTags(this);
  265. let or = EXIF.getTag(this, "Orientation"); //这个Orientation 就是我们判断需不需要旋转的值了,有1、3、6、8
  266. resolve(suc(or));
  267. });
  268. },
  269. });
  270. });
  271. },
  272. rotateImg(img, direction, canvas, times = 1) {
  273. // console.log("开始旋转");
  274. //最小与最大旋转方向,图片旋转4次后回到原方向
  275. var min_step = 0;
  276. var max_step = 3;
  277. if (img == null) return;
  278. //img的高度和宽度不能在img元素隐藏后获取,否则会出错
  279. var height = img.height;
  280. var width = img.width;
  281. let maxWidth = this.maxWidth;
  282. let maxHeight = this.maxHeight;
  283. var step = 0;
  284. if (step == null) {
  285. step = min_step;
  286. }
  287. if (direction == "right") {
  288. step += times;
  289. //旋转到原位置,即超过最大值
  290. step > max_step && (step = min_step);
  291. } else if (direction == "left") {
  292. step -= times;
  293. step < min_step && (step = max_step);
  294. } else {
  295. //不旋转
  296. step = 0;
  297. }
  298. //旋转角度以弧度值为参数
  299. var degree = (step * 90 * Math.PI) / 180;
  300. var ctx = uni.createCanvasContext("canvas");
  301. // console.log(degree);
  302. // console.log(step);
  303. switch (step) {
  304. case 1:
  305. // console.log("右旋转 90度");
  306. width = maxHeight;
  307. height = maxWidth;
  308. ctx.rotate(degree);
  309. ctx.drawImage(img.src, 0, -height, width, height);
  310. ctx.draw();
  311. uni.canvasToTempFilePath({
  312. width: maxHeight,
  313. height: maxWidth,
  314. destWidth: maxHeight,
  315. destHeight: maxWidth,
  316. canvasId: "canvas",
  317. fileType: "jpg", //支持jpg或png
  318. quality: 1, //图片质量
  319. success(res3) {
  320. let path1 = res3.tempFilePath;
  321. console.log(path1);
  322. this.$store.state.imageBase = path1;
  323. // that.toBase64(path1); //转base64图片
  324. },
  325. });
  326. this.takeToReset();
  327. break;
  328. case 2:
  329. //console.log('旋转 180度')
  330. width = maxWidth;
  331. height = maxHeight;
  332. ctx.rotate(degree);
  333. ctx.drawImage(img.src, -width, -height, width, height);
  334. ctx.draw();
  335. uni.canvasToTempFilePath({
  336. width: maxWidth,
  337. height: maxHeight,
  338. destWidth: maxWidth,
  339. destHeight: maxHeight,
  340. canvasId: "canvas",
  341. fileType: "jpg", //支持jpg或png
  342. quality: 1, //图片质量
  343. success(res3) {
  344. let path1 = res3.tempFilePath;
  345. console.log(path1);
  346. this.$store.state.imageBase = path1;
  347. // that.toBase64(path1); //转base64图片
  348. },
  349. });
  350. this.takeToReset();
  351. break;
  352. case 3:
  353. // console.log("左旋转 90度");
  354. width = maxHeight;
  355. height = maxWidth;
  356. ctx.rotate(degree);
  357. ctx.drawImage(img.src, -width, 0, width, height);
  358. ctx.draw();
  359. uni.canvasToTempFilePath({
  360. width: maxHeight,
  361. height: maxWidth,
  362. destWidth: maxHeight,
  363. destHeight: maxWidth,
  364. canvasId: "canvas",
  365. fileType: "jpg", //支持jpg或png
  366. quality: 1, //图片质量
  367. success(res3) {
  368. let path1 = res3.tempFilePath;
  369. console.log(path1);
  370. this.$store.state.imageBase = path1;
  371. // that.toBase64(path1); //转base64图片
  372. },
  373. });
  374. this.takeToReset();
  375. break;
  376. default:
  377. //不旋转
  378. width = maxWidth;
  379. height = maxHeight;
  380. ctx.drawImage(img.src, 0, 0, width, height);
  381. ctx.draw();
  382. uni.canvasToTempFilePath({
  383. width: maxWidth,
  384. height: maxHeight,
  385. destWidth: maxWidth,
  386. destHeight: maxHeight,
  387. canvasId: "canvas",
  388. fileType: "jpg", //支持jpg或png
  389. quality: 1, //图片质量
  390. success(res3) {
  391. let path1 = res3.tempFilePath;
  392. console.log(path1);
  393. this.$store.state.imageBase = path1;
  394. // that.toBase64(path1); //转base64图片
  395. },
  396. });
  397. this.takeToReset();
  398. break;
  399. }
  400. },
  401. //上传图片
  402. upload() {
  403. let idnum = this.$store.state.idnum;
  404. let image = this.$store.state.imageBase;
  405. this.isShow3 = !this.isShow3; //关闭提示框
  406. uni.showToast({
  407. title: "人脸匹配中",
  408. icon: "loading",
  409. mask: true,
  410. duration: 2000,
  411. });
  412. if (idnum && image) {
  413. uni.request({
  414. url: "https://jtishfw.ncjti.edu.cn/yinxin/ncjtSecurityManagement/verifyBase64ImagesWithIDNumber",
  415. data: {
  416. idnum: idnum,
  417. image: image,
  418. },
  419. header: { "content-type": "application/x-www-form-urlencoded" },
  420. method: "POST",
  421. sslVerify: true,
  422. success: ({ data, statusCode, header }) => {
  423. if (data.error) {
  424. uni.showToast({
  425. title: "人脸匹配失败",
  426. icon: "error",
  427. mask: true,
  428. duration: 1000,
  429. });
  430. setTimeout(this.back, 1000);
  431. } else {
  432. this.$store.state.sex = data.sex;
  433. this.$store.state.examNumber = data.examNumber;
  434. setTimeout(this.uploadSucceed, 500);
  435. }
  436. },
  437. fail: () => {
  438. uni.showToast({
  439. title: "人脸提交失败",
  440. icon: "error",
  441. mask: true,
  442. duration: 1000,
  443. });
  444. setTimeout(this.back, 1000);
  445. },
  446. });
  447. } else {
  448. uni.showToast({
  449. title: "image或idnum不能为空",
  450. icon: "error",
  451. mask: true,
  452. duration: 1500,
  453. });
  454. this.isShow3 = !this.isShow3; //显示提示框
  455. }
  456. },
  457. //人脸采集成功
  458. uploadSucceed() {
  459. this.hintWord = "人脸匹配成功";
  460. this.hintImage = "../../static/images/success@2x.png";
  461. this.isShow3 = !this.isShow3;
  462. this.takeToReset();
  463. setTimeout(this.navigateToConfirm, 1500);
  464. },
  465. //图片转Base64
  466. toBase64(path) {
  467. pathToBase64(path)
  468. .then((base64) => {
  469. this.$store.state.imageBase = base64;
  470. console.log(this.$store.state.imageBase);
  471. })
  472. .catch((error) => {
  473. console.error(error);
  474. });
  475. },
  476. //跳转人脸采集确认页面
  477. navigateToConfirm() {
  478. uni.navigateTo({
  479. url: "/pages/confirm/confirm",
  480. });
  481. },
  482. //返回重新拍照
  483. back() {
  484. uni.reLaunch({
  485. url: "/pages/faceSearch/faceSea",
  486. });
  487. },
  488. },
  489. };
  490. </script>
  491. <style lang="scss">
  492. @import url("./css/faceSea.min.css");
  493. </style>