uniapp小程序端实现身份证相机
实现效果
template:
<template> <view> <!-- 选择相机拍照 --> <view class="container"> <!-- 相机 --> <!-- 初始showcamera == true显示相机,拍照后showcamera == false --> <view class="camerabox" v-if="showCamera"> <camera mode="normal" device-position="back" flash="off" > <!-- 视图容器 铺满相机 --> <cover-view class="coverView" style="width: 100%;height: 100%;"> <!-- 头像框 与相机中央显示--> <cover-view ref="coverImg" class="coverImg"></cover-view> </cover-view> </camera> </view> <!-- 照片 --> <!-- 点击拍照后,在画布上显示截取后的照片照片 --> <view class="photobox" v-if="!showCamera"> <canvas id="photo" canvas-id="photo" ref="photo" v-if="!showCamera" style="width: 250px;height: 158px;" ></canvas> <!-- 显示完整照片 --> <!-- :style="'width: ' + canvasWidth + 'px; height:' + canvasWidth + 'px;'" --> <!-- <image :src="imgurl" mode="" id="image" ref="image" ></image> --> </view> <!-- <view v-if="!showCamera" class="photobox" ref="photobox"> <image :src="imgurl" mode="" id="image" ref="image" ></image> </view> --> <!-- 底部按钮 --> <!-- 相机模式 --> <view class="bottom" v-if="showCamera"> <!-- 返回上级页面 --> <view class="button" @click="back">返回</view> <!-- 拍照按钮 --> <image src="@/static/take_camera_btn_icon.png" @click="takePhoto"></image> <!-- 打开相册选择图片 --> <view class="button" @click="chooseImage">相册</view> </view> <!-- 照片模式 --> <view class="bottom" v-else> <!-- 清除当前照片,返回相机模式 --> <view class="button" @click="clearPhoto">取消</view> <!-- 保存当前照片,传出上一级 --> <view class="button" @click="back">确定</view> </view> </view> </view> </template>
script
<script> import { mapMutations, mapState, mapActions } from 'vuex'; export default { components: { }, data() { return { cameraContext: {}, idcardFrontSide: 'front', // 标识当前拍摄的是身份证哪一面 showCamera: true, // 控制拍照还是显示拍照后的照片 isCamera: true, // 无用 imgurl: '', // 照片截取后地址 src: '', // 原照片地址 flag: true, // 拍照按钮防抖动 D: {}, // coverView盒子信息 d: {}, // coverImage盒子信息 imgW: 0, // 原图片宽 imgH: 0, // 原图片高 W: 0, H: 0, w: 0, h: 0, rx: 0, ry: 0 } }, computed:{ ...mapState({ storeData: store => store.businessJoin.fromData }), }, methods: { ...mapMutations({ setItem: 'businessJoin/setItem' }), // 返回上级 back() { // 若存在截取的照片 将图片数据保存至vuex中 if(this.imgurl) { // 拍照或相册选择成功后,将临时图片地址存在vuex if(this.idcardFrontSide == 'front') { console.log('保存了front') this.setItem({item: 'cardFontImgUrl', data: this.imgurl}) } else { console.log('保存了back') this.setItem({item: 'cardBackImgUrl', data: this.imgurl}) } } // 返回上级页面 uni.navigateBack({ delta: 1 }); }, // 点击拍照按钮照相 takePhoto() { // 若上次拍照已完成 if (this.flag == true) { var _this = this; uni.createCameraContext().takePhoto({ quality: 'high', success: (res) => { // this.showCamera = !this.showCamera // 开始拍照 开启防抖动 this.flag = false // 拍照后的完整照片 this.src = res.tempImagePath // 获取照片信息 uni.getImageInfo({ src: this.src, success: data => { // console.log('图片信息', data) // console.log('图片长', this.imgW) // console.log('图片宽', this.imgH) // 图片长宽 this.imgW = data.width this.imgH = data.height } }) }, fail(err) { console.log('拍照失败', err) } }); } }, // 获得完整照片后,截取只保留中央身份证框部分 async cutphoto() { // // 截取 // console.log('拍照了') const that = this console.log('节点外部') // 定时器保证获取到节点信息不为空 await setTimeout(()=>{ // 获取.coverView节点信息 uni.createSelectorQuery().in(this).select('.coverView').fields({ dataset: true, //返回节点 dataset size: true, // 返回节点尺寸 rect: true // 返回节点布局位置 }, data => { // 显示照片 // console.log('this.R', this.R) // console.log('#coverView节点信息') // console.log('#coverView节点信息', data) // coverView长宽 this.W = data.width this.H = data.height // 实际图片与盒子长宽的比例 this.rx = this.imgW / this.W this.ry = this.imgH / this.H // console.log('比例rx', this.rx) // console.log('比例ry', this.ry) this.D = data }).exec() // 获取.coverImg节点信息 uni.createSelectorQuery().in(this).select('.coverImg').fields({ dataset: true, size: true, rect: true }, data => { // 显示照片 this.showCamera = !this.showCamera // console.log('#coverImg节点信息') // console.log('#coverImg节点信息', data) // coverImg宽高 this.w = data.width this.h = data.height const w = this.w const h = this.h // 中央矩形区域左上角坐标 const _w = (this.W - this.w) / 2 const _h = (this.H - this.h) / 2 // 获取画布 const ctx = uni.createCanvasContext("photo", this); // 开始截取 ctx.drawImage( this.src, // 截取的原图片 _w*this.rx, _h*this.ry, // 源图像的矩形选择框的左上角 X 坐标 this.w*this.rx, this.h*this.ry, // 图像的左上角在目标canvas上 X、Y 轴的位置 0,0, // 图像的左上角在目标canvas上 X、Y 轴的位置 this.w, this.h // 在目标画布上绘制图像的宽度 高度 ) // 保存截取的内容 ctx.save() // 绘制截取后的图片 ctx.draw(true, () => { // 输出绘制后的图片 uni.canvasToTempFilePath({ canvasId: 'photo', success: function(res) { // 在H5平台下,tempFilePath 为 base64 // console.log('进入canvasToTempFilePath的success') // console.log('base64', res.tempFilePath) // 处理后的图片 that.imgurl = res.tempFilePath // 完成拍照的过程 that.flag = true } }) }) }).exec() },500) }, // // 拍摄后清除上一张照片 clearPhoto() { // console.log('清除') // const { windowWidth, windowHeight } = uni.getSystemInfoSync(); // const ctx = uni.createCanvasContext("photo", this); // ctx.clearRect(this.src, (windowWidth - 569)/2, (windowHeight - 899)/2, 569, 899); this.showCamera = !this.showCamera }, // 从相册选择图片 chooseImage() { uni.chooseImage({ count: 1, sizeType: ['original', 'compressed'], sourceType: ['album'], success: (res) => { console.log(res.tempFilePaths[0]) this.imgurl = res.tempFilePaths[0] this.back() }, fail: (err) => {} }); } }, watch: { // 拍摄照片后,调用方法截取图片 src: { handler() { this.cutphoto() } } }, onLoad(options) { // #ifdef MP if(uni.createCameraContext) { this.cameraContext = uni.createCameraContext() }else { // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示 uni.showModal({ title: '提示', content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。' }) } this.idcardFrontSide = options.idcardFrontSide console.log('当前的类型', this.idcardFrontSide) // #endif } } </script>
css
<style scoped lang="scss"> .container { height: 100vh; /*#ifdef H5 */ height: calc(100vh - var(--window-top)); /* #endif */ display: flex; flex-direction: column; background-color: #000; .camerabox { flex: 3; display: flex; justify-content: center; align-items: center; // margin-top: 40rpx; padding: 190rpx 0 150rpx; camera { display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; // width: 80vw; // height: calc(80vw / 1.58); } } .coverView { display: flex; align-items: center; justify-content: center; text-align: center; } .coverImg { // transform: rotate(-90deg); // height: 80vw; // width: calc(80vw / 1.58); // height: 500rpx; // width: 316rpx; width: 250px; height: 158px; border: 1px solid #3798F1; box-sizing: border-box; } .photobox { flex: 3; display: flex; justify-content: center; align-items: center; margin-top: 40rpx; padding: 150rpx 0; background-color: #000; #photo { // width: 100vw; // height: calc(100vh - 200rpx); // width: 100%; // height: 100%; // height: 80vw; // width: calc(80vw / 1.58); // width: 500rpx; // height: 316rpx; align-items: center; justify-content: center; background-color:#000; } #image { width: 100%; height: 100%; } // image { // width: 80vw; // height: calc(80vw / 1.58); // background-color: #808080; // } // .emtyImg { // display: flex; // align-items: center; // justify-content: center; // width: 80vw; // height: calc(80vw / 1.58); // background-color: #808080; // text { // color: #fff; // } // } } .bottom { flex: 1; display: flex; justify-content: space-around; align-items: center; width: 100%; height: 200rpx; background-color: #000; image { width: 170rpx; height: 170rpx; } .button { font-size: 30rpx; color: #fff; padding: 50rpx; } } } // 用于操作 .canvsborder{ border: 1rpx solid #333; position: fixed; top: 0; left: 10000rpx; } </style>