APP自定义身份证相机(Android +iOS)

基本上同时兼容安卓和苹果的插件都需要付费,这里我找了2个好用的免费插件

1.仅支持安卓:自定义身份证相机(支持蒙版自定义),内置蒙版,照片预览,身份证裁剪 - DCloud 插件市场、

2.支持iOS(已测),支持Android(未测,应该也可以用):

 自定义相机 - DCloud 插件市场

第一个插件使用方法(仅支持安卓):

创建一个realName.vue文件

<view class="personalInfo" style="margin-top: 20rpx;">
        <view class="label" style="margin-bottom: 8rpx;">
            <view class="blue"></view>
            <view class="title">证件图片</view>
        </view>
        <view class="tips">请拍摄或上传身份证原件照片,确保照片完整清晰</view>
        <view class="imgBox">
            <view class="front">
                <image :src="frontImg" :class="platform == 'ios' ? 'transformImg' : ''" @click="uploadImgNew('front')"/>
                <view class="frontBtn" @click="uploadImgNew('front')" v-if="frontImg == ''">
                    上传人像面
                </view>
            </view>
            <view class="back">
                <image :src="backImg" :class="platform == 'ios' ? 'transformImg' : ''" @click="uploadImgNew('back')"/>
                <view class="backBtn" @click="uploadImgNew('back')" v-if="backImg == ''">
                    上传国徽面
                </view>
            </view>
        </view>
    </view>
