自定义相机 Failed to obtain the rear camera of the device. Please try another solution to obtain resources!
Loading... * { margin: 0; padding: 0; box-sizing: border-box; border: 0; } html, body { width: 100%; height: 100%; overflow: hidden; background-color: #000; color: #fff; } .cancleBtn { padding: 2vw 0; width: 100%; } .takeOffTip { position: fixed; padding-top: 2vw; top: 0; left: 0; width: 100%; font-size: 1.8vw; text-align: center; color: #fff; } .bottonSize { height: 100%; line-height: 6vw; line-height: 6dvw; padding: 0 1.5vw; } .bottomBtnBox, .rightBtnBox { position: fixed; right: 0; display: flex; justify-content: space-between; align-items: center; background-color: #000; z-index: 10; } .bottomBtnBox { bottom: 0; width: 100%; height: 6vw; height: 6dvw; } .rightBtnBox { flex-direction: column; top: 0; height: 100%; width: 6vw; width: 6dvw; } html[prew='-1'] .bottomBtnBox, html[prew='0'] .bottomBtnBox, html[prew='-1'] .rightBtnBox, html[prew='1'] .rightBtnBox, html[prew='1'] .customer_carema { display: none; } html[prew='1'] .imgBox { border: 0; font-size: 0; opacity: 0; } .takeBtn { padding: 4px; width: 5vw; width: 5dvw; height: 5vw; height: 5dvw; background-color: #fff; border-radius: 50%; } .takeBtn::before { content: ''; display: block; width: 100%; height: 100%; border: 5px solid #000; background-color: #fff; border-radius: 50%; box-sizing: border-box; } .rightBtnBox::before { content: ''; display: block; } .btn { background-color: #000; text-align: center; font-size: 1.5vw; color: #fff; } .customer_video, .carema_img, .cuteImg { width: 100%; height: 100%; object-fit: cover; } .imgBoxDom { position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; z-index: 9; } .imgBox { width: var(--carema-box-width); height: var(--carema-box-height); border: 2px solid #fff; display: flex; justify-content: center; align-items: center; font-size: 10vw; z-index: 10; border-radius: 2vw; } .errTip { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 8888; display: none; flex-direction: column; justify-content: center; align-items: center; background-color: #000; } .errTip>p { padding-bottom: 20px; color: #fff; } .errTip button { padding: 10px 30px; } html[prew='2'] .errTip { display: flex; } html[loaded='1'] .loading-css { display: none; } .loading-css { position: fixed; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; background-color: #000; z-index: 9999; } .loading-css::before { margin-bottom: 10px; content: ''; width: 50px; height: 50px; display: inline-block; border: 3px solid #f3f3f3; border-top: 3px solid rgb(160, 155, 155); border-radius: 50%; animation: loading-360 0.8s infinite linear; } @keyframes loading-360 { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } 调试相机 function WbCRM() { this.body = document.body; this.html = document.documentElement; this.takeBtn = document.querySelector('.takeBtn'); this.imgBox = document.querySelector('.imgBox'); this.reTakeBtn = document.querySelector('.reTakeBtn'); this.cancleBtn = document.querySelector('.cancleBtn'); this.nextBtn = document.querySelector('.nextBtn'); var errBtn = document.querySelector('.errBtn'); this.video = null; this.err = null; this.fullImg = null; this.file = ''; this.idType = ''; this.isDev = false; this.stream = null; this.openId = ''; this.ratio = window.devicePixelRatio || 1; this.videoWidth = this.body.clientWidth * this.ratio; this.videoHeight = this.body.clientHeight * this.ratio; this.html.setAttribute('prew', '-1'); var isMp3 = !(navigator.userAgent.match(/Firefox/)); var audio = new Audio(); audio.autoplay = isMp3 ? './shutter.mp3' : './shutter.ogg'; this.audio = audio; console.log(isMp3,audio); this.mediaDevices = (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) ? navigator.mediaDevices : ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? { getUserMedia: function (c) { return new Promise(function (y, n) { (navigator.mozGetUserMedia || navigator.webkitGetUserMedia).call(navigator, c, y, n); }); } } : null); this.setDom(); this.setCarema(); this.takeBtn.addEventListener('click', this.takePhoto.bind(this)); this.nextBtn.addEventListener('click', this.next.bind(this)); this.reTakeBtn.addEventListener('click', this.reTake.bind(this)); this.cancleBtn.addEventListener('click', this.cancle.bind(this)); errBtn.addEventListener('click', this.openErro.bind(this)); } WbCRM.prototype.openErro = function () { this.sendMsg('open_erro'); } WbCRM.prototype.cancle = function () { this.removeStream(); this.sendMsg('off_carema'); } WbCRM.prototype.next = function () { if (this.fullImg) this.fullImg.remove(); this.removeStream(); this.sendMsg('success_file'); } WbCRM.prototype.reTake = function () { this.file = null; this.err = null; if (this.fullImg) this.fullImg.remove(); this.html.setAttribute('loaded', 0); this.removeStream(); this.setCarema(); } WbCRM.prototype.cutImage = function () { var boxWidth = this.imgBox.clientWidth * this.ratio; var boxHeight = this.imgBox.clientHeight * this.ratio; var vLeft = (this.videoWidth - boxWidth) / 2; var vTop = (this.videoHeight - boxHeight) / 2; var nCanvas = wbCRMTools.drawHighDefinitionImg(boxWidth, boxHeight); var nCtx = nCanvas.getContext('2d'); nCtx.drawImage(this.fullImg, -vLeft, -vTop); var cutImage = nCtx.getImageData(0, 0, boxWidth, boxHeight); wbCRMTools.changeImgData(cutImage?.data || [], this.idType || ''); nCtx.putImageData(cutImage, 0, 0); reImgUrl = nCanvas.toDataURL('image/jpeg'); var cImg = document.createElement('img'); cImg.src = reImgUrl; this.file = wbCRMTools.canvas2File(reImgUrl); wbCRMTools.clearCanvas(nCtx, nCanvas); cImg.className = "cuteImg"; this.imgBox.append(cImg); this.html.setAttribute('prew', '1'); this.removeStream(); } WbCRM.prototype.takePhoto = function () { var gCanvas = wbCRMTools.drawHighDefinitionImg(this.videoWidth, this.videoHeight); var originalCtx = gCanvas.getContext('2d'); originalCtx.drawImage(this.video, 0, 0, this.videoWidth, this.videoHeight); var imgUrl = gCanvas.toDataURL('image/jpeg'); var fullImg = document.createElement("img"); fullImg.className = "carema_img"; fullImg.src = imgUrl; this.fullImg = fullImg; this.body.append(fullImg); wbCRMTools.clearCanvas(originalCtx, gCanvas); this.audio.play(); fullImg.onload = this.cutImage.bind(this); } WbCRM.prototype.sendMsg = function (mothod) { this.audio.remove(); const origin = this.isDev ? undefined : window.location.origin; window.opener.postMessage({ mothod: mothod, file: this.file, openId: this.openId, error: this.err }, origin); window.close(); } WbCRM.prototype.removeStream = function () { var self = this; if (self.stream) { self.stream.getTracks().forEach(function (track) { if (track.readyState === 'live') track.stop(); self.stream.removeTrack(track); }); } if (this.video) this.video.remove(); var cuteImgList = document.querySelectorAll('.cuteImg'); cuteImgList.forEach(function (dom) { dom.remove(); }) } WbCRM.prototype.setDom = function () { this.openId = wbCRMTools.getUrlParam('openId'); var okText = wbCRMTools.getUrlParam('continue'); var cancelText = wbCRMTools.getUrlParam('cancel'); var retakeText = wbCRMTools.getUrlParam('retake'); var idType = wbCRMTools.getUrlParam('idType') || ''; var takeOffTip = wbCRMTools.getUrlParam('takeOffTip'); const isDev = wbCRMTools.getUrlParam('isDev'); this.isDev = isDev === '1'; this.nextBtn.innerText = okText || 'Cuntinue'; this.cancleBtn.innerText = cancelText || 'Cancel'; this.reTakeBtn.innerText = retakeText || 'Retake'; document.querySelector('.takeOffTip').innerHTML = takeOffTip; this.html.setAttribute('loaded', 0); this.html.style.setProperty('--carema-box-width', '64.512vw'); this.html.style.setProperty('--carema-box-height', '40.6789vw'); if (idType === "LANDING") { this.html.style.setProperty('--carema-box-width', '51.2vw'); this.html.style.setProperty('--carema-box-height', '44.5935vw'); } this.idType = idType; } WbCRM.prototype.setVideo = function (stream) { var video = document.createElement('video'); video.setAttribute('autoplay', 'autoplay'); video.setAttribute('playsinline', 'playsinline'); video.className = 'customer_video'; this.video = video; this.stream = stream; this.body.append(video); var self = this; video.onloadedmetadata = function (e) { self.stream = stream; self.loaded = true; self.html.setAttribute('loaded', 1); }; video.onplay = function () { self.html.setAttribute('prew', '0'); } // as window.URL.createObjectURL() is deprecated, adding a check so that it works in Safari. // older browsers may not have srcObject if ("srcObject" in video) { video.srcObject = stream; } else { // using URL.createObjectURL() as fallback for old browsers video.src = window.URL.createObjectURL(stream); } } WbCRM.prototype.setCarema = function () { const videoConf = this.isDev ? {} : { width: { min: 1024, ideal: 2360, max: 2732 }, height: { min: 776, ideal: 1640, max: 2048 }, facingMode: { exact: "environment" } } var self = this; this.mediaDevices.getUserMedia({ audio: false, video: videoConf }).then(this.setVideo.bind(this)).catch(function (error) { self.err = error.toString(); self.html.setAttribute('prew', '2'); self.html.setAttribute('loaded', '1'); }) } window.addEventListener('load', function () { var wbCRM = new WbCRM(); window.addEventListener('visibilitychange', function () { wbCRM.removeStream(); window.close(); }); }); var wbCRMTools = { drawHighDefinitionImg: function (width, height) { const canvas = document.createElement('canvas'); canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; canvas.width = width; canvas.height = height; return canvas; }, clearCanvas: function (ctx, canvas) { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.beginPath(); canvas.height = 0; canvas.width = 0; canvas.remove(); canvas.parentNode?.removeChild(canvas); }, changeImgData: function (data, idType) { const isGrayscale = ['PASSPORT', 'LANDING', 'ENTRYPERMIT', 'SUP_LEGAL_ID'].some(imgType => idType.indexOf(imgType) !== -1); let contrast = 35; const thereshold = 20; if ('LANDING' === idType) contrast = 45; // gaussBlur will use in the feature, cancel this fun now, don`t delete please // this.gaussBlur(imageData, 1); // If MacId and HK-LANDING change cavans-img-code. const factor = (255 + contrast) / (255.01 - contrast); //add .1 to avoid /0 error const denominator = 1 / (1 - contrast / 255) - 1; const setCV = cv => cv + (cv - thereshold) * denominator; const setCTV = cv => cv + (cv - thereshold) * contrast / 255; const getRGB = cv => factor * (cv - 128) + 128; // Data array data-length. const len = data?.length || 0; // loop value to change cavans imgData; for (let index = 0; index < len; index += 4) { let R = data[index]; //r value let G = data[index + 1]; //g value let B = data[index + 2] //b value if (contrast || thereshold) { R = getRGB(R); //r value G = getRGB(G); //g value B = getRGB(B); //b value } const isColorNum = index % 4 === 0; if (isColorNum) { R = contrast ? setCV(R) : setCTV(R); G = contrast ? setCV(G) : setCTV(G); B = contrast ? setCV(B) : setCTV(B); if (isGrayscale) { const vNum = Math.round((R + G + B) / 3); R = vNum; G = vNum; B = vNum; data[index + 3] = 255; } data[index] = R; data[index + 1] = G; data[index + 2] = B; } } }, getUrlParam: function (urlKey) { var url = window.location.search; var reg = new RegExp("(^|&)" + urlKey + "=([^&]*)(&|$)"); var result = url.substring(1).match(reg); return result ? decodeURIComponent(result[2]) : null; }, canvas2File: function (dataUrl) { let arr = dataUrl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } const nowId = Date.now(); const fileName = `takePhoto_${nowId}.jpeg`; const blob = new Blob([u8arr], { type: mime, name: fileName }); blob.lastModifiedDate = new Date(); return new File([blob], fileName, { type: "image/jpeg" }); } } 

