碧桂园
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

265 行
9.3 KiB

  1. import {CrsClient} from "./crsClient";
  2. import {CryptoJS} from "./CryptoJS";
  3. const systemInfo = wx.getSystemInfoSync();
  4. const SELECT_TYPE = {
  5. NONE: 0,
  6. IMAGE: 1,
  7. VIDEO: 2,
  8. };
  9. Page({
  10. data: {
  11. showOverlay: true,
  12. showSelect: false,
  13. SELECT_TYPE: SELECT_TYPE,
  14. selectType: 0,
  15. //CRS配置
  16. config: {
  17. apiKey: 'a9abd99b2dfb3a5bee964cbb0bced0ae', // EasyAR开发中心 - API KEY - API Key
  18. apiSecret: '483e000a38265687c058efb7ab66cbc0917a3331b6dbf5482df46c76cb749529', // EasyAR开发中心 - API KEY - API Secret
  19. crsAppId: '8911f4b8f03725e300ca4130c01f27e9', // EasyAR开发中心 - 云服务 - 云识别管理 - 云识别库信息 - CRS AppId
  20. token: '',
  21. clientHost: 'http://bd9b3490fe845642e600cf53f0cd64b8.cn1.crs.easyar.com:8080', //服务器一般不变
  22. jpegQuality: 0.7, //JPEG压缩质量,建议不低于70%
  23. minInterval: 1000, //最短的两次CRS请求间隔
  24. },
  25. //识别到这个数组中的ID就触发内容
  26. targetIds: [
  27. "",
  28. "79014ee9-60c7-4a0c-81ed-0d5889a7ecc9"
  29. ],
  30. showLoading: false,
  31. showLoadingText: "",
  32. },
  33. /** @type {CameraFrameListener} 相机帧回调 */
  34. listener: undefined,
  35. /** @type {HTMLCanvasElement} canvas对象 */
  36. canvas: undefined,
  37. /** @type {boolean} 是否需要持续识别,在点击“识别体验”之后和识别成功之前为true */
  38. runningCrs: undefined,
  39. /** @type {boolean} 当前是否正在进行CRS请求 */
  40. busy: undefined,
  41. /** @type {CrsClient} 负责发起CRS请求的对象 */
  42. crsClient: undefined,
  43. /** @type {number} 最后一次CRS请求的事件,用于判断是否满足最短请求间隔 */
  44. last: undefined,
  45. onLoad: function () {
  46. },
  47. onReady: function () {
  48. if (systemInfo.platform === "devtools") { //开发工具不会触发initdone事件,于是在onReady手动触发
  49. this.onCameraInit();
  50. }
  51. // 获取token
  52. this.queryToken().then(msg => {
  53. console.log('token1')
  54. console.log(msg)
  55. this.data.config.token = msg;
  56. }).catch(err => {
  57. console.info(err);
  58. });
  59. },
  60. showLoading(text) {
  61. this.setData({
  62. showLoading: true,
  63. showLoadingText: text,
  64. });
  65. },
  66. hideLoading() {
  67. this.setData({
  68. showLoading: false,
  69. });
  70. },
  71. //图像识别部分:
  72. onShow: function () {
  73. if (this.listener) this.listener.start(); //页面隐藏时相机帧的监听会自动停止,但恢复展示时不会自动启动,这里手动启动
  74. this.scan()
  75. },
  76. scan: function () {
  77. this.runningCrs = true;
  78. this.setData({
  79. showOverlay: false,
  80. showContent: false,
  81. selectType: SELECT_TYPE.NONE,
  82. });
  83. this.showLoading("识别中");
  84. },
  85. onCameraInit: function () {
  86. //找到canvas对象
  87. const query = wx.createSelectorQuery();
  88. query.select('#capture')
  89. .fields({node: true})
  90. .exec((res) => {
  91. const canvas = res[0].node;
  92. //设置canvas内部尺寸为480*640,frame-size="medium"的设置下相机帧大多是480*640
  93. canvas.width = 480;
  94. canvas.height = 640;
  95. this.canvas = canvas;
  96. this.crsClient = new CrsClient(this.data.config, this.canvas);
  97. //开始监听相机帧
  98. let cameraContext = wx.createCameraContext();
  99. this.listener = cameraContext.onCameraFrame(frame => {
  100. if (!this.canvas) return;
  101. let canvas = this.canvas;
  102. //如果尺寸不匹配,就修改canvas尺寸以适应相机帧
  103. if (canvas.width !== frame.width || canvas.height !== frame.height) {
  104. canvas.width = frame.width;
  105. canvas.height = frame.height;
  106. }
  107. this.queryImage(frame);
  108. });
  109. this.listener.start();
  110. });
  111. },
  112. queryImage: function (frame) {
  113. if (!this.runningCrs || this.busy || !this.crsClient) return;
  114. //最短的两次CRS请求间隔
  115. let now = new Date().getTime();
  116. if (this.last && (now - this.last < this.data.config.minInterval)) return;
  117. this.last = now;
  118. this.busy = true; //如果正在进行CRS请求,就不允许再次请求
  119. this.crsClient.queryImage(frame).then(res => {
  120. if (!this.runningCrs) return; //避免在停止后仍然触发
  121. let result = res.result;
  122. if (!result) return;
  123. if (result.target) {
  124. console.log("识别成功");
  125. this.runningCrs = false;
  126. this.hideLoading();
  127. let base64 = result.target.meta
  128. let web = this.base64_decode(base64)
  129. // 解析跳转链接
  130. wx.navigateTo({
  131. url: '../out/index?web=' + web + '&index=2',
  132. })
  133. // todo: 解析meta中的信息,触发业务逻辑
  134. //如果待触发的id列表中存在识别到的这个id,就触发
  135. if (this.data.targetIds.find(targetId => targetId === result.target.meta)) {
  136. this.onResult(result.target.meta);
  137. }
  138. } else {
  139. console.log("识别失败");
  140. }
  141. this.busy = false;
  142. }).catch(e => {
  143. this.busy = false;
  144. }); //小程序iOS端不支持finally,所以在then和catch里分别设置busy = false
  145. },
  146. onResult: function (target) {
  147. console.log("触发内容!");
  148. console.log(target);
  149. if (target) {
  150. console.log("meta base64:", target);
  151. }
  152. this.setData({
  153. showOverlay: false,
  154. showContent: true,
  155. selectType: SELECT_TYPE.IMAGE,
  156. });
  157. },
  158. //界面:
  159. back: function () {
  160. this.runningCrs = false;
  161. this.setData({
  162. showOverlay: true,
  163. showContent: false,
  164. selectType: SELECT_TYPE.NONE,
  165. });
  166. this.hideLoading();
  167. },
  168. experience: function () {
  169. this.setData({
  170. showOverlay: false,
  171. showContent: true,
  172. selectType: SELECT_TYPE.IMAGE,
  173. });
  174. },
  175. download: function () {
  176. wx.saveImageToPhotosAlbum({
  177. filePath: "/images/namecard.jpg",
  178. success: res => {
  179. wx.showToast({title: "已保存到相册", icon: "none"});
  180. },
  181. fail: res => {
  182. wx.showToast({title: "保存失败", icon: "none"});
  183. },
  184. });
  185. },
  186. selectContent: function (e) {
  187. this.setData({
  188. selectType: e.currentTarget.dataset.contenttype,
  189. });
  190. },
  191. queryToken: function() { // 获取token
  192. return new Promise((resolve, reject) => {
  193. wx.request({
  194. url: 'https://cktest.2weisou.com/meta/ar/ar/getToken',
  195. method: 'get',
  196. data: {},
  197. header: {
  198. 'content-type': 'application/json'
  199. },
  200. success: res => resolve(res.data),
  201. fail: err => reject(err)
  202. });
  203. });
  204. },
  205. base64_decode(input) { // 解码,配合decodeURIComponent使用
  206. var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  207. var output = "";
  208. var chr1, chr2, chr3;
  209. var enc1, enc2, enc3, enc4;
  210. var i = 0;
  211. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  212. while (i < input.length) {
  213. enc1 = base64EncodeChars.indexOf(input.charAt(i++));
  214. enc2 = base64EncodeChars.indexOf(input.charAt(i++));
  215. enc3 = base64EncodeChars.indexOf(input.charAt(i++));
  216. enc4 = base64EncodeChars.indexOf(input.charAt(i++));
  217. chr1 = (enc1 << 2) | (enc2 >> 4);
  218. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  219. chr3 = ((enc3 & 3) << 6) | enc4;
  220. output = output + String.fromCharCode(chr1);
  221. if (enc3 != 64) {
  222. output = output + String.fromCharCode(chr2);
  223. }
  224. if (enc4 != 64) {
  225. output = output + String.fromCharCode(chr3);
  226. }
  227. }
  228. return this.utf8_decode(output);
  229. },
  230. utf8_decode(utftext) { // utf-8解码
  231. var string = '';
  232. let i = 0;
  233. let c = 0;
  234. let c1 = 0;
  235. let c2 = 0;
  236. while (i < utftext.length) {
  237. c = utftext.charCodeAt(i);
  238. if (c < 128) {
  239. string += String.fromCharCode(c);
  240. i++;
  241. } else if ((c > 191) && (c < 224)) {
  242. c1 = utftext.charCodeAt(i + 1);
  243. string += String.fromCharCode(((c & 31) << 6) | (c1 & 63));
  244. i += 2;
  245. } else {
  246. c1 = utftext.charCodeAt(i + 1);
  247. c2 = utftext.charCodeAt(i + 2);
  248. string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63));
  249. i += 3;
  250. }
  251. }
  252. return string;
  253. }
  254. });