export default {
  data () {
    return {
        frontImg: '',
        backImg: '',
		canvasSiz:{
			width:188,
			height:273
		},
        flag: true
    }
  },
methods:{
    uploadImgNew(types){
        console.log('打开相机');
        let platform = uni.getSystemInfoSync().platform
        if(!this.flag){
            uni.showToast({
                title: '图片正在上传中,请误做其他操作', 
                icon: 'none'
            })
            return
        }
        if(platform == 'ios'){
            // ios的另外用了别的插件,下面会讲到
            uni.navigateTo({
                url: `./idcard?dotype=${types == 'front' ? 'face' : 'badge'}`
            })
        }else{
            var cameraModule = uni.requireNativePlugin('yun-camerax-module');
            //无需蒙版可将type设置为非参数值,例如 type:99
            cameraModule.takePhoto({ 
                type: types == 'front' ? 0 : 1, 
                imageIndex: 2, fullSrc: true,
                text: types == 'front' ? '将身份证正面置于此区域内并对齐边缘' : '将身份证背面置于此区域内并对齐边缘'
            }, res => {
                console.log(res);
                uni.showModal({
                    title: '提示',
                    // content: JSON.stringify(res),
                    content: '请再次确认使用该图',
                    success: (res1) => {
                        if (res1.confirm) {
                            console.log('用户点击确定',res);
                            this.upLoadImg(res.file,types)
                        } else if (res1.cancel) {
                            console.log('用户点击取消');
                        }
                    }
                });
            });
        }
    },
    async upLoadImg(path,type) {
      setTimeout(()=>{
        uni.showToast({
              title: '上传中',
              icon: 'none'
        })
        this.flag = false
        uni.uploadFile({
          url: 'xxxxxx/upload', //后端上传接口
          filePath: path,
          name: "file",
          success: (res) => {
            console.log('res222',res);
            if(JSON.parse(res.data).code == 0){
                console.log('JSON.parse(res.data)',JSON.parse(res.data));
                if(type == 'front'){
                    this.frontImg = JSON.parse(res.data).data.rel_path
                    this.$forceUpdate()
                }else{
                    this.backImg = JSON.parse(res.data).data.rel_path
                    this.$forceUpdate()
                }
                this.flag = true   
            }else{
              uni.showToast({
                  title: JSON.parse(res.data).msg,
                  icon: 'none'
              })
            }
              
          },
          fail(e) {
            this.showTip("上传图片失败");
          },
        });
      },300)
    }, 

第二个插件使用方法:

需要用到live-pusher直播推流,在manifest.json中勾选,真机调试需要重新打自定义基座再重新运行

为了防止样式兼容问题,另外需配置如下:

在同级目录下创建idcard.nvue文件

然后把下面代码整个copy进去

<template>
	<view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
		<view class="preview" :style="{ width: windowWidth, height: windowHeight - 65 }">
			<live-pusher
				id="livePusher"
				ref="livePusher"
				class="livePusher"
				mode="FHD"
				beauty="0"
				whiteness="0"
				:aspect="aspect"
				min-bitrate="1000"
				audio-quality="16KHz"
				:device-position="back"
				:auto-focus="true"
				:muted="true"
				:enable-camera="true"
				:enable-mic="false"
				:zoom="false"
				@statechange="statechange"
				:style="{ width: cameraWidth, height: cameraHeight }"
			></live-pusher>

			<!--提示语-->
			<cover-view class="remind">
				<text class="remind-text" style="">{{ message }}</text>
			</cover-view>

			<!--辅助线-->
			<cover-view class="outline-box" :style="{ width: windowWidth, height: windowHeight - 80}">
				<cover-image
					class="outline-img"
					:src="dotype == 'face' ? '/static/live-camera/outline/idcardface.png' : '/static/live-camera/outline/idcardbadge.png'"
					style=""
				></cover-image>
			</cover-view>
		</view>

		<view class="menu">
			<!--底部菜单区域背景-->
			<cover-image class="menu-mask" src="/static/live-camera/bar.png"></cover-image>

			<!--返回键-->
			<cover-image class="menu-back" @tap="back" src="/static/live-camera/back.png"></cover-image>

			<!--快门键-->
			<cover-image class="menu-snapshot" @tap="snapshot" src="/static/live-camera/shutter.png"></cover-image>

			<!--反转键-->
			<cover-image class="menu-flip" @tap="flip" src="/static/live-camera/flip.png"></cover-image>
		</view>
	</view>
</template>

<script>
let _this = null;
export default {
	data() {
		return {
			poenCarmeInterval: null, //打开相机的轮询
			dotype: 'face', //操作类型
			message: '', //提示
			aspect: '2:3', //比例
			cameraWidth: '', //相机画面宽度
			cameraHeight: '', //相机画面宽度
			windowWidth: '', //屏幕可用宽度
			windowHeight: '', //屏幕可用高度
			camerastate: false, //相机准备好了
			livePusher: null, //流视频对象
			snapshotsrc: null //快照
		};
	},
	onLoad(e) {
		console.log('e',e);
		_this = this;
		this.dotype = e.dotype;
		this.initCamera();
	},
	onReady() {
		uni.showToast({
			title: '相机加载中...',
			icon: 'none',
			duration: 800
		})
		this.livePusher = uni.createLivePusherContext('livePusher', this);
		console.log('this.livePusher',this.livePusher);
		this.startPreview(); //开启预览并设置摄像头
		this.poenCarme();
	},
	methods: {
		//轮询打开
		poenCarme() {
			//#ifdef APP-PLUS
			if (plus.os.name == 'Android') {
				console.log('111');
				this.poenCarmeInterval = setInterval(function() {
					console.log(_this.camerastate);
					if (!_this.camerastate) _this.startPreview();
				}, 2500);
			}else{
				console.log('2222');
			}
			//#endif
		},
		//初始化相机
		initCamera() {
			//处理安卓手机异步授权问题
			uni.getSystemInfo({
				success: (res) => {
					console.log('resxxxx',res);
					this.windowWidth = res.windowWidth;
					this.windowHeight = res.windowHeight;
					this.cameraWidth = res.windowWidth;
					this.cameraHeight = res.windowWidth * 1.5;
				}
			});
		},

		//开始预览
		startPreview() {
			console.log('执行开始预览');
			this.livePusher.startPreview({
				success: (a) => {
					console.log('aaa',a);
				}
			});
		},

		//停止预览
		stopPreview() {
			this.livePusher.stopPreview({
				success: a => {
					console.log('停止预览',a);
					this.camerastate = false; //标记相机未启动
				}
			});
		},

		//状态
		statechange(e) {
			//状态改变
			console.log(e);
			if (e.detail.code == 1007) {
				_this.camerastate = true;
			} else if (e.detail.code == -1301) {
				_this.camerastate = false;
			}
		},

		//返回
		back() {
			uni.navigateBack();
		},

		//抓拍
		snapshot() {
			this.livePusher.snapshot({
				success: e => {
					console.log('快门',e);
					this.snapshotsrc = e.message.tempImagePath;
					this.stopPreview();
					this.setImage();
					uni.navigateBack();
				}
			});
		},

		//反转
		flip() {
			this.livePusher.switchCamera();
		},

		//设置
		setImage() {
			let pages = getCurrentPages();
			let prevPage = pages[pages.length - 2]; //上一个页面

			//直接调用上一个页面的setImage()方法,把数据存到上一个页面中去
			prevPage.$vm.setImage({ path: this.snapshotsrc, dotype: this.dotype });
		}
	}
};
</script>

<style lang="scss">

.live-camera {
	.preview {
		justify-content: center;
		align-items: center;
		.outline-box {
			position: absolute;
			top: 0;
			left: 0;
			bottom: 0;
			z-index: 99;
			align-items: center;
			justify-content: center;
			.outline-img {
				width: 750rpx;
				height: 1125rpx;
			}
		}
		.remind {
			position: absolute;
			top: 880rpx;
			width: 750rpx;
			z-index: 100;
			align-items: center;
			justify-content: center;
			.remind-text {
				color: #dddddd;
				font-weight: bold;
			}
		}
	}
	.menu {
		position: absolute;
		left: 0;
		bottom: 0;
		width: 750rpx;
		height: 180rpx;
		z-index: 98;
		align-items: center;
		justify-content: center;
		.menu-mask {
			position: absolute;
			left: 0;
			bottom: 0;
			width: 750rpx;
			height: 180rpx;
			z-index: 98;
		}
		.menu-back {
			position: absolute;
			left: 30rpx;
			bottom: 50rpx;
			width: 80rpx;
			height: 80rpx;
			z-index: 99;
			align-items: center;
			justify-content: center;
		}
		.menu-snapshot {
			width: 130rpx;
			height: 130rpx;
			z-index: 99;
		}
		.menu-flip {
			position: absolute;
			right: 30rpx;
			bottom: 50rpx;
			width: 80rpx;
			height: 80rpx;
			z-index: 99;
			align-items: center;
			justify-content: center;
		}
	}
}

</style>

因为第一次使用nvue,代码整个都成灰色,需要在vscode设置中按下图配置,代码就会和.vue文件一样变彩色,方便阅读

在realName.vue文件中加入:

<canvas id="canvas-clipper" canvas-id="canvas-clipper" type="2d" :style="{width: canvasSiz.width+'px',height: canvasSiz.height+'px',position: 'absolute',left:'-500000px',top: '-500000px'}" />

这里用到canvas是为了把live-pusher横屏拍摄的身份证裁剪

methods:{
    //设置图片
	setImage(e) {
		console.log('跳回这个页面',e);
        let type = e.dotype == 'face' ? 'front' : 'back'
		//显示在页面
        console.log('type',type);
        // this.upLoadImg(e.path,type)
        this.zjzClipper(e.path,type)
	},
    //证件照裁切
	zjzClipper(path,type) {
		uni.getImageInfo({
			src: path,
			success: (image) => {
				console.log('image',image);
				this.canvasSiz.width =188;
				this.canvasSiz.height =273;
				
				
				//因为nvue页面使用canvas比较麻烦,所以在此页面上处理图片
				let ctx = uni.createCanvasContext('canvas-clipper', this);
				
				ctx.drawImage(
					path,
					parseInt(0.15 * image.width),
					parseInt(0.17 * image.height),
					parseInt(0.69 * image.width),
					parseInt(0.65 * image.height),
					0,
					0,
					188,
					273
				);
				
				ctx.draw(false, () => {
					uni.canvasToTempFilePath(
						{
							destWidth: 188,
							destHeight: 273,
							canvasId: 'canvas-clipper',
							fileType: 'jpg',
							success: (res) => {
								// this.savePhoto(res.tempFilePath);
                                // this.frontImg = res.tempFilePath
                                this.upLoadImg(res.tempFilePath,type)
							}
						},
						this
					);
				});
			}
		});
	},

如果想保存拍摄的照片还可以使用下面方法

savePhoto(path){
		this.imagesrc = path;
		//保存到相册
		uni.saveImageToPhotosAlbum({
			filePath: path,
			success: () => {
				uni.showToast({
					title: '已保存至相册',
					duration: 2000
				});
			}
		});
	},

realName.vue的css样式部分

.personalInfo{
        padding: 27rpx 30rpx;
        box-sizing: border-box;
        background-color: #fff;
        .label{
            display: flex;
            align-items: center;
            margin-bottom: 50rpx;
            .blue{
                width: 8rpx;
                height: 30rpx;
                background-color: #3E71FE;
                margin-right: 12rpx;
            }
            .title{
                font-weight: 500;
                font-size: 32rpx;
                color: #1D1B1A;
            }
        }
        .realName{
            display: flex;
            align-items: center;
            margin-bottom: 30rpx;
            padding-left: 20rpx;
            box-sizing: border-box;
            .name{
                font-weight: 500;
                font-size: 28rpx;
                color: #1D1B1A;
            }
        }
        .tips{
            font-weight: normal;
            font-size: 24rpx;
            color: #929292;
            margin-bottom: 30rpx;
        }
        .lineBottom{
            width: 650rpx;
            height: 2rpx;
            background: #F5F5F5;
            margin: auto;
            margin-bottom: 30rpx;
        }
        .imgBox{
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            padding: 0 82rpx;
            box-sizing: border-box;
            .front{
                position: relative;
                width: 526rpx;
                height: 288rpx;
                border-radius: 20rpx 20rpx 20rpx 20rpx;
                margin-bottom: 28rpx;
                background: url('https://res.qyjpay.cn/static/res/yewuban-smrz-zhengmian.png') no-repeat center;
                background-size: contain;
                .frontBtn{
                    position: absolute;
                    bottom: 50rpx;
                    left: 123rpx;
                    width: 280rpx;
                    height: 90rpx;
                    line-height: 90rpx;
                    background: #3E71FE;
                    box-shadow: 0rpx 8rpx 12rpx 1rpx rgba(62,113,254,0.15);
                    border-radius: 45rpx 45rpx 45rpx 45rpx;
                    font-size: 32rpx;
                    color: #FFFFFF;
                    font-weight: normal;
                    text-align: center;
                }
                image{
                    position: absolute;
                    left: 0;
                    top: 0;
                    width: 526rpx;
                    height: 288rpx;
                    border-radius: 20rpx 20rpx 20rpx 20rpx;
                }
            }
            .transformImg{
                position: absolute;
                left: 120rpx !important;
                top: -120rpx !important;
                transform: rotate(-90deg);
                width: 288rpx !important;
                height: 526rpx !important;
                z-index: 999;
            }
            .back{
                position: relative;
                width: 526rpx;
                height: 288rpx;
                border-radius: 20rpx 20rpx 20rpx 20rpx;
                background: url('https://res.qyjpay.cn/static/res/yewuban-smrz-fanmian.png') no-repeat center;
                background-size: contain;
                .backBtn{
                    position: absolute;
                    bottom: 50rpx;
                    left: 123rpx;
                    width: 280rpx;
                    height: 90rpx;
                    line-height: 90rpx;
                    background: #3E71FE;
                    box-shadow: 0rpx 8rpx 12rpx 1rpx rgba(62,113,254,0.15);
                    border-radius: 45rpx 45rpx 45rpx 45rpx;
                    font-size: 32rpx;
                    color: #FFFFFF;
                    font-weight: normal;
                    text-align: center;
                }
                image{
                    position: absolute;
                    left: 0;
                    top: 0;
                    width: 526rpx;
                    height: 288rpx;
                    border-radius: 20rpx 20rpx 20rpx 20rpx;
                }
            }
        }
    }

里面的图片和结构根据项目需求自行修改

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/569899.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端CSS基础8(盒子模型(margin、border、padding、content))

前端CSS基础8&#xff08;盒子模型&#xff08;margin、border、padding、content&#xff09;&#xff09; CSS盒子模型CSS中常用的长度单位元素的分类&#xff0c;各个元素的显示模式修改元素的显示模式&#xff08;类型&#xff09;盒子模型的组成部分盒子内容区-contentCSS…

激活虚拟环境.ps1“因为在此系统上禁止运行脚本”解决办法

激活虚拟环境.ps1“因为在此系统上禁止运行脚本”解决办法 1.问题收录 Django激活虚拟环境时遇到的&#xff0c;已解决&#xff0c;作以收录&#xff0c;希望能帮到大家 2.分析问题 核心是Powershell的安全策略&#xff0c;将XX命令视为不安全脚本&#xff0c;不允许执行&…

树莓集团有效链接政、企、校,搭建三方合作平台

树莓集团——数字生态产业链建设者&#xff0c;有效链接政、企、校&#xff0c;搭建三方合作平台。集团旗下树莓教育拥有发展数字影像培训十余年的成都王老师摄影培训学校&#xff0c;一家在数字影像教育领域中独树一帜的专业机构。树莓集团凭借其深厚的教育积淀和丰富的实践经…

单片机通讯协议

参考&#xff1a;江科大单片机教程 STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili IIC通讯协议SPI通信协议UARTCANUSB速度100k-400khz4Mhz-线数2 CLK,DATA4CLK,ENB,IO,OI额外设备一主多从一主多从 一般不用自己写&#xff0c;都有相应的库或官方提供相应的&#…

Mysql用语句创建表/插入列【示例】

一、 创建表 COMMENT表示字段或列的注释 -- 新建student表 CREATE TABLE student (id BIGINT NOT NULL COMMENT 学生id, enroll_date DATE NOT NULL COMMENT 注册时间, NAME VARCHAR(18) DEFAULT NOT NULL COMMENT 学生姓名, deal_flag TINYINT(1) DEFAULT 0 NOT NULL COMM…

linux开发板开机启动向日葵

硬件&#xff1a;orangepi 5 pro 操作系统&#xff1a;ubuntu 20.4 lts 安装向日葵 根据我的实测&#xff0c;arm架构的ubuntu系统只能安装向日葵提供的麒麟系统的那个版本&#xff0c;具体安装方式官网下载页面有 允许任意用户连接到 X11 使用root用户登录后打开终端输入一下…

数据分析学习资源(未完)

1、PDF 数据分析自学攻略 增长黑客&#xff08;AARRR&#xff09; 量化思维

Centos7升级编译器

Centos7默认编译器版本&#xff1a; gcc5.1之前的编译器&#xff0c;默认是C98标准的&#xff0c;若是编译一些支持C高版本的软件时&#xff0c;难免会出现问题。例如&#xff1a;编译最新版jsoncpp&#xff0c;会有如下问题&#xff1a;&#xff08;原因是&#xff1a;std在C9…

从阿里云迁移Redis到AWS的规划和前期准备

在将Redis实例从阿里云迁移到AWS之前,需要进行全面的规划和前期准备。以下九河云提供一些重要的步骤和注意事项: 1. 评估Redis使用情况 首先,您需要评估当前Redis实例的使用情况,包括实例规格、内存使用量、吞吐量、访问模式等。这将有助于选择合适的AWS Redis产品和实例类型…

代码随想录算法训练营day40

题目&#xff1a;343. 整数拆分、96.不同的二叉搜索树 参考链接&#xff1a;代码随想录 343. 整数拆分 思路&#xff1a;五部曲来走。dp数组&#xff0c;dp[i]用于记录拆i得到的最大乘积和&#xff0c;我们要求的也就是dp[n]&#xff1b;递推公式&#xff0c;我们想拆分i&am…

薄板样条插值TPS原理以及torch和opencv实现

薄板样条插值TPS原理以及torch和opencv实现 1、薄板样条插值TPS原理概述原理以及公式推导2、torch实现3、opencv实现1、薄板样条插值TPS原理 概述 薄板样条(Thin Plate Spline),简称TPS,是一种插值方法,可找到通过所有给定点的“最小弯曲”光滑曲面。因为它一般都是基于…

Echarts水球图的配置项,掌握后极其简单。

Echarts水球图&#xff08;Liquid Fill Gauge&#xff09;是 Echarts 中的一种数据可视化图表类型&#xff0c;用于展示一种类似水球的效果&#xff0c;可以直观地显示一个数值相对于总量的比例。水球图通常用于展示进度、完成率、占比等数据&#xff0c;具有直观、美观的特点&…

Win linux 下配置adb fastboot

一、Win配置adb & fastboot 环境变量 主机&#xff1a;Win10&#xff0c;除了adb fastboot需要设置变量之外&#xff0c;驱动直接安装即可 win下adb fastboot 下载地址&#xff1a;https://download.csdn.net/download/u012627628/89215420 win下qcom设备驱动下载地址&a…

反向海淘代购系统是什么?如何为国外的人代购中国电商平台的商品?

随着全球化的深入发展&#xff0c;跨境购物已成为越来越多人的日常选择。然而&#xff0c;传统意义上的“海淘”主要是指中国消费者从国外电商平台购买商品。近年来&#xff0c;随着中国电商市场的蓬勃发展&#xff0c;越来越多的海外消费者也开始对中国商品产生浓厚兴趣&#…

Memecoin再迎爆发:是本轮牛市大反弹的开始吗?

在加密货币市场上&#xff0c;Memecoin再度掀起了一波热潮&#xff0c;引发了人们对于本轮牛市是否即将到来的猜测和期待。近期&#xff0c;诸如BONK、PEPE和POPCAT等Memecoin的价格出现了显著的上涨&#xff0c;涨幅之大令人瞠目。这一现象引发了广泛的讨论&#xff0c;人们开…

C++之入门

文章目录 1、前言2、C的关键字2.1C语言32关键字2.2C关键字(63个) 3、命名空间4、输入输出(cout、cin)4、缺省参数5、函数重载6 引用6.1 引用的定义6.2 引用的特性6.3引用的使用场景6.4 实际例子6.5、总结 7、内联函数8、auto关键字9、nullptr关键字 1、前言 C语言是结构化和模…

恶意软件狩猎新途径:使用.NET元数据分析跟踪恶意软件

本文由Blaze于2024年3月25日发表于其个人博客网站上。 就在不久前&#xff0c;我们意外发现了一个PureCrypter样本&#xff0c;而PureCrypter则是一款适用于各种类型恶意软件&#xff08;例如Agent Tesla和RedLine&#xff09;的加载器和混淆处理工具。深入分析之后&#xff0c…

BDC报错信息查看

1.在事务代码st22的报错信息中下载本地文件 2.打开本地文件查看报错信息 3.在事务代码se91中输入对应消息类和消息编号 4.查看报错信息&#xff0c;根据报错信息取解决问题

GaussDB数据库SQL系列-聚合函数

背景 在这篇文章中&#xff0c;我们将深入探讨GaussDB数据库中聚合函数的使用和优化。聚合函数是数据库查询中非常重要的工具&#xff0c;它们可以对一组值执行计算并返回单个值。例如&#xff0c;聚合函数可以用来计算平均值、总和、最大值和最小值。 这些功能在数据分析和报…

数据结构(七)---树

目录 一.树的基本概念 二.树的性质 三.二叉树 1.二叉树的基本概念 2.特殊的二叉树 &#xff08;1&#xff09;满二叉树 &#xff08;2&#xff09;完全二叉树 &#xff08;3&#xff09;二叉排序树 &#xff08;4&#xff09;平衡二叉树 3.二叉树的性质 4.完全二叉树…