face.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="applicable-device" content="mobile">
  6. <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
  7. <title>H5摄像头(新版浏览器https)(兼容老版浏览器)</title>
  8. <!-- <script type="text/javascript" src="https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js">
  9. </script> -->
  10. <script type="text/javascript" src="js/uni.webview.1.5.2.js">
  11. </script>
  12. </head>
  13. <body style="background-color: blanchedalmond;display: flex;flex-direction: column;">
  14. <!-- 说明:将网页更改为https访问才行 否者报错:NotSupportedError Only secure origins are allowed (see: https://goo.gl/Y0ZkNV). -->
  15. <!-- video用于显示媒体设备的视频流,自动播放;属性:https://zhuanlan.zhihu.com/p/535917105 -->
  16. <!-- <img class="face-mark" src="../images/face-mark.png" alt="" /> -->
  17. <!-- transform: rotateY(180deg); 镜像解决 -->
  18. <!-- 可以通过画布canvas渲染,获取使用默认的video也行 -->
  19. <!-- <canvas id="canvas" width="500" height="400" style="transform: rotateY(180deg);"></canvas> -->
  20. <canvas class="canvas" id="canvas"></canvas>
  21. <div class="box">
  22. <span class="text">请正对摄像头</span>
  23. <video id="video" autoplay webkit-playsinline="true" playsinline="true"></video>
  24. </div>
  25. <div class="wenziBox">
  26. <div class="zhuyi">
  27. <p class="line"></p>
  28. <span>注意事项</span>
  29. <p class="line"></p>
  30. </div>
  31. <div class="imgBox">
  32. <div class="item">
  33. <img class="buttonImg" src="../images/face.png" alt="" />
  34. <span class="span">正脸</span>
  35. </div>
  36. <div class="item">
  37. <img class="buttonImg" src="../images/deng.png" alt="" />
  38. <span class="span">光线</span>
  39. </div>
  40. <div class="item">
  41. <img class="buttonImg" src="../images/qingxi.png" alt="" />
  42. <span class="span">清晰</span>
  43. </div>
  44. </div>
  45. </div>
  46. <div class="buttonBox">
  47. <!-- 拍照按钮 -->
  48. <img class="buttonImg" id="back" src="../images/back.png" />
  49. <img class="buttonImg" id="capture" src="../images/pai.png" />
  50. <img class="buttonImg" id="fanzhuan" src="../images/fan.png" />
  51. </div>
  52. <div id="popup">
  53. <img id="popupImg" style="height: 200px;width: 200px;" alt="" src="">
  54. <div class="popupBox">
  55. <button id="closeBtn">取消</button>
  56. <button id="okBtn">确认</button>
  57. </div>
  58. </div>
  59. <script type="text/javascript">
  60. var isQian = false; //是前置摄像头
  61. var isZhuan = true; //是否翻转摄像头
  62. // 获取弹窗元素
  63. var popup = document.getElementById('popup');
  64. var popupImg = document.getElementById('popupImg');
  65. popup.style.display = 'none';
  66. // 获取关闭按钮元素
  67. var closeBtn = document.getElementById('closeBtn');
  68. var okBtn = document.getElementById('okBtn');
  69. var video = document.getElementById("video");
  70. var canvas = document.getElementById("canvas");
  71. var context = canvas.getContext("2d");
  72. var v_t_w = 200,
  73. v_t_h = 200;
  74. var idealw=200;
  75. var idealh=200;
  76. var mode = 'environment';
  77. var mediaStreamTrack;
  78. document.addEventListener('UniAppJSBridgeReady', function() {
  79. okBtn.addEventListener('click', function() {
  80. uni.postMessage({
  81. data: {
  82. faceBase64: popupImg.src
  83. }
  84. });
  85. window.history.back(-1)
  86. });
  87. });
  88. // 弹出弹窗
  89. function openPopup() {
  90. popup.style.display = 'block';
  91. }
  92. // 关闭弹窗
  93. function closePopup() {
  94. takePhoto();
  95. popup.style.display = 'none';
  96. }
  97. // 绑定关闭按钮的点击事件
  98. closeBtn.addEventListener('click', closePopup);
  99. // 访问用户媒体设备的兼容方法
  100. function getUserMedia(constrains, successFun, errorFun) {
  101. //like12 modified,20210628,bug,navigator.mediaDevices为空会导致后面卡死
  102. if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  103. //最新标准API(新版浏览器https)
  104. navigator.mediaDevices.getUserMedia(constrains).then(successFun).catch(errorFun);
  105. } else if (navigator.webkitGetUserMedia) {
  106. //like12 modified,20210628,不是这种调用方法 应该为后者
  107. //webkit内核浏览器(老版浏览器)
  108. //navigator.webkitGetUserMedia(constrains).then(successFun).catch(errorFun);
  109. navigator.webkitGetUserMedia({
  110. "video": true
  111. }, successFun, errorFun);
  112. } else if (navigator.mozGetUserMedia) {
  113. //Firefox浏览器
  114. navagator.mozGetUserMedia(constrains).then(successFun).catch(errorFun);
  115. } else if (navigator.getUserMedia) {
  116. //旧版API
  117. navigator.getUserMedia(constrains).then(successFun).catch(errorFun);
  118. }
  119. }
  120. // 成功的回调函数
  121. function successFun(stream) {
  122. //like12 modifed,20210618,Chrome升级后,新版本不再支持该用法
  123. //摄像头视频流显示报错Failed to execute 'createObjectURL' on 'URL'
  124. //研究即时通信的过程中需要调用摄像头,发现报错,原来是谷歌弃用了这个方法,根据官方提示修改即可
  125. //所以原先的代码:video.src = URL.createObjectURL(stream);
  126. //需要被修改为:video.srcObject = stream;
  127. //(新版浏览器https)
  128. if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  129. video.srcObject = stream;
  130. }
  131. //(老版浏览器)
  132. else {
  133. //兼容webkit内核浏览器
  134. var CompatibleURL = window.URL || window.webkitURL;
  135. //将视频流设置为video元素的源
  136. //此处的代码将会报错 解决的办法是将video的srcObject属性指向stream即可
  137. video.src = CompatibleURL.createObjectURL(stream);
  138. }
  139. mediaStreamTrack = stream.getTracks()[0];
  140. let settings = mediaStreamTrack.getSettings();
  141. // 获取分辨率信息
  142. v_t_w = settings.width;
  143. v_t_h = settings.height;
  144. //video.width=v_t_w;
  145. //video.height=v_t_h;
  146. canvas.width = v_t_w;
  147. canvas.height = v_t_h;
  148. // 播放视频
  149. video.play();
  150. isZhuan=true;
  151. // alert('视频播放');
  152. // 可以通过画布canvas渲染,获取使用默认的video也行
  153. // setInterval(function() {
  154. // canvas.width = v_t_w;
  155. // canvas.height = v_t_h;
  156. // context.drawImage(video, 0, 0, v_t_w, v_t_h);
  157. // }, 10);
  158. }
  159. // 异常的回调函数
  160. function errorFun(error) {
  161. isZhuan=true;
  162. console.log("访问用户媒体设备失败:", error.name, error.message);
  163. alert("访问用户媒体设备失败:" + error.name + " " + error.message);
  164. }
  165. document.getElementById('fanzhuan').addEventListener('click', function() {
  166. changeMode();
  167. })
  168. document.getElementById('back').addEventListener('click', function() {
  169. window.history.back(-1)
  170. })
  171. // 注册拍照按钮的单击事件-截图
  172. document.getElementById("capture").addEventListener("click", function() {
  173. // 获取ID为"myElement"的元素
  174. var element = document.getElementById("popup");
  175. // 获取该元素的样式属性
  176. var style = window.getComputedStyle(element);
  177. // 例如,获取元素的背景颜色
  178. var displayStyle = style.display;
  179. if(displayStyle!='none')
  180. {
  181. return ;
  182. }
  183. canvas.width = video.videoWidth;
  184. canvas.height = video.videoHeight;
  185. // context.strokeRect(60, 60, 100, 100);
  186. // context.beginPath();
  187. // context.arc(v_t_w / 2, v_t_w / 2, v_t_w / 2, 0, Math.PI * 2, true); // 绘制
  188. // context.closePath(); // 结束路径绘制
  189. // context.clip(); // 根据路径切割画布内容
  190. // context.setTransform(-1, 0, 0, 1, v_t_w, 0);
  191. // context.drawImage(video, 0, 0, v_t_w, v_t_h);
  192. if (isQian == true) {
  193. context.translate(canvas.width, 0);
  194. context.scale(-1, 1);
  195. }
  196. context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
  197. mediaStreamTrack && mediaStreamTrack.stop();
  198. var base64Img = canvas.toDataURL('image/jpeg');
  199. //var base64 = canvas.toDataURL('image/jpeg',0.5);// 图片质量0.5
  200. popupImg.src = base64Img;
  201. // console.log(base64Img);
  202. openPopup()
  203. });
  204. function takePhoto() {
  205. // 开始调用摄像头
  206. //like12 modified,20210628,bug,navigator.mediaDevices为空会导致后面卡死
  207. if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia ||
  208. navigator.getUserMedia ||
  209. navigator.webkitGetUserMedia ||
  210. navigator.mozGetUserMedia) {
  211. // 调用用户媒体设备,访问摄像头
  212. getUserMedia({
  213. video: {
  214. // width: v_t_w,
  215. // height: v_t_h,
  216. width: {
  217. ideal: idealw
  218. },
  219. height: {
  220. ideal: idealh
  221. },
  222. facingMode: mode //设置使用后置摄像头,user为前置摄像头
  223. },
  224. }, successFun, errorFun);
  225. } else {
  226. alert("你的浏览器不支持访问用户媒体设备");
  227. }
  228. }
  229. takePhoto();
  230. function changeMode() {
  231. console.log("翻转摄像头");
  232. if(!isZhuan){
  233. return
  234. }
  235. isZhuan=false;
  236. mode = mode === 'user' ? 'environment' : 'user';
  237. mediaStreamTrack.stop();
  238. isQian = false;
  239. document.querySelector("video").style.cssText =
  240. "width: 200px; height: 200px;-webkit-playsinline: true; playsinline: true;transform:rotateY(0deg);";
  241. if (mode.toLowerCase().includes("user")) {
  242. isQian = true;
  243. document.querySelector("video").style.cssText =
  244. "width: 200px; height: 200px;-webkit-playsinline: true; playsinline: true;transform:rotateY(180deg);";
  245. }
  246. takePhoto();
  247. }
  248. </script>
  249. </body>
  250. <style scoped>
  251. video {
  252. /* transform: rotateY(180deg); */
  253. /* display: none; */
  254. width: 200px;
  255. height: 200px;
  256. margin-top: 6vh;
  257. border-radius: 50%;
  258. /* transform: scaleX(-1);
  259. -o-transform: scaleX(-1);
  260. -webkit-transform: scaleX(-1); */
  261. filter: fliph;
  262. -ms-filter: fliph;
  263. }
  264. .face-mark {
  265. position: absolute;
  266. top: 5%;
  267. left: 50%;
  268. transform: translateX(-50%);
  269. width: 80%;
  270. }
  271. .box {
  272. margin: 6vh auto 12vh;
  273. display: flex;
  274. flex-direction: column;
  275. text-align: center;
  276. }
  277. .canvas {
  278. /* margin-top: 6vh;
  279. border-radius: 50%;
  280. transform: rotateY(180deg) */
  281. display: none;
  282. }
  283. .zhuyi {
  284. margin-top: 15px;
  285. display: flex;
  286. flex-direction: row;
  287. justify-content: space-around;
  288. }
  289. .line {
  290. border-bottom: 1px solid black;
  291. width: 20vw;
  292. }
  293. .imgBox {
  294. display: flex;
  295. flex-direction: row;
  296. justify-content: space-around;
  297. margin-top: 2vh;
  298. }
  299. .item {
  300. display: flex;
  301. flex-direction: column;
  302. }
  303. .span {
  304. text-align: center;
  305. }
  306. .buttonBox {
  307. display: flex;
  308. justify-content: space-around;
  309. margin-top: 10vh;
  310. }
  311. .buttonImg {
  312. width: 15vw;
  313. object-fit: contain;
  314. margin-bottom: 1vh;
  315. }
  316. .noneImg {
  317. display: none;
  318. }
  319. #popup {
  320. display: flex;
  321. justify-content: center;
  322. position: fixed;
  323. width: 100%;
  324. top: 30%;
  325. left: 50%;
  326. transform: translate(-50%, -50%);
  327. background: #fff;
  328. padding: 20px;
  329. border-radius: 5px;
  330. box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
  331. z-index: 9999;
  332. }
  333. #popup h2 {
  334. margin-top: 0;
  335. }
  336. #closeBtn {
  337. width: 30vw;
  338. height: 4vh;
  339. border-radius: 16px;
  340. }
  341. #okBtn {
  342. width: 30vw;
  343. height: 4vh;
  344. border-radius: 16px;
  345. }
  346. #popupImg {
  347. margin-left: 25vw;
  348. }
  349. .popupBox {
  350. margin-top: 2vh;
  351. width: 100%;
  352. display: flex;
  353. justify-content: space-around;
  354. }
  355. </style>
  356. </html>