• uniapp 小程序 身份证 和人脸视频拍摄


     使用前提:

        已经在微信公众平台的用户隐私协议,已经选择配置“摄像头,录像”等权限

    开发背景:客户需要使用带有拍摄边框的摄像头 ,微信小程序的方法无法支持,使用camera修改

       身份证正反面:

    1. <template>
    2. <view :style="{ height: windowHeight + 'px' }">
    3. <camera
    4. mode="normal"
    5. :device-position="devicePosition"
    6. flash="off"
    7. :style="{ height: cameraHeight + 'px' }"
    8. >
    9. <cover-view class="controls" style="width: 100%;height: 100%;">
    10. <cover-image
    11. v-show="!idcardFrontSide"
    12. class="w569-h828"
    13. src="/static/images/index/camera_module_side.png"
    14. />
    15. cover-view>
    16. <cover-image
    17. v-show="!idcardFrontSide"
    18. class="w569-h828"
    19. src="/static/images/index/camera_module_side.png"
    20. />
    21. cover-view>
    22. camera>
    23. <view class="bottom font-36-fff">
    24. <view class="wrap">
    25. <view class="back" @click="switchBtn">切换view>
    26. <view @click="takePhoto">
    27. <image class="w131-h131" src="/static/images/index/take_camera_btn_icon.png">
    28. image>
    29. view>
    30. <view @click="chooseImage">
    31. 相册
    32. view>
    33. view>
    34. view>
    35. view>
    36. template>
    37. <script>
    38. export default {
    39. data() {
    40. return {
    41. cameraContext: {},
    42. windowHeight: '',
    43. cameraHeight: '',
    44. idcardFrontSide: true,
    45. devicePosition: 'front',
    46. };
    47. },
    48. onLoad(options) {
    49. if(uni.createCameraContext) {
    50. this.cameraContext = uni.createCameraContext()
    51. }else {
    52. // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
    53. uni.showModal({
    54. title: '提示',
    55. content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
    56. })
    57. }
    58. },
    59. onShow() {
    60. const systemInfo = uni.getSystemInfoSync()
    61. this.windowHeight = systemInfo.windowHeight
    62. this.cameraHeight = systemInfo.windowHeight - 80
    63. },
    64. methods: {
    65. // 拍照
    66. takePhoto() {
    67. uni.showLoading({
    68. title:'拍摄中'
    69. })
    70. this.cameraContext.takePhoto({
    71. quality: 'high',
    72. success: (res) => {
    73. uni.showToast({
    74. title:'拍照成功',
    75. icon: 'none',
    76. duration: 1200
    77. })
    78. },
    79. fail: (err) => {
    80. uni.showToast({
    81. title:'拍照失败,请检查系统是否授权',
    82. icon: 'none',
    83. duration: 1200
    84. })
    85. }
    86. })
    87. },
    88. // 从相册选取
    89. chooseImage() {
    90. uni.chooseImage({
    91. count: 1,
    92. sizeType: ['original', 'compressed'],
    93. sourceType: ['album'],
    94. success: (res) => {},
    95. fail: (err) => {}
    96. });
    97. },
    98. },
    99. // 切换摄像头
    100. switchBtn() {
    101. if(this.devicePosition === 'back') {
    102. this.devicePosition = 'front'
    103. } else {
    104. this.devicePosition = 'back'
    105. }
    106. },
    107. }
    108. script>
    109. <style lang="less" scoped>
    110. .icon-w569-h828 {
    111. width: 569rpx;
    112. height: 828rpx;
    113. }
    114. .controls {
    115. position: relative;
    116. display: flex;
    117. align-items: center;
    118. justify-content: center;
    119. }
    120. .bottom {
    121. width: 100%;
    122. background-color: #000;
    123. .wrap {
    124. display: flex;
    125. align-items: center;
    126. justify-content: space-between;
    127. height: 80px;
    128. padding: 0 73rpx;
    129. }
    130. }
    131. .w569-h828 {
    132. width: 569rpx;
    133. height: 828rpx;
    134. }
    135. .w131-h131 {
    136. width: 131rpx;
    137. height: 131rpx;
    138. }
    139. .font-36-fff {
    140. font-size: 36rpx;
    141. color: #fff;
    142. }
    143. style>

    人脸视频:

    1. <template>
    2. <view class="container background-color-474747" :style="{height: windowHeight + 'px'}">
    3. <view class="video-wrap wpercent-100 text-align" :style="{height: takeVideoHeight + 'px'}" v-if="tipShow">
    4. <view class="content-wrap">
    5. <view class="font-36-fff font-weight">请保持声音清晰,话术完整,露出五官view>
    6. <view class="padding-top-20 font-36-fff font-weight">不符合以上要求,需重新拍摄view>
    7. <view class="padding-top-35 padding-bottom-30 font-24-FF2323 font-weight">点击下方按钮开始拍摄view>
    8. <image class="tips-icon" src="/static/images/index/take_video_tips.png">image>
    9. <text class="know" @click="startCenterCountDown">知道了text>
    10. view>
    11. view>
    12. <view class="video-wrap wpercent-100" v-if="cameraShow" >
    13. <view v-if="!centerCountDownShow" class="number">{{ second }}sview>
    14. <camera
    15. mode="normal"
    16. class="wpercent-100"
    17. :device-position="devicePosition"
    18. :style="{height: takeVideoHeight + 'px'}">
    19. <cover-view class="center-count-down-wrap" v-if="centerCountDownShow && centerCountDownValue != 4">
    20. <cover-view :class="centerCountDownValue === '开始' ? 'center-count-down-start' : 'center-count-down'">{{ centerCountDownValue }}cover-view>
    21. cover-view>
    22. <cover-image v-if="!centerCountDownShow" class="controls" src="/static/images/index/take_video_back.png"/>
    23. <cover-view class="font-36-fff font-weight absolute-one-font" v-if="!centerCountDownShow">
    24. 正视镜头录制一段匀速朗读下方数字的视频
    25. cover-view>
    26. <cover-view class="font-36-fff font-weight absolute-two-font" v-if="!centerCountDownShow">
    27. 1234
    28. cover-view>
    29. camera>
    30. view>
    31. <transition name="fade" :duration="{ enter: 500, leave: 800 }">
    32. <view class="bottom" v-if="showBottom">
    33. <view class="wrap">
    34. <view class="back" @click="backTwoStep">
    35. <image class="w55-h49" src="/static/images/index/back_before_icon.png">image>
    36. view>
    37. <view class="take" @click="startCenterCountDown" v-if="tipShow">
    38. <image class="w100-h100" src="/static/images/index/take_btn_icon.png">image>
    39. view>
    40. <view class="take" @click="stopRecord" v-if="cameraShow && !centerCountDownShow">
    41. <image class="w100-h100" src="/static/images/index/take_btn_icon.png">image>
    42. view>
    43. <view class="switch" @click="switchCamera">
    44. <image class="w69-h56" src="/static/images/index/switch_camera_icon.png">image>
    45. view>
    46. view>
    47. view>
    48. transition>
    49. view>
    50. template>
    51. <script>
    52. export default {
    53. data() {
    54. return {
    55. windowHeight: '',
    56. takeVideoHeight: '',
    57. tipShow: true,
    58. showBottom: true,
    59. centerCountDownShow: false,
    60. cameraShow: false,
    61. centerCountDownValue: 4,
    62. cameraContext: {},
    63. devicePosition: 'front',
    64. second: 9,
    65. setTimer: '',
    66. };
    67. },
    68. onLoad() {
    69. if(uni.createCameraContext) {
    70. setTimeout(() => {
    71. this.cameraContext = uni.createCameraContext();
    72. },200)
    73. }else {
    74. // 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
    75. uni.showModal({
    76. title: '提示',
    77. content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。'
    78. })
    79. }
    80. },
    81. created() {
    82. const systemInfo = uni.getSystemInfoSync()
    83. this.windowHeight = systemInfo.windowHeight
    84. this.computedHeight(80)
    85. },
    86. methods: {
    87. // 计算height
    88. computedHeight (number) {
    89. const systemInfo = uni.getSystemInfoSync()
    90. this.takeVideoHeight = systemInfo.windowHeight - number
    91. },
    92. // 开始倒计时 3,2,1,开始
    93. startCenterCountDown () {
    94. this.computedHeight(0)
    95. this.setBoolean(false)
    96. this.centerCountDown()
    97. },
    98. // 中间倒计时
    99. centerCountDown() {
    100. let promise = new Promise((resolve, reject) => {
    101. let setTimer = setInterval(() => {
    102. if(this.centerCountDownValue === 1) {
    103. this.centerCountDownValue = '开始'
    104. resolve(setTimer)
    105. } else {
    106. this.centerCountDownValue = this.centerCountDownValue - 1
    107. }
    108. if(this.centerCountDownValue === 2) { // this.cameraContext.startRecord 有延迟执行的问题,所以需要提前半秒执行
    109. setTimeout(() => {
    110. this.startRecord()
    111. }, 1200)
    112. }
    113. }, 1000)
    114. })
    115. promise.then((setTimer) => {
    116. clearInterval(setTimer)
    117. this.computedHeight(80)
    118. this.showBottom = true
    119. this.centerCountDownShow = false
    120. })
    121. },
    122. // 开始录像
    123. startRecord() {
    124. this.cameraContext.startRecord({
    125. success: (res) => {
    126. this.rightTopCountDown()
    127. },
    128. fail: (err) => {
    129. uni.showToast({
    130. title: '录像失败,请重试',
    131. icon: 'none',
    132. duration: 1200
    133. })
    134. }
    135. })
    136. },
    137. // 右上角倒计时
    138. rightTopCountDown() {
    139. let promise = new Promise((resolve, reject) => {
    140. this.setTimer = setInterval(() => {
    141. this.second = this.second - 1
    142. if (this.second <= 0) {
    143. this.stopRecord()
    144. resolve(this.setTimer)
    145. }
    146. }, 1000)
    147. })
    148. promise.then((setTimer) => {
    149. clearInterval(setTimer)
    150. this.second = 9
    151. })
    152. },
    153. // 结束录像
    154. stopRecord() {
    155. uni.showToast({
    156. title: '结束录像,正在处理视频',
    157. icon: 'none',
    158. duration: 10000
    159. })
    160. clearInterval(this.setTimer)
    161. this.second = 9
    162. this.showBottom = false
    163. this.computedHeight(0)
    164. this.cameraContext.stopRecord({
    165. compressed: true,
    166. success: (res) => {
    167. uni.setStorageSync('taxCollectVideoPath',res.tempVideoPath)
    168. setTimeout(() => {
    169. this.stopRecordInitData()
    170. }, 500)
    171. },
    172. fail: (err) => {
    173. this.showBottom = true
    174. this.computedHeight(80)
    175. uni.showToast({
    176. title: '操作失败,请重试',
    177. icon: 'none',
    178. duration: 1200
    179. })
    180. }
    181. })
    182. },
    183. // 切换摄像头
    184. switchCamera() {
    185. if(this.devicePosition === 'back') {
    186. this.devicePosition = 'front'
    187. } else {
    188. this.devicePosition = 'back'
    189. }
    190. },
    191. // 结束录像之后 初始数据
    192. stopRecordInitData () {
    193. this.computedHeight(80)
    194. this.setBoolean(true)
    195. this.centerCountDownValue = 4
    196. this.second = 9
    197. },
    198. // 设置 boolean
    199. setBoolean(boolean) {
    200. this.tipShow = boolean
    201. this.showBottom = boolean
    202. this.cameraShow = !boolean
    203. this.centerCountDownShow = !boolean
    204. },
    205. }
    206. }
    207. script>
    208. <style lang="less" scoped>
    209. .container {
    210. position: relative;
    211. .video-wrap {
    212. position: relative;
    213. .content-wrap {
    214. position: absolute;
    215. bottom: 150px;
    216. width: 100%;
    217. }
    218. .padding-bottom-40 {
    219. padding-bottom: 40rpx;
    220. }
    221. .tips-icon {
    222. position: absolute;
    223. left: 242rpx;
    224. width: 96rpx;
    225. height: 327rpx;
    226. }
    227. .know {
    228. position: relative;
    229. top: 210rpx;
    230. left: 155rpx;
    231. display: inline-block;
    232. width: 199rpx;
    233. height: 92rpx;
    234. line-height: 92rpx;
    235. text-align: center;
    236. border: 3rpx dashed #fff;
    237. border-radius: 5rpx;
    238. font-size: 48rpx;
    239. color: #fff;
    240. }
    241. .number {
    242. position: absolute;
    243. top: 15px;
    244. right: 20px;
    245. z-index: 11;
    246. color: #fff;
    247. width: 30px;
    248. height: 30px;
    249. background-color: #7a7a7a;
    250. border-radius: 50%;
    251. text-align: center;
    252. line-height: 30px;
    253. }
    254. .center-count-down-wrap {
    255. display: flex;
    256. justify-content: center;
    257. align-items: center;
    258. width: 100%;
    259. height: 100%;
    260. }
    261. .center-count-down {
    262. font-size: 330rpx;
    263. color: #fff;
    264. font-weight: bold;
    265. }
    266. .center-count-down-start {
    267. font-size: 220rpx;
    268. color: #fff;
    269. font-weight: bold;
    270. }
    271. }
    272. .controls {
    273. position: absolute;
    274. bottom: 200rpx;
    275. width: 100%;
    276. height: 753rpx;
    277. }
    278. .absolute-one-font {
    279. position: absolute;
    280. left: 4.5%;
    281. bottom: 130rpx;
    282. }
    283. .absolute-two-font {
    284. position: absolute;
    285. bottom: 30rpx;
    286. left: 44%;
    287. }
    288. .bottom {
    289. // position: fixed;
    290. // bottom: 0;
    291. width: 100%;
    292. background-color: #000;
    293. .wrap {
    294. display: flex;
    295. align-items: center;
    296. justify-content: space-between;
    297. height: 80px;
    298. padding: 0 73rpx;
    299. }
    300. }
    301. .fade-enter-active, .fade-leave-active {
    302. transition: opacity .5s;
    303. }
    304. .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
    305. opacity: 0;
    306. }
    307. .background-color-474747 {
    308. background-color: #474747;
    309. }
    310. .wpercent-100 {
    311. width: 100%;
    312. }
    313. .text-align {
    314. text-align: center;
    315. }
    316. .font-36-fff {
    317. font-size: 36rpx;
    318. color: #fff;
    319. }
    320. .font-weight {
    321. font-weight: bold;
    322. }
    323. .w55-h49 {
    324. width: 55rpx;
    325. height: 49rpx;
    326. }
    327. .w100-h100 {
    328. width: 100rpx;
    329. height: 100rpx;
    330. }
    331. .w69-h56 {
    332. width: 69rpx;
    333. height: 56rpx;
    334. }
    335. }
    336. style>


    效果图:

    借鉴的是uniapp-components,记录一下如何使用
  • 相关阅读:
    【计算机网络】图解应用层协议
    C语言大佬的必杀技---宏的高级用法
    基于GIS的生态安全网络格局构建(附练习数据下载)
    Java Web大作业——编程导航系统
    双十一快递业务量暴增,快递驿站视频智能监控方案保障快递业务顺利开展
    外观专利申请流程是怎样的?
    Docker和K8s的发展历程
    (附源码)springboot毕业生弃置物品交易系统 毕业设计 231151
    Android AMS——创建Application(七)
    【紫光同创国产FPGA教程】【PGC1/2KG第七章】7.数字钟实验例程
  • 原文地址:https://blog.csdn.net/weixin_53105591/article/details/134370229