├── LICENSE
├── README.md
├── app.js
├── app.json
├── app.wxss
├── assets
├── blazeface_v1
│ ├── group1-shard1of1.bin
│ └── model.json
├── facemesh_v1
│ ├── group1-shard1of1.bin
│ └── model.json
├── handdetector_v1
│ ├── group1-shard1of2.bin
│ ├── group1-shard2of2.bin
│ └── model.json
├── handskeleton_v1
│ ├── anchors.json
│ ├── group1-shard1of2.bin
│ ├── group1-shard2of2.bin
│ └── model.json
├── mobilenet_v2_050_224
│ ├── group1-shard1of2.bin
│ ├── group1-shard2of2.bin
│ └── model.json
└── sunglass.glb
├── miniprogram_npm
├── @tensorflow-models
│ ├── blazeface
│ │ └── index.js
│ ├── face-landmarks-detection
│ │ └── index.js
│ └── handpose
│ │ ├── index.js
│ │ └── index.js.map
├── @tensorflow
│ ├── tfjs-backend-cpu
│ │ └── index.js
│ ├── tfjs-backend-webgl
│ │ └── index.js
│ ├── tfjs-converter
│ │ └── index.js
│ └── tfjs-core
│ │ └── index.js
├── abab
│ └── index.js
├── balanced-match
│ └── index.js
├── base64-js
│ └── index.js
├── brace-expansion
│ └── index.js
├── concat-map
│ └── index.js
├── fetch-wechat
│ └── index.js
├── fs.realpath
│ └── index.js
├── glob
│ └── index.js
├── inflight
│ └── index.js
├── inherits
│ └── index.js
├── minimatch
│ └── index.js
├── node-fetch
│ └── index.js
├── once
│ └── index.js
├── path-is-absolute
│ └── index.js
├── rimraf
│ └── index.js
├── seedrandom
│ └── index.js
├── text-encoder
│ └── index.js
├── threejs-miniprogram
│ └── index.js
└── wrappy
│ └── index.js
├── package-lock.json
├── package.json
├── package_face_2d_mask
├── pages
│ ├── camera
│ │ ├── camera.js
│ │ ├── camera.json
│ │ ├── camera.wxml
│ │ └── camera.wxss
│ └── photo
│ │ ├── photo.js
│ │ ├── photo.json
│ │ ├── photo.wxml
│ │ └── photo.wxss
└── utils
│ ├── cat_beard.png
│ ├── faceBusiness.js
│ └── modelBusiness.js
├── package_face_3d_mask
├── pages
│ ├── camera
│ │ ├── camera.js
│ │ ├── camera.json
│ │ ├── camera.wxml
│ │ └── camera.wxss
│ └── photo
│ │ ├── photo.js
│ │ ├── photo.json
│ │ ├── photo.wxml
│ │ └── photo.wxss
└── utils
│ ├── GLTFLoader.js
│ ├── faceBusiness.js
│ └── modelBusiness.js
├── package_handpose_mask
├── pages
│ ├── camera
│ │ ├── camera.js
│ │ ├── camera.json
│ │ ├── camera.wxml
│ │ └── camera.wxss
│ └── photo
│ │ ├── photo.js
│ │ ├── photo.json
│ │ ├── photo.wxml
│ │ └── photo.wxss
└── utils
│ ├── cat_beard.png
│ ├── handBusiness.js
│ └── modelBusiness.js
├── package_mobilenet
├── pages
│ ├── camera
│ │ ├── camera.js
│ │ ├── camera.json
│ │ ├── camera.wxml
│ │ └── camera.wxss
│ └── photo
│ │ ├── photo.js
│ │ ├── photo.json
│ │ ├── photo.wxml
│ │ └── photo.wxss
└── utils
│ ├── imagenet_classes.js
│ └── mobilenet.js
├── pages
└── index
│ ├── index.js
│ ├── index.json
│ ├── index.wxml
│ └── index.wxss
├── plugin
├── config.js
├── file_storage.js
├── index.js
├── local_storage.js
├── model_artifacts.js
└── wechat_platform.js
├── project.config.json
├── screenshot
├── 1.jpg
├── 3-1.jpg
├── 3-2.jpg
├── 3-3.jpg
├── 4-1.jpg
├── 4-2.jpg
├── 4-3.jpg
├── 5.jpg
├── 6.jpg
└── 7.jpg
├── sitemap.json
└── style
└── weui.wxss
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 AR Fashion
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [Chinese README](https://zhuanlan.zhihu.com/p/81636351)
2 |
3 | ## Updated
4 |
5 | | Date | Update |
6 | | -- | -- |
7 | | 2022-01-05 | New: Added a image classify demo using tfjs. |
8 | | 2021-09-08 | New: Added a hand pose demo using tfjs. It is slow and about 500 ms per detection.|
9 | | 2021-03-13 | Bug Fixed: 1. The image of the face 2d mask is not displayed on android WeChat. 2. When enter the demo UI on the second time, the 3D model is not displayed.|
10 | | 2021-03-11 | New: A Face AR using "face-landmarks-detection" and "TensorFlow.js". Update: Replace "face-api.js" with "face-landmarks-detection", the codes of "face-api.js" are removed. |
11 | | 2019-09-07 | New: A Face detecting and recognition with "face-api.js". |
12 |
13 | ## Introduction on WeChat Mini-program AR
14 |
15 | TensorFlow.js is a JavaScript library for machine learning.
16 | There is a WeChat Mini-program plugin for TensorFlow.js.
17 |
18 | [tfjs-wechat](https://github.com/tensorflow/tfjs-wechat)
19 |
20 | We can create AR effects with TensorFlow.js. A "face-landmarks-detection" library is based on TensorFlow.js.
21 |
22 | The "face-landmarks-detection" library offers a face detection in the browser environment.
23 |
24 | [face-landmarks-detection](https://github.com/tensorflow/tfjs-models/tree/master/face-landmarks-detection)
25 |
26 | Why choose "face-landmarks-detection"?
27 |
28 | Because I didn't find a tiny model of TensorFlow.js for face detecting until I found the "face-landmarks-detection" library.
29 |
30 | This demo demonstrates a face AR.
31 |
32 | Index Page of the WeChat Mini-program
33 |
34 | 
35 |
36 | ## Face Detecting and 3D Mask
37 |
38 | Use the demo to scan a face. Expect a effect below.
39 |
40 | 
41 |
42 | A effect of translating and scaling.
43 |
44 | 
45 |
46 | A effect of rotating.
47 |
48 | 
49 |
50 | ## Face Detecting and 2D Mask
51 |
52 | Use the demo to scan a face. Expect a effect below.
53 |
54 | 
55 |
56 | A effect of translating and scaling.
57 |
58 | 
59 |
60 | A effect of rotating.
61 |
62 | 
63 |
64 | ## Hand Pose and 2D Mask
65 |
66 | Use the demo to scan a hand. Expect a effect below.
67 |
68 | 
69 |
70 | ## Image Classify
71 |
72 | Use the demo to scan a cup. Expect a effect below.
73 |
74 | 
75 |
76 | ## How to build
77 |
78 | The WeChat Mini-program includes some npm packages. We install and compile the npm packages.
79 |
80 | step 1: run "npm install"
81 |
82 | step 2: run "WeChat developer tool -- Tool Menu -- build npm", a folder "miniprogram_npm" will be created.
83 |
84 | The project has included a "miniprogram_npm" folder precompiled.
85 |
86 | File: /package.json
87 |
88 | ```javascript
89 | "dependencies": {
90 | "@tensorflow-models/face-landmarks-detection": "0.0.3",
91 | "@tensorflow-models/handpose": "0.0.6",
92 | "@tensorflow/tfjs-backend-webgl": "2.1.0",
93 | "@tensorflow/tfjs-converter": "2.1.0",
94 | "@tensorflow/tfjs-core": "2.1.0",
95 | "abab": "2.0.0",
96 | "base64-js": "1.3.1",
97 | "fetch-wechat": "0.0.3",
98 | "text-encoder": "0.0.4",
99 | "threejs-miniprogram": "0.0.2"
100 | }
101 | ```
102 |
103 | ## Set the url of the "TensorFlow.js" model
104 |
105 | You can search a keyword "BLAZEFACE_MODEL_URL" in the "blazeface" folder. The search result is modified.
106 |
107 | File: /miniprogram_npm/@tensorflow-models/blazeface
108 |
109 | ```javascript
110 | // modified
111 | var BLAZEFACE_MODEL_URL = 'https://m.sanyue.red/demo/tfjs/blazeface_v1';
112 | ```
113 |
114 | You can search a keyword "FACEMESH_GRAPHMODEL_PATH" in the "face-landmarks-detection" folder.
115 |
116 | File: /miniprogram_npm/@tensorflow-models/face-landmarks-detection
117 |
118 | ```javascript
119 | // modified
120 | var FACEMESH_GRAPHMODEL_PATH = 'https://m.sanyue.red/demo/tfjs/facemesh_v1';
121 | ```
122 |
123 | You can search keywords that are "HANDDETECT_MODEL_PATH" and "HANDPOSE_MODEL_PATH" in the "handpose" folder.
124 |
125 | File: /miniprogram_npm/@tensorflow-models/handpose
126 |
127 | ```javascript
128 | // modified
129 | HANDDETECT_MODEL_PATH = 'https://m.sanyue.red/demo/tfjs/handdetector_v1';
130 |
131 | // modified
132 | HANDPOSE_MODEL_PATH = 'https://m.sanyue.red/demo/tfjs/handskeleton_v1';
133 | ```
134 |
135 | You can search keywords that are "mobilenet_model_path" in the file "mobilenet.js".
136 |
137 | File: /package_mobilenet/utils/mobilenet.js
138 |
139 | ```javascript
140 | // mobilenet_model_path
141 | '2.00': {
142 | '0.50': {
143 | url: 'https://m.sanyue.red/demo/tfjs/mobilenet_v2_050_224',
144 | inputRange: [0, 1]
145 | },
146 | ```
147 |
148 | ## Set the url of the 3D model
149 |
150 | You may replace the default url of a gltf model for 3D mask.
151 |
152 | File: /package_face_3d_mask/pages/photo/photo.js and /package_face_3d_mask/pagescamera/camera.js
153 |
154 | ```javascript
155 | // a url of gltf model
156 | const modelUrl = 'https://m.sanyue.red/demo/gltf/sunglass.glb';;
157 | ```
158 |
159 | ## Set the url of the 2D sprite image
160 |
161 | You may replace the default url of a image for 2D mask.
162 |
163 | File: /package_face_2d_mask/pages/photo/photo.js and /package_face_2d_mask/pages/camera/camera.js
164 |
165 | ```javascript
166 | // a url of sprite image
167 | const modelUrl = '../../utils/cat_beard.png';
168 | ```
169 |
170 | ## How to put a 3D model or a image on an other position
171 |
172 | This is a map of the 486 keypoints of a face.
173 |
174 | [486 keypoints Map](https://github.com/tensorflow/tfjs-models/raw/master/face-landmarks-detection/mesh_map.jpg)
175 |
176 | For example, a number 168, number 122 and number 351 are the middle of the eyes.
177 |
178 | File: /package_face_3d_mask/utils/modelBusiness.js
179 |
180 | ```javascript
181 | // index of the track points of the face
182 | const trackPointA = 168;
183 | const trackPointB = 122;
184 | const trackPointC = 351;
185 | ```
186 | For example, a number 0, number 61 and number 291 are the mouth.
187 |
188 | File: /package_face_2d_mask/utils/modelBusiness.js
189 |
190 | ```javascript
191 | // index of the track points of the face
192 | const trackPointA = 0;
193 | const trackPointB = 61;
194 | const trackPointC = 291;
195 | ```
196 |
197 | ## Hand Pose Map
198 |
199 | The landmarks of the hand pose.
200 |
201 | 
202 |
203 | ```javascript
204 | // the "predictions" is an array of objects describing each detected hand.
205 | [
206 | {
207 | handInViewConfidence: 1,
208 | boundingBox: {
209 | topLeft: [162.91, -17.42],
210 | bottomRight: [548.56, 368.23],
211 | },
212 | landmarks: [
213 | [472.52, 298.59, 0.00],
214 | [412.80, 315.64, -6.18],
215 | // etc.
216 | ],
217 | annotations: {
218 | thumb: [
219 | [412.80, 315.64, -6.18]
220 | [350.02, 298.38, -7.14],
221 | // etc.
222 | ],
223 | // etc.
224 | }
225 | }
226 | ]
227 | ```
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright 2019 Google LLC. All Rights Reserved.
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | * =============================================================================
16 | */
17 |
18 | const fetchWechat = require('fetch-wechat');
19 | const tf = require('@tensorflow/tfjs-core');
20 | const webgl = require('@tensorflow/tfjs-backend-webgl');
21 | const plugin = require('./plugin/index.js');
22 | const ENABLE_DEBUG = true;
23 | //app.js
24 | App({
25 | globalData: {
26 | localStorageIO: plugin.localStorageIO,
27 | fileStorageIO: plugin.fileStorageIO,
28 | },
29 | onLaunch: async function () {
30 | /*
31 | 注意 由于最新版本的WeChat的OffscreenCanvas会随页面跳转而失效,
32 | 在app.js的 onLaunch 函数中设置 tfjs 会导致小程序退出或页面跳转之后操作出错。
33 | 建议在使用tfjs的page的onLoad中调用 configPlugin 函数。
34 | */
35 | plugin.configPlugin({
36 | fetchFunc: fetchWechat.fetchFunc(),
37 | tf,
38 | webgl,
39 | canvas: wx.createOffscreenCanvas()
40 | },
41 | ENABLE_DEBUG);
42 |
43 | /*
44 | 注意 使用WASM暂时只能导入 2.0.0的tfjs库。因为2.0.1 版本wasm有和WeChat兼容性问题。
45 | 中低端手机的GPU往往相对CPU要弱一些,而WASM backend是跑在CPU上的,这就为中低端手机提供了另一个加速平台。
46 | const info = wx.getSystemInfoSync();
47 | console.log(info.platform);
48 | if (info.platform == 'android') {
49 | setWasmPath(
50 | 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@2.0.0/wasm-out/tfjs-backend-wasm.wasm',
51 | true);
52 | await tf.setBackend('wasm');
53 | console.log('set wasm as backend');
54 | }
55 | */
56 | }
57 | })
58 |
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index"
4 | ],
5 | "subpackages": [
6 | {
7 | "root": "package_face_3d_mask",
8 | "pages": [
9 | "pages/camera/camera",
10 | "pages/photo/photo"
11 | ]
12 | },
13 | {
14 | "root": "package_face_2d_mask",
15 | "pages": [
16 | "pages/camera/camera",
17 | "pages/photo/photo"
18 | ]
19 | },
20 | {
21 | "root": "package_handpose_mask",
22 | "pages": [
23 | "pages/camera/camera",
24 | "pages/photo/photo"
25 | ]
26 | }
27 | ],
28 | "window": {
29 | "backgroundTextStyle": "light",
30 | "navigationBarBackgroundColor": "#fff",
31 | "navigationBarTitleText": "Miniprogram AI",
32 | "navigationBarTextStyle": "black"
33 | },
34 | "sitemapLocation": "sitemap.json"
35 | }
36 |
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | /**app.wxss**/
2 | @import "style/weui.wxss"
3 |
4 | page{
5 | background-color: #F8F8F8;
6 | font-size: 16px;
7 | font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
8 | }
9 | .page__hd {
10 | padding: 40px;
11 | }
12 | .page__bd {
13 | padding-bottom: 40px;
14 | }
15 | .page__bd_spacing {
16 | padding-left: 15px;
17 | padding-right: 15px;
18 | }
19 |
20 | .page__ft{
21 | padding-bottom: 10px;
22 | text-align: center;
23 | }
24 |
25 | .page__title {
26 | text-align: left;
27 | font-size: 20px;
28 | font-weight: 400;
29 | }
30 |
31 | .page__desc {
32 | margin-top: 5px;
33 | color: #888888;
34 | text-align: left;
35 | font-size: 14px;
36 | }
37 |
38 | .marginTop10{
39 | margin-top: 10px;
40 | }
--------------------------------------------------------------------------------
/assets/blazeface_v1/group1-shard1of1.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/blazeface_v1/group1-shard1of1.bin
--------------------------------------------------------------------------------
/assets/facemesh_v1/group1-shard1of1.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/facemesh_v1/group1-shard1of1.bin
--------------------------------------------------------------------------------
/assets/handdetector_v1/group1-shard1of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/handdetector_v1/group1-shard1of2.bin
--------------------------------------------------------------------------------
/assets/handdetector_v1/group1-shard2of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/handdetector_v1/group1-shard2of2.bin
--------------------------------------------------------------------------------
/assets/handskeleton_v1/group1-shard1of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/handskeleton_v1/group1-shard1of2.bin
--------------------------------------------------------------------------------
/assets/handskeleton_v1/group1-shard2of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/handskeleton_v1/group1-shard2of2.bin
--------------------------------------------------------------------------------
/assets/mobilenet_v2_050_224/group1-shard1of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/mobilenet_v2_050_224/group1-shard1of2.bin
--------------------------------------------------------------------------------
/assets/mobilenet_v2_050_224/group1-shard2of2.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/mobilenet_v2_050_224/group1-shard2of2.bin
--------------------------------------------------------------------------------
/assets/sunglass.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/assets/sunglass.glb
--------------------------------------------------------------------------------
/miniprogram_npm/abab/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415622, function(require, module, exports) {
8 |
9 |
10 | const atob = require("./lib/atob");
11 | const btoa = require("./lib/btoa");
12 |
13 | module.exports = {
14 | atob,
15 | btoa
16 | };
17 |
18 | }, function(modId) {var map = {"./lib/atob":1615362415623,"./lib/btoa":1615362415624}; return __REQUIRE__(map[modId], modId); })
19 | __DEFINE__(1615362415623, function(require, module, exports) {
20 |
21 |
22 | /**
23 | * Implementation of atob() according to the HTML and Infra specs, except that
24 | * instead of throwing INVALID_CHARACTER_ERR we return null.
25 | */
26 | function atob(data) {
27 | // Web IDL requires DOMStrings to just be converted using ECMAScript
28 | // ToString, which in our case amounts to using a template literal.
29 | data = `${data}`;
30 | // "Remove all ASCII whitespace from data."
31 | data = data.replace(/[ \t\n\f\r]/g, "");
32 | // "If data's length divides by 4 leaving no remainder, then: if data ends
33 | // with one or two U+003D (=) code points, then remove them from data."
34 | if (data.length % 4 === 0) {
35 | data = data.replace(/==?$/, "");
36 | }
37 | // "If data's length divides by 4 leaving a remainder of 1, then return
38 | // failure."
39 | //
40 | // "If data contains a code point that is not one of
41 | //
42 | // U+002B (+)
43 | // U+002F (/)
44 | // ASCII alphanumeric
45 | //
46 | // then return failure."
47 | if (data.length % 4 === 1 || /[^+/0-9A-Za-z]/.test(data)) {
48 | return null;
49 | }
50 | // "Let output be an empty byte sequence."
51 | let output = "";
52 | // "Let buffer be an empty buffer that can have bits appended to it."
53 | //
54 | // We append bits via left-shift and or. accumulatedBits is used to track
55 | // when we've gotten to 24 bits.
56 | let buffer = 0;
57 | let accumulatedBits = 0;
58 | // "Let position be a position variable for data, initially pointing at the
59 | // start of data."
60 | //
61 | // "While position does not point past the end of data:"
62 | for (let i = 0; i < data.length; i++) {
63 | // "Find the code point pointed to by position in the second column of
64 | // Table 1: The Base 64 Alphabet of RFC 4648. Let n be the number given in
65 | // the first cell of the same row.
66 | //
67 | // "Append to buffer the six bits corresponding to n, most significant bit
68 | // first."
69 | //
70 | // atobLookup() implements the table from RFC 4648.
71 | buffer <<= 6;
72 | buffer |= atobLookup(data[i]);
73 | accumulatedBits += 6;
74 | // "If buffer has accumulated 24 bits, interpret them as three 8-bit
75 | // big-endian numbers. Append three bytes with values equal to those
76 | // numbers to output, in the same order, and then empty buffer."
77 | if (accumulatedBits === 24) {
78 | output += String.fromCharCode((buffer & 0xff0000) >> 16);
79 | output += String.fromCharCode((buffer & 0xff00) >> 8);
80 | output += String.fromCharCode(buffer & 0xff);
81 | buffer = accumulatedBits = 0;
82 | }
83 | // "Advance position by 1."
84 | }
85 | // "If buffer is not empty, it contains either 12 or 18 bits. If it contains
86 | // 12 bits, then discard the last four and interpret the remaining eight as
87 | // an 8-bit big-endian number. If it contains 18 bits, then discard the last
88 | // two and interpret the remaining 16 as two 8-bit big-endian numbers. Append
89 | // the one or two bytes with values equal to those one or two numbers to
90 | // output, in the same order."
91 | if (accumulatedBits === 12) {
92 | buffer >>= 4;
93 | output += String.fromCharCode(buffer);
94 | } else if (accumulatedBits === 18) {
95 | buffer >>= 2;
96 | output += String.fromCharCode((buffer & 0xff00) >> 8);
97 | output += String.fromCharCode(buffer & 0xff);
98 | }
99 | // "Return output."
100 | return output;
101 | }
102 | /**
103 | * A lookup table for atob(), which converts an ASCII character to the
104 | * corresponding six-bit number.
105 | */
106 | function atobLookup(chr) {
107 | if (/[A-Z]/.test(chr)) {
108 | return chr.charCodeAt(0) - "A".charCodeAt(0);
109 | }
110 | if (/[a-z]/.test(chr)) {
111 | return chr.charCodeAt(0) - "a".charCodeAt(0) + 26;
112 | }
113 | if (/[0-9]/.test(chr)) {
114 | return chr.charCodeAt(0) - "0".charCodeAt(0) + 52;
115 | }
116 | if (chr === "+") {
117 | return 62;
118 | }
119 | if (chr === "/") {
120 | return 63;
121 | }
122 | // Throw exception; should not be hit in tests
123 | return undefined;
124 | }
125 |
126 | module.exports = atob;
127 |
128 | }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
129 | __DEFINE__(1615362415624, function(require, module, exports) {
130 |
131 |
132 | /**
133 | * btoa() as defined by the HTML and Infra specs, which mostly just references
134 | * RFC 4648.
135 | */
136 | function btoa(s) {
137 | let i;
138 | // String conversion as required by Web IDL.
139 | s = `${s}`;
140 | // "The btoa() method must throw an "InvalidCharacterError" DOMException if
141 | // data contains any character whose code point is greater than U+00FF."
142 | for (i = 0; i < s.length; i++) {
143 | if (s.charCodeAt(i) > 255) {
144 | return null;
145 | }
146 | }
147 | let out = "";
148 | for (i = 0; i < s.length; i += 3) {
149 | const groupsOfSix = [undefined, undefined, undefined, undefined];
150 | groupsOfSix[0] = s.charCodeAt(i) >> 2;
151 | groupsOfSix[1] = (s.charCodeAt(i) & 0x03) << 4;
152 | if (s.length > i + 1) {
153 | groupsOfSix[1] |= s.charCodeAt(i + 1) >> 4;
154 | groupsOfSix[2] = (s.charCodeAt(i + 1) & 0x0f) << 2;
155 | }
156 | if (s.length > i + 2) {
157 | groupsOfSix[2] |= s.charCodeAt(i + 2) >> 6;
158 | groupsOfSix[3] = s.charCodeAt(i + 2) & 0x3f;
159 | }
160 | for (let j = 0; j < groupsOfSix.length; j++) {
161 | if (typeof groupsOfSix[j] === "undefined") {
162 | out += "=";
163 | } else {
164 | out += btoaLookup(groupsOfSix[j]);
165 | }
166 | }
167 | }
168 | return out;
169 | }
170 |
171 | /**
172 | * Lookup table for btoa(), which converts a six-bit number into the
173 | * corresponding ASCII character.
174 | */
175 | function btoaLookup(idx) {
176 | if (idx < 26) {
177 | return String.fromCharCode(idx + "A".charCodeAt(0));
178 | }
179 | if (idx < 52) {
180 | return String.fromCharCode(idx - 26 + "a".charCodeAt(0));
181 | }
182 | if (idx < 62) {
183 | return String.fromCharCode(idx - 52 + "0".charCodeAt(0));
184 | }
185 | if (idx === 62) {
186 | return "+";
187 | }
188 | if (idx === 63) {
189 | return "/";
190 | }
191 | // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
192 | return undefined;
193 | }
194 |
195 | module.exports = btoa;
196 |
197 | }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
198 | return __REQUIRE__(1615362415622);
199 | })()
200 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/balanced-match/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415625, function(require, module, exports) {
8 |
9 | module.exports = balanced;
10 | function balanced(a, b, str) {
11 | if (a instanceof RegExp) a = maybeMatch(a, str);
12 | if (b instanceof RegExp) b = maybeMatch(b, str);
13 |
14 | var r = range(a, b, str);
15 |
16 | return r && {
17 | start: r[0],
18 | end: r[1],
19 | pre: str.slice(0, r[0]),
20 | body: str.slice(r[0] + a.length, r[1]),
21 | post: str.slice(r[1] + b.length)
22 | };
23 | }
24 |
25 | function maybeMatch(reg, str) {
26 | var m = str.match(reg);
27 | return m ? m[0] : null;
28 | }
29 |
30 | balanced.range = range;
31 | function range(a, b, str) {
32 | var begs, beg, left, right, result;
33 | var ai = str.indexOf(a);
34 | var bi = str.indexOf(b, ai + 1);
35 | var i = ai;
36 |
37 | if (ai >= 0 && bi > 0) {
38 | begs = [];
39 | left = str.length;
40 |
41 | while (i >= 0 && !result) {
42 | if (i == ai) {
43 | begs.push(i);
44 | ai = str.indexOf(a, i + 1);
45 | } else if (begs.length == 1) {
46 | result = [ begs.pop(), bi ];
47 | } else {
48 | beg = begs.pop();
49 | if (beg < left) {
50 | left = beg;
51 | right = bi;
52 | }
53 |
54 | bi = str.indexOf(b, i + 1);
55 | }
56 |
57 | i = ai < bi && ai >= 0 ? ai : bi;
58 | }
59 |
60 | if (begs.length) {
61 | result = [ left, right ];
62 | }
63 | }
64 |
65 | return result;
66 | }
67 |
68 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
69 | return __REQUIRE__(1615362415625);
70 | })()
71 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/base64-js/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415626, function(require, module, exports) {
8 |
9 |
10 | exports.byteLength = byteLength
11 | exports.toByteArray = toByteArray
12 | exports.fromByteArray = fromByteArray
13 |
14 | var lookup = []
15 | var revLookup = []
16 | var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
17 |
18 | var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
19 | for (var i = 0, len = code.length; i < len; ++i) {
20 | lookup[i] = code[i]
21 | revLookup[code.charCodeAt(i)] = i
22 | }
23 |
24 | // Support decoding URL-safe base64 strings, as Node.js does.
25 | // See: https://en.wikipedia.org/wiki/Base64#URL_applications
26 | revLookup['-'.charCodeAt(0)] = 62
27 | revLookup['_'.charCodeAt(0)] = 63
28 |
29 | function getLens (b64) {
30 | var len = b64.length
31 |
32 | if (len % 4 > 0) {
33 | throw new Error('Invalid string. Length must be a multiple of 4')
34 | }
35 |
36 | // Trim off extra bytes after placeholder bytes are found
37 | // See: https://github.com/beatgammit/base64-js/issues/42
38 | var validLen = b64.indexOf('=')
39 | if (validLen === -1) validLen = len
40 |
41 | var placeHoldersLen = validLen === len
42 | ? 0
43 | : 4 - (validLen % 4)
44 |
45 | return [validLen, placeHoldersLen]
46 | }
47 |
48 | // base64 is 4/3 + up to two characters of the original data
49 | function byteLength (b64) {
50 | var lens = getLens(b64)
51 | var validLen = lens[0]
52 | var placeHoldersLen = lens[1]
53 | return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
54 | }
55 |
56 | function _byteLength (b64, validLen, placeHoldersLen) {
57 | return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen
58 | }
59 |
60 | function toByteArray (b64) {
61 | var tmp
62 | var lens = getLens(b64)
63 | var validLen = lens[0]
64 | var placeHoldersLen = lens[1]
65 |
66 | var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen))
67 |
68 | var curByte = 0
69 |
70 | // if there are placeholders, only get up to the last complete 4 chars
71 | var len = placeHoldersLen > 0
72 | ? validLen - 4
73 | : validLen
74 |
75 | var i
76 | for (i = 0; i < len; i += 4) {
77 | tmp =
78 | (revLookup[b64.charCodeAt(i)] << 18) |
79 | (revLookup[b64.charCodeAt(i + 1)] << 12) |
80 | (revLookup[b64.charCodeAt(i + 2)] << 6) |
81 | revLookup[b64.charCodeAt(i + 3)]
82 | arr[curByte++] = (tmp >> 16) & 0xFF
83 | arr[curByte++] = (tmp >> 8) & 0xFF
84 | arr[curByte++] = tmp & 0xFF
85 | }
86 |
87 | if (placeHoldersLen === 2) {
88 | tmp =
89 | (revLookup[b64.charCodeAt(i)] << 2) |
90 | (revLookup[b64.charCodeAt(i + 1)] >> 4)
91 | arr[curByte++] = tmp & 0xFF
92 | }
93 |
94 | if (placeHoldersLen === 1) {
95 | tmp =
96 | (revLookup[b64.charCodeAt(i)] << 10) |
97 | (revLookup[b64.charCodeAt(i + 1)] << 4) |
98 | (revLookup[b64.charCodeAt(i + 2)] >> 2)
99 | arr[curByte++] = (tmp >> 8) & 0xFF
100 | arr[curByte++] = tmp & 0xFF
101 | }
102 |
103 | return arr
104 | }
105 |
106 | function tripletToBase64 (num) {
107 | return lookup[num >> 18 & 0x3F] +
108 | lookup[num >> 12 & 0x3F] +
109 | lookup[num >> 6 & 0x3F] +
110 | lookup[num & 0x3F]
111 | }
112 |
113 | function encodeChunk (uint8, start, end) {
114 | var tmp
115 | var output = []
116 | for (var i = start; i < end; i += 3) {
117 | tmp =
118 | ((uint8[i] << 16) & 0xFF0000) +
119 | ((uint8[i + 1] << 8) & 0xFF00) +
120 | (uint8[i + 2] & 0xFF)
121 | output.push(tripletToBase64(tmp))
122 | }
123 | return output.join('')
124 | }
125 |
126 | function fromByteArray (uint8) {
127 | var tmp
128 | var len = uint8.length
129 | var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
130 | var parts = []
131 | var maxChunkLength = 16383 // must be multiple of 3
132 |
133 | // go through the array every three bytes, we'll deal with trailing stuff later
134 | for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
135 | parts.push(encodeChunk(
136 | uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
137 | ))
138 | }
139 |
140 | // pad the end with zeros, but make sure to not forget the extra bytes
141 | if (extraBytes === 1) {
142 | tmp = uint8[len - 1]
143 | parts.push(
144 | lookup[tmp >> 2] +
145 | lookup[(tmp << 4) & 0x3F] +
146 | '=='
147 | )
148 | } else if (extraBytes === 2) {
149 | tmp = (uint8[len - 2] << 8) + uint8[len - 1]
150 | parts.push(
151 | lookup[tmp >> 10] +
152 | lookup[(tmp >> 4) & 0x3F] +
153 | lookup[(tmp << 2) & 0x3F] +
154 | '='
155 | )
156 | }
157 |
158 | return parts.join('')
159 | }
160 |
161 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
162 | return __REQUIRE__(1615362415626);
163 | })()
164 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/brace-expansion/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415627, function(require, module, exports) {
8 | var concatMap = require('concat-map');
9 | var balanced = require('balanced-match');
10 |
11 | module.exports = expandTop;
12 |
13 | var escSlash = '\0SLASH'+Math.random()+'\0';
14 | var escOpen = '\0OPEN'+Math.random()+'\0';
15 | var escClose = '\0CLOSE'+Math.random()+'\0';
16 | var escComma = '\0COMMA'+Math.random()+'\0';
17 | var escPeriod = '\0PERIOD'+Math.random()+'\0';
18 |
19 | function numeric(str) {
20 | return parseInt(str, 10) == str
21 | ? parseInt(str, 10)
22 | : str.charCodeAt(0);
23 | }
24 |
25 | function escapeBraces(str) {
26 | return str.split('\\\\').join(escSlash)
27 | .split('\\{').join(escOpen)
28 | .split('\\}').join(escClose)
29 | .split('\\,').join(escComma)
30 | .split('\\.').join(escPeriod);
31 | }
32 |
33 | function unescapeBraces(str) {
34 | return str.split(escSlash).join('\\')
35 | .split(escOpen).join('{')
36 | .split(escClose).join('}')
37 | .split(escComma).join(',')
38 | .split(escPeriod).join('.');
39 | }
40 |
41 |
42 | // Basically just str.split(","), but handling cases
43 | // where we have nested braced sections, which should be
44 | // treated as individual members, like {a,{b,c},d}
45 | function parseCommaParts(str) {
46 | if (!str)
47 | return [''];
48 |
49 | var parts = [];
50 | var m = balanced('{', '}', str);
51 |
52 | if (!m)
53 | return str.split(',');
54 |
55 | var pre = m.pre;
56 | var body = m.body;
57 | var post = m.post;
58 | var p = pre.split(',');
59 |
60 | p[p.length-1] += '{' + body + '}';
61 | var postParts = parseCommaParts(post);
62 | if (post.length) {
63 | p[p.length-1] += postParts.shift();
64 | p.push.apply(p, postParts);
65 | }
66 |
67 | parts.push.apply(parts, p);
68 |
69 | return parts;
70 | }
71 |
72 | function expandTop(str) {
73 | if (!str)
74 | return [];
75 |
76 | // I don't know why Bash 4.3 does this, but it does.
77 | // Anything starting with {} will have the first two bytes preserved
78 | // but *only* at the top level, so {},a}b will not expand to anything,
79 | // but a{},b}c will be expanded to [a}c,abc].
80 | // One could argue that this is a bug in Bash, but since the goal of
81 | // this module is to match Bash's rules, we escape a leading {}
82 | if (str.substr(0, 2) === '{}') {
83 | str = '\\{\\}' + str.substr(2);
84 | }
85 |
86 | return expand(escapeBraces(str), true).map(unescapeBraces);
87 | }
88 |
89 | function identity(e) {
90 | return e;
91 | }
92 |
93 | function embrace(str) {
94 | return '{' + str + '}';
95 | }
96 | function isPadded(el) {
97 | return /^-?0\d/.test(el);
98 | }
99 |
100 | function lte(i, y) {
101 | return i <= y;
102 | }
103 | function gte(i, y) {
104 | return i >= y;
105 | }
106 |
107 | function expand(str, isTop) {
108 | var expansions = [];
109 |
110 | var m = balanced('{', '}', str);
111 | if (!m || /\$$/.test(m.pre)) return [str];
112 |
113 | var isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
114 | var isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
115 | var isSequence = isNumericSequence || isAlphaSequence;
116 | var isOptions = m.body.indexOf(',') >= 0;
117 | if (!isSequence && !isOptions) {
118 | // {a},b}
119 | if (m.post.match(/,.*\}/)) {
120 | str = m.pre + '{' + m.body + escClose + m.post;
121 | return expand(str);
122 | }
123 | return [str];
124 | }
125 |
126 | var n;
127 | if (isSequence) {
128 | n = m.body.split(/\.\./);
129 | } else {
130 | n = parseCommaParts(m.body);
131 | if (n.length === 1) {
132 | // x{{a,b}}y ==> x{a}y x{b}y
133 | n = expand(n[0], false).map(embrace);
134 | if (n.length === 1) {
135 | var post = m.post.length
136 | ? expand(m.post, false)
137 | : [''];
138 | return post.map(function(p) {
139 | return m.pre + n[0] + p;
140 | });
141 | }
142 | }
143 | }
144 |
145 | // at this point, n is the parts, and we know it's not a comma set
146 | // with a single entry.
147 |
148 | // no need to expand pre, since it is guaranteed to be free of brace-sets
149 | var pre = m.pre;
150 | var post = m.post.length
151 | ? expand(m.post, false)
152 | : [''];
153 |
154 | var N;
155 |
156 | if (isSequence) {
157 | var x = numeric(n[0]);
158 | var y = numeric(n[1]);
159 | var width = Math.max(n[0].length, n[1].length)
160 | var incr = n.length == 3
161 | ? Math.abs(numeric(n[2]))
162 | : 1;
163 | var test = lte;
164 | var reverse = y < x;
165 | if (reverse) {
166 | incr *= -1;
167 | test = gte;
168 | }
169 | var pad = n.some(isPadded);
170 |
171 | N = [];
172 |
173 | for (var i = x; test(i, y); i += incr) {
174 | var c;
175 | if (isAlphaSequence) {
176 | c = String.fromCharCode(i);
177 | if (c === '\\')
178 | c = '';
179 | } else {
180 | c = String(i);
181 | if (pad) {
182 | var need = width - c.length;
183 | if (need > 0) {
184 | var z = new Array(need + 1).join('0');
185 | if (i < 0)
186 | c = '-' + z + c.slice(1);
187 | else
188 | c = z + c;
189 | }
190 | }
191 | }
192 | N.push(c);
193 | }
194 | } else {
195 | N = concatMap(n, function(el) { return expand(el, false) });
196 | }
197 |
198 | for (var j = 0; j < N.length; j++) {
199 | for (var k = 0; k < post.length; k++) {
200 | var expansion = pre + N[j] + post[k];
201 | if (!isTop || isSequence || expansion)
202 | expansions.push(expansion);
203 | }
204 | }
205 |
206 | return expansions;
207 | }
208 |
209 |
210 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
211 | return __REQUIRE__(1615362415627);
212 | })()
213 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/concat-map/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415628, function(require, module, exports) {
8 | module.exports = function (xs, fn) {
9 | var res = [];
10 | for (var i = 0; i < xs.length; i++) {
11 | var x = fn(xs[i], i);
12 | if (isArray(x)) res.push.apply(res, x);
13 | else res.push(x);
14 | }
15 | return res;
16 | };
17 |
18 | var isArray = Array.isArray || function (xs) {
19 | return Object.prototype.toString.call(xs) === '[object Array]';
20 | };
21 |
22 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
23 | return __REQUIRE__(1615362415628);
24 | })()
25 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/fetch-wechat/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415629, function(require, module, exports) {
8 |
9 | Object.defineProperty(exports, "__esModule", { value: true });
10 | exports.TEXT_FILE_EXTS = /\.(txt|json|html|txt|csv)/;
11 | function parseResponse(url, res) {
12 | var header = res.header || {};
13 | header = Object.keys(header).reduce(function (map, key) {
14 | map[key.toLowerCase()] = header[key];
15 | return map;
16 | }, {});
17 | return {
18 | ok: ((res.statusCode / 200) | 0) === 1,
19 | status: res.statusCode,
20 | statusText: res.statusCode,
21 | url: url,
22 | clone: function () { return parseResponse(url, res); },
23 | text: function () {
24 | return Promise.resolve(typeof res.data === 'string' ? res.data : JSON.stringify(res.data));
25 | },
26 | json: function () {
27 | if (typeof res.data === 'object')
28 | return Promise.resolve(res.data);
29 | var json = {};
30 | try {
31 | json = JSON.parse(res.data);
32 | }
33 | catch (err) {
34 | console.error(err);
35 | }
36 | return Promise.resolve(json);
37 | },
38 | arrayBuffer: function () {
39 | return Promise.resolve(res.data);
40 | },
41 | headers: {
42 | keys: function () { return Object.keys(header); },
43 | entries: function () {
44 | var all = [];
45 | for (var key in header) {
46 | if (header.hasOwnProperty(key)) {
47 | all.push([key, header[key]]);
48 | }
49 | }
50 | return all;
51 | },
52 | get: function (n) { return header[n.toLowerCase()]; },
53 | has: function (n) { return n.toLowerCase() in header; }
54 | }
55 | };
56 | }
57 | exports.parseResponse = parseResponse;
58 | function fetchFunc() {
59 | // tslint:disable-next-line:no-any
60 | return function (url, options) {
61 | options = options || {};
62 | var dataType = url.match(exports.TEXT_FILE_EXTS) ? 'text' : 'arraybuffer';
63 | return new Promise(function (resolve, reject) {
64 | wx.request({
65 | url: url,
66 | method: options.method || 'GET',
67 | data: options.body,
68 | header: options.headers,
69 | dataType: dataType,
70 | responseType: dataType,
71 | success: function (resp) { return resolve(parseResponse(url, resp)); },
72 | fail: function (err) { return reject(err); }
73 | });
74 | });
75 | };
76 | }
77 | exports.fetchFunc = fetchFunc;
78 | function setWechatFetch(debug) {
79 | if (debug === void 0) { debug = false; }
80 | // tslint:disable-next-line:no-any
81 | var typedGlobal = global;
82 | if (typeof typedGlobal.fetch !== 'function') {
83 | if (debug) {
84 | console.log('setup global fetch...');
85 | }
86 | typedGlobal.fetch = fetchFunc();
87 | }
88 | }
89 | exports.setWechatFetch = setWechatFetch;
90 | //# sourceMappingURL=index.js.map
91 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
92 | return __REQUIRE__(1615362415629);
93 | })()
94 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/fs.realpath/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415630, function(require, module, exports) {
8 | module.exports = realpath
9 | realpath.realpath = realpath
10 | realpath.sync = realpathSync
11 | realpath.realpathSync = realpathSync
12 | realpath.monkeypatch = monkeypatch
13 | realpath.unmonkeypatch = unmonkeypatch
14 |
15 | var fs = require('fs')
16 | var origRealpath = fs.realpath
17 | var origRealpathSync = fs.realpathSync
18 |
19 | var version = process.version
20 | var ok = /^v[0-5]\./.test(version)
21 | var old = require('./old.js')
22 |
23 | function newError (er) {
24 | return er && er.syscall === 'realpath' && (
25 | er.code === 'ELOOP' ||
26 | er.code === 'ENOMEM' ||
27 | er.code === 'ENAMETOOLONG'
28 | )
29 | }
30 |
31 | function realpath (p, cache, cb) {
32 | if (ok) {
33 | return origRealpath(p, cache, cb)
34 | }
35 |
36 | if (typeof cache === 'function') {
37 | cb = cache
38 | cache = null
39 | }
40 | origRealpath(p, cache, function (er, result) {
41 | if (newError(er)) {
42 | old.realpath(p, cache, cb)
43 | } else {
44 | cb(er, result)
45 | }
46 | })
47 | }
48 |
49 | function realpathSync (p, cache) {
50 | if (ok) {
51 | return origRealpathSync(p, cache)
52 | }
53 |
54 | try {
55 | return origRealpathSync(p, cache)
56 | } catch (er) {
57 | if (newError(er)) {
58 | return old.realpathSync(p, cache)
59 | } else {
60 | throw er
61 | }
62 | }
63 | }
64 |
65 | function monkeypatch () {
66 | fs.realpath = realpath
67 | fs.realpathSync = realpathSync
68 | }
69 |
70 | function unmonkeypatch () {
71 | fs.realpath = origRealpath
72 | fs.realpathSync = origRealpathSync
73 | }
74 |
75 | }, function(modId) {var map = {"./old.js":1615362415631}; return __REQUIRE__(map[modId], modId); })
76 | __DEFINE__(1615362415631, function(require, module, exports) {
77 | // Copyright Joyent, Inc. and other Node contributors.
78 | //
79 | // Permission is hereby granted, free of charge, to any person obtaining a
80 | // copy of this software and associated documentation files (the
81 | // "Software"), to deal in the Software without restriction, including
82 | // without limitation the rights to use, copy, modify, merge, publish,
83 | // distribute, sublicense, and/or sell copies of the Software, and to permit
84 | // persons to whom the Software is furnished to do so, subject to the
85 | // following conditions:
86 | //
87 | // The above copyright notice and this permission notice shall be included
88 | // in all copies or substantial portions of the Software.
89 | //
90 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
91 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
92 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
93 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
94 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
95 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
96 | // USE OR OTHER DEALINGS IN THE SOFTWARE.
97 |
98 | var pathModule = require('path');
99 | var isWindows = process.platform === 'win32';
100 | var fs = require('fs');
101 |
102 | // JavaScript implementation of realpath, ported from node pre-v6
103 |
104 | var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
105 |
106 | function rethrow() {
107 | // Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
108 | // is fairly slow to generate.
109 | var callback;
110 | if (DEBUG) {
111 | var backtrace = new Error;
112 | callback = debugCallback;
113 | } else
114 | callback = missingCallback;
115 |
116 | return callback;
117 |
118 | function debugCallback(err) {
119 | if (err) {
120 | backtrace.message = err.message;
121 | err = backtrace;
122 | missingCallback(err);
123 | }
124 | }
125 |
126 | function missingCallback(err) {
127 | if (err) {
128 | if (process.throwDeprecation)
129 | throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs
130 | else if (!process.noDeprecation) {
131 | var msg = 'fs: missing callback ' + (err.stack || err.message);
132 | if (process.traceDeprecation)
133 | console.trace(msg);
134 | else
135 | console.error(msg);
136 | }
137 | }
138 | }
139 | }
140 |
141 | function maybeCallback(cb) {
142 | return typeof cb === 'function' ? cb : rethrow();
143 | }
144 |
145 | var normalize = pathModule.normalize;
146 |
147 | // Regexp that finds the next partion of a (partial) path
148 | // result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
149 | if (isWindows) {
150 | var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
151 | } else {
152 | var nextPartRe = /(.*?)(?:[\/]+|$)/g;
153 | }
154 |
155 | // Regex to find the device root, including trailing slash. E.g. 'c:\\'.
156 | if (isWindows) {
157 | var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
158 | } else {
159 | var splitRootRe = /^[\/]*/;
160 | }
161 |
162 | exports.realpathSync = function realpathSync(p, cache) {
163 | // make p is absolute
164 | p = pathModule.resolve(p);
165 |
166 | if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
167 | return cache[p];
168 | }
169 |
170 | var original = p,
171 | seenLinks = {},
172 | knownHard = {};
173 |
174 | // current character position in p
175 | var pos;
176 | // the partial path so far, including a trailing slash if any
177 | var current;
178 | // the partial path without a trailing slash (except when pointing at a root)
179 | var base;
180 | // the partial path scanned in the previous round, with slash
181 | var previous;
182 |
183 | start();
184 |
185 | function start() {
186 | // Skip over roots
187 | var m = splitRootRe.exec(p);
188 | pos = m[0].length;
189 | current = m[0];
190 | base = m[0];
191 | previous = '';
192 |
193 | // On windows, check that the root exists. On unix there is no need.
194 | if (isWindows && !knownHard[base]) {
195 | fs.lstatSync(base);
196 | knownHard[base] = true;
197 | }
198 | }
199 |
200 | // walk down the path, swapping out linked pathparts for their real
201 | // values
202 | // NB: p.length changes.
203 | while (pos < p.length) {
204 | // find the next part
205 | nextPartRe.lastIndex = pos;
206 | var result = nextPartRe.exec(p);
207 | previous = current;
208 | current += result[0];
209 | base = previous + result[1];
210 | pos = nextPartRe.lastIndex;
211 |
212 | // continue if not a symlink
213 | if (knownHard[base] || (cache && cache[base] === base)) {
214 | continue;
215 | }
216 |
217 | var resolvedLink;
218 | if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
219 | // some known symbolic link. no need to stat again.
220 | resolvedLink = cache[base];
221 | } else {
222 | var stat = fs.lstatSync(base);
223 | if (!stat.isSymbolicLink()) {
224 | knownHard[base] = true;
225 | if (cache) cache[base] = base;
226 | continue;
227 | }
228 |
229 | // read the link if it wasn't read before
230 | // dev/ino always return 0 on windows, so skip the check.
231 | var linkTarget = null;
232 | if (!isWindows) {
233 | var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
234 | if (seenLinks.hasOwnProperty(id)) {
235 | linkTarget = seenLinks[id];
236 | }
237 | }
238 | if (linkTarget === null) {
239 | fs.statSync(base);
240 | linkTarget = fs.readlinkSync(base);
241 | }
242 | resolvedLink = pathModule.resolve(previous, linkTarget);
243 | // track this, if given a cache.
244 | if (cache) cache[base] = resolvedLink;
245 | if (!isWindows) seenLinks[id] = linkTarget;
246 | }
247 |
248 | // resolve the link, then start over
249 | p = pathModule.resolve(resolvedLink, p.slice(pos));
250 | start();
251 | }
252 |
253 | if (cache) cache[original] = p;
254 |
255 | return p;
256 | };
257 |
258 |
259 | exports.realpath = function realpath(p, cache, cb) {
260 | if (typeof cb !== 'function') {
261 | cb = maybeCallback(cache);
262 | cache = null;
263 | }
264 |
265 | // make p is absolute
266 | p = pathModule.resolve(p);
267 |
268 | if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
269 | return process.nextTick(cb.bind(null, null, cache[p]));
270 | }
271 |
272 | var original = p,
273 | seenLinks = {},
274 | knownHard = {};
275 |
276 | // current character position in p
277 | var pos;
278 | // the partial path so far, including a trailing slash if any
279 | var current;
280 | // the partial path without a trailing slash (except when pointing at a root)
281 | var base;
282 | // the partial path scanned in the previous round, with slash
283 | var previous;
284 |
285 | start();
286 |
287 | function start() {
288 | // Skip over roots
289 | var m = splitRootRe.exec(p);
290 | pos = m[0].length;
291 | current = m[0];
292 | base = m[0];
293 | previous = '';
294 |
295 | // On windows, check that the root exists. On unix there is no need.
296 | if (isWindows && !knownHard[base]) {
297 | fs.lstat(base, function(err) {
298 | if (err) return cb(err);
299 | knownHard[base] = true;
300 | LOOP();
301 | });
302 | } else {
303 | process.nextTick(LOOP);
304 | }
305 | }
306 |
307 | // walk down the path, swapping out linked pathparts for their real
308 | // values
309 | function LOOP() {
310 | // stop if scanned past end of path
311 | if (pos >= p.length) {
312 | if (cache) cache[original] = p;
313 | return cb(null, p);
314 | }
315 |
316 | // find the next part
317 | nextPartRe.lastIndex = pos;
318 | var result = nextPartRe.exec(p);
319 | previous = current;
320 | current += result[0];
321 | base = previous + result[1];
322 | pos = nextPartRe.lastIndex;
323 |
324 | // continue if not a symlink
325 | if (knownHard[base] || (cache && cache[base] === base)) {
326 | return process.nextTick(LOOP);
327 | }
328 |
329 | if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
330 | // known symbolic link. no need to stat again.
331 | return gotResolvedLink(cache[base]);
332 | }
333 |
334 | return fs.lstat(base, gotStat);
335 | }
336 |
337 | function gotStat(err, stat) {
338 | if (err) return cb(err);
339 |
340 | // if not a symlink, skip to the next path part
341 | if (!stat.isSymbolicLink()) {
342 | knownHard[base] = true;
343 | if (cache) cache[base] = base;
344 | return process.nextTick(LOOP);
345 | }
346 |
347 | // stat & read the link if not read before
348 | // call gotTarget as soon as the link target is known
349 | // dev/ino always return 0 on windows, so skip the check.
350 | if (!isWindows) {
351 | var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
352 | if (seenLinks.hasOwnProperty(id)) {
353 | return gotTarget(null, seenLinks[id], base);
354 | }
355 | }
356 | fs.stat(base, function(err) {
357 | if (err) return cb(err);
358 |
359 | fs.readlink(base, function(err, target) {
360 | if (!isWindows) seenLinks[id] = target;
361 | gotTarget(err, target);
362 | });
363 | });
364 | }
365 |
366 | function gotTarget(err, target, base) {
367 | if (err) return cb(err);
368 |
369 | var resolvedLink = pathModule.resolve(previous, target);
370 | if (cache) cache[base] = resolvedLink;
371 | gotResolvedLink(resolvedLink);
372 | }
373 |
374 | function gotResolvedLink(resolvedLink) {
375 | // resolve the link, then start over
376 | p = pathModule.resolve(resolvedLink, p.slice(pos));
377 | start();
378 | }
379 | };
380 |
381 | }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
382 | return __REQUIRE__(1615362415630);
383 | })()
384 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/inflight/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415635, function(require, module, exports) {
8 | var wrappy = require('wrappy')
9 | var reqs = Object.create(null)
10 | var once = require('once')
11 |
12 | module.exports = wrappy(inflight)
13 |
14 | function inflight (key, cb) {
15 | if (reqs[key]) {
16 | reqs[key].push(cb)
17 | return null
18 | } else {
19 | reqs[key] = [cb]
20 | return makeres(key)
21 | }
22 | }
23 |
24 | function makeres (key) {
25 | return once(function RES () {
26 | var cbs = reqs[key]
27 | var len = cbs.length
28 | var args = slice(arguments)
29 |
30 | // XXX It's somewhat ambiguous whether a new callback added in this
31 | // pass should be queued for later execution if something in the
32 | // list of callbacks throws, or if it should just be discarded.
33 | // However, it's such an edge case that it hardly matters, and either
34 | // choice is likely as surprising as the other.
35 | // As it happens, we do go ahead and schedule it for later execution.
36 | try {
37 | for (var i = 0; i < len; i++) {
38 | cbs[i].apply(null, args)
39 | }
40 | } finally {
41 | if (cbs.length > len) {
42 | // added more in the interim.
43 | // de-zalgo, just in case, but don't call again.
44 | cbs.splice(0, len)
45 | process.nextTick(function () {
46 | RES.apply(null, args)
47 | })
48 | } else {
49 | delete reqs[key]
50 | }
51 | }
52 | })
53 | }
54 |
55 | function slice (args) {
56 | var length = args.length
57 | var array = []
58 |
59 | for (var i = 0; i < length; i++) array[i] = args[i]
60 | return array
61 | }
62 |
63 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
64 | return __REQUIRE__(1615362415635);
65 | })()
66 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/inherits/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415636, function(require, module, exports) {
8 | try {
9 | var util = require('util');
10 | /* istanbul ignore next */
11 | if (typeof util.inherits !== 'function') throw '';
12 | module.exports = util.inherits;
13 | } catch (e) {
14 | /* istanbul ignore next */
15 | module.exports = require('./inherits_browser.js');
16 | }
17 |
18 | }, function(modId) {var map = {"./inherits_browser.js":1615362415637}; return __REQUIRE__(map[modId], modId); })
19 | __DEFINE__(1615362415637, function(require, module, exports) {
20 | if (typeof Object.create === 'function') {
21 | // implementation from standard node.js 'util' module
22 | module.exports = function inherits(ctor, superCtor) {
23 | if (superCtor) {
24 | ctor.super_ = superCtor
25 | ctor.prototype = Object.create(superCtor.prototype, {
26 | constructor: {
27 | value: ctor,
28 | enumerable: false,
29 | writable: true,
30 | configurable: true
31 | }
32 | })
33 | }
34 | };
35 | } else {
36 | // old school shim for old browsers
37 | module.exports = function inherits(ctor, superCtor) {
38 | if (superCtor) {
39 | ctor.super_ = superCtor
40 | var TempCtor = function () {}
41 | TempCtor.prototype = superCtor.prototype
42 | ctor.prototype = new TempCtor()
43 | ctor.prototype.constructor = ctor
44 | }
45 | }
46 | }
47 |
48 | }, function(modId) { var map = {}; return __REQUIRE__(map[modId], modId); })
49 | return __REQUIRE__(1615362415636);
50 | })()
51 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/once/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415640, function(require, module, exports) {
8 | var wrappy = require('wrappy')
9 | module.exports = wrappy(once)
10 | module.exports.strict = wrappy(onceStrict)
11 |
12 | once.proto = once(function () {
13 | Object.defineProperty(Function.prototype, 'once', {
14 | value: function () {
15 | return once(this)
16 | },
17 | configurable: true
18 | })
19 |
20 | Object.defineProperty(Function.prototype, 'onceStrict', {
21 | value: function () {
22 | return onceStrict(this)
23 | },
24 | configurable: true
25 | })
26 | })
27 |
28 | function once (fn) {
29 | var f = function () {
30 | if (f.called) return f.value
31 | f.called = true
32 | return f.value = fn.apply(this, arguments)
33 | }
34 | f.called = false
35 | return f
36 | }
37 |
38 | function onceStrict (fn) {
39 | var f = function () {
40 | if (f.called)
41 | throw new Error(f.onceError)
42 | f.called = true
43 | return f.value = fn.apply(this, arguments)
44 | }
45 | var name = fn.name || 'Function wrapped with `once`'
46 | f.onceError = name + " shouldn't be called more than once"
47 | f.called = false
48 | return f
49 | }
50 |
51 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
52 | return __REQUIRE__(1615362415640);
53 | })()
54 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/path-is-absolute/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415641, function(require, module, exports) {
8 |
9 |
10 | function posix(path) {
11 | return path.charAt(0) === '/';
12 | }
13 |
14 | function win32(path) {
15 | // https://github.com/nodejs/node/blob/b3fcc245fb25539909ef1d5eaa01dbf92e168633/lib/path.js#L56
16 | var splitDeviceRe = /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/;
17 | var result = splitDeviceRe.exec(path);
18 | var device = result[1] || '';
19 | var isUnc = Boolean(device && device.charAt(1) !== ':');
20 |
21 | // UNC paths are always absolute
22 | return Boolean(result[2] || isUnc);
23 | }
24 |
25 | module.exports = process.platform === 'win32' ? win32 : posix;
26 | module.exports.posix = posix;
27 | module.exports.win32 = win32;
28 |
29 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
30 | return __REQUIRE__(1615362415641);
31 | })()
32 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/rimraf/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415642, function(require, module, exports) {
8 | const assert = require("assert")
9 | const path = require("path")
10 | const fs = require("fs")
11 | let glob = undefined
12 | try {
13 | glob = require("glob")
14 | } catch (_err) {
15 | // treat glob as optional.
16 | }
17 |
18 | const defaultGlobOpts = {
19 | nosort: true,
20 | silent: true
21 | }
22 |
23 | // for EMFILE handling
24 | let timeout = 0
25 |
26 | const isWindows = (process.platform === "win32")
27 |
28 | const defaults = options => {
29 | const methods = [
30 | 'unlink',
31 | 'chmod',
32 | 'stat',
33 | 'lstat',
34 | 'rmdir',
35 | 'readdir'
36 | ]
37 | methods.forEach(m => {
38 | options[m] = options[m] || fs[m]
39 | m = m + 'Sync'
40 | options[m] = options[m] || fs[m]
41 | })
42 |
43 | options.maxBusyTries = options.maxBusyTries || 3
44 | options.emfileWait = options.emfileWait || 1000
45 | if (options.glob === false) {
46 | options.disableGlob = true
47 | }
48 | if (options.disableGlob !== true && glob === undefined) {
49 | throw Error('glob dependency not found, set `options.disableGlob = true` if intentional')
50 | }
51 | options.disableGlob = options.disableGlob || false
52 | options.glob = options.glob || defaultGlobOpts
53 | }
54 |
55 | const rimraf = (p, options, cb) => {
56 | if (typeof options === 'function') {
57 | cb = options
58 | options = {}
59 | }
60 |
61 | assert(p, 'rimraf: missing path')
62 | assert.equal(typeof p, 'string', 'rimraf: path should be a string')
63 | assert.equal(typeof cb, 'function', 'rimraf: callback function required')
64 | assert(options, 'rimraf: invalid options argument provided')
65 | assert.equal(typeof options, 'object', 'rimraf: options should be object')
66 |
67 | defaults(options)
68 |
69 | let busyTries = 0
70 | let errState = null
71 | let n = 0
72 |
73 | const next = (er) => {
74 | errState = errState || er
75 | if (--n === 0)
76 | cb(errState)
77 | }
78 |
79 | const afterGlob = (er, results) => {
80 | if (er)
81 | return cb(er)
82 |
83 | n = results.length
84 | if (n === 0)
85 | return cb()
86 |
87 | results.forEach(p => {
88 | const CB = (er) => {
89 | if (er) {
90 | if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
91 | busyTries < options.maxBusyTries) {
92 | busyTries ++
93 | // try again, with the same exact callback as this one.
94 | return setTimeout(() => rimraf_(p, options, CB), busyTries * 100)
95 | }
96 |
97 | // this one won't happen if graceful-fs is used.
98 | if (er.code === "EMFILE" && timeout < options.emfileWait) {
99 | return setTimeout(() => rimraf_(p, options, CB), timeout ++)
100 | }
101 |
102 | // already gone
103 | if (er.code === "ENOENT") er = null
104 | }
105 |
106 | timeout = 0
107 | next(er)
108 | }
109 | rimraf_(p, options, CB)
110 | })
111 | }
112 |
113 | if (options.disableGlob || !glob.hasMagic(p))
114 | return afterGlob(null, [p])
115 |
116 | options.lstat(p, (er, stat) => {
117 | if (!er)
118 | return afterGlob(null, [p])
119 |
120 | glob(p, options.glob, afterGlob)
121 | })
122 |
123 | }
124 |
125 | // Two possible strategies.
126 | // 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR
127 | // 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR
128 | //
129 | // Both result in an extra syscall when you guess wrong. However, there
130 | // are likely far more normal files in the world than directories. This
131 | // is based on the assumption that a the average number of files per
132 | // directory is >= 1.
133 | //
134 | // If anyone ever complains about this, then I guess the strategy could
135 | // be made configurable somehow. But until then, YAGNI.
136 | const rimraf_ = (p, options, cb) => {
137 | assert(p)
138 | assert(options)
139 | assert(typeof cb === 'function')
140 |
141 | // sunos lets the root user unlink directories, which is... weird.
142 | // so we have to lstat here and make sure it's not a dir.
143 | options.lstat(p, (er, st) => {
144 | if (er && er.code === "ENOENT")
145 | return cb(null)
146 |
147 | // Windows can EPERM on stat. Life is suffering.
148 | if (er && er.code === "EPERM" && isWindows)
149 | fixWinEPERM(p, options, er, cb)
150 |
151 | if (st && st.isDirectory())
152 | return rmdir(p, options, er, cb)
153 |
154 | options.unlink(p, er => {
155 | if (er) {
156 | if (er.code === "ENOENT")
157 | return cb(null)
158 | if (er.code === "EPERM")
159 | return (isWindows)
160 | ? fixWinEPERM(p, options, er, cb)
161 | : rmdir(p, options, er, cb)
162 | if (er.code === "EISDIR")
163 | return rmdir(p, options, er, cb)
164 | }
165 | return cb(er)
166 | })
167 | })
168 | }
169 |
170 | const fixWinEPERM = (p, options, er, cb) => {
171 | assert(p)
172 | assert(options)
173 | assert(typeof cb === 'function')
174 |
175 | options.chmod(p, 0o666, er2 => {
176 | if (er2)
177 | cb(er2.code === "ENOENT" ? null : er)
178 | else
179 | options.stat(p, (er3, stats) => {
180 | if (er3)
181 | cb(er3.code === "ENOENT" ? null : er)
182 | else if (stats.isDirectory())
183 | rmdir(p, options, er, cb)
184 | else
185 | options.unlink(p, cb)
186 | })
187 | })
188 | }
189 |
190 | const fixWinEPERMSync = (p, options, er) => {
191 | assert(p)
192 | assert(options)
193 |
194 | try {
195 | options.chmodSync(p, 0o666)
196 | } catch (er2) {
197 | if (er2.code === "ENOENT")
198 | return
199 | else
200 | throw er
201 | }
202 |
203 | let stats
204 | try {
205 | stats = options.statSync(p)
206 | } catch (er3) {
207 | if (er3.code === "ENOENT")
208 | return
209 | else
210 | throw er
211 | }
212 |
213 | if (stats.isDirectory())
214 | rmdirSync(p, options, er)
215 | else
216 | options.unlinkSync(p)
217 | }
218 |
219 | const rmdir = (p, options, originalEr, cb) => {
220 | assert(p)
221 | assert(options)
222 | assert(typeof cb === 'function')
223 |
224 | // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
225 | // if we guessed wrong, and it's not a directory, then
226 | // raise the original error.
227 | options.rmdir(p, er => {
228 | if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
229 | rmkids(p, options, cb)
230 | else if (er && er.code === "ENOTDIR")
231 | cb(originalEr)
232 | else
233 | cb(er)
234 | })
235 | }
236 |
237 | const rmkids = (p, options, cb) => {
238 | assert(p)
239 | assert(options)
240 | assert(typeof cb === 'function')
241 |
242 | options.readdir(p, (er, files) => {
243 | if (er)
244 | return cb(er)
245 | let n = files.length
246 | if (n === 0)
247 | return options.rmdir(p, cb)
248 | let errState
249 | files.forEach(f => {
250 | rimraf(path.join(p, f), options, er => {
251 | if (errState)
252 | return
253 | if (er)
254 | return cb(errState = er)
255 | if (--n === 0)
256 | options.rmdir(p, cb)
257 | })
258 | })
259 | })
260 | }
261 |
262 | // this looks simpler, and is strictly *faster*, but will
263 | // tie up the JavaScript thread and fail on excessively
264 | // deep directory trees.
265 | const rimrafSync = (p, options) => {
266 | options = options || {}
267 | defaults(options)
268 |
269 | assert(p, 'rimraf: missing path')
270 | assert.equal(typeof p, 'string', 'rimraf: path should be a string')
271 | assert(options, 'rimraf: missing options')
272 | assert.equal(typeof options, 'object', 'rimraf: options should be object')
273 |
274 | let results
275 |
276 | if (options.disableGlob || !glob.hasMagic(p)) {
277 | results = [p]
278 | } else {
279 | try {
280 | options.lstatSync(p)
281 | results = [p]
282 | } catch (er) {
283 | results = glob.sync(p, options.glob)
284 | }
285 | }
286 |
287 | if (!results.length)
288 | return
289 |
290 | for (let i = 0; i < results.length; i++) {
291 | const p = results[i]
292 |
293 | let st
294 | try {
295 | st = options.lstatSync(p)
296 | } catch (er) {
297 | if (er.code === "ENOENT")
298 | return
299 |
300 | // Windows can EPERM on stat. Life is suffering.
301 | if (er.code === "EPERM" && isWindows)
302 | fixWinEPERMSync(p, options, er)
303 | }
304 |
305 | try {
306 | // sunos lets the root user unlink directories, which is... weird.
307 | if (st && st.isDirectory())
308 | rmdirSync(p, options, null)
309 | else
310 | options.unlinkSync(p)
311 | } catch (er) {
312 | if (er.code === "ENOENT")
313 | return
314 | if (er.code === "EPERM")
315 | return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
316 | if (er.code !== "EISDIR")
317 | throw er
318 |
319 | rmdirSync(p, options, er)
320 | }
321 | }
322 | }
323 |
324 | const rmdirSync = (p, options, originalEr) => {
325 | assert(p)
326 | assert(options)
327 |
328 | try {
329 | options.rmdirSync(p)
330 | } catch (er) {
331 | if (er.code === "ENOENT")
332 | return
333 | if (er.code === "ENOTDIR")
334 | throw originalEr
335 | if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
336 | rmkidsSync(p, options)
337 | }
338 | }
339 |
340 | const rmkidsSync = (p, options) => {
341 | assert(p)
342 | assert(options)
343 | options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options))
344 |
345 | // We only end up here once we got ENOTEMPTY at least once, and
346 | // at this point, we are guaranteed to have removed all the kids.
347 | // So, we know that it won't be ENOENT or ENOTDIR or anything else.
348 | // try really hard to delete stuff on windows, because it has a
349 | // PROFOUNDLY annoying habit of not closing handles promptly when
350 | // files are deleted, resulting in spurious ENOTEMPTY errors.
351 | const retries = isWindows ? 100 : 1
352 | let i = 0
353 | do {
354 | let threw = true
355 | try {
356 | const ret = options.rmdirSync(p, options)
357 | threw = false
358 | return ret
359 | } finally {
360 | if (++i < retries && threw)
361 | continue
362 | }
363 | } while (true)
364 | }
365 |
366 | module.exports = rimraf
367 | rimraf.sync = rimrafSync
368 |
369 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
370 | return __REQUIRE__(1615362415642);
371 | })()
372 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/text-encoder/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415651, function(require, module, exports) {
8 | var utf8Encodings = [
9 | 'utf8',
10 | 'utf-8',
11 | 'unicode-1-1-utf-8'
12 | ];
13 |
14 | function TextEncoder(encoding) {
15 | if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
16 | throw new RangeError('Invalid encoding type. Only utf-8 is supported');
17 | } else {
18 | this.encoding = 'utf-8';
19 | this.encode = function(str) {
20 | if (typeof str !== 'string') {
21 | throw new TypeError('passed argument must be of tye string');
22 | }
23 | var binstr = unescape(encodeURIComponent(str)),
24 | arr = new Uint8Array(binstr.length);
25 | const split = binstr.split('');
26 | for (let i = 0; i < split.length; i++) {
27 | arr[i] = split[i].charCodeAt(0);
28 | }
29 | return arr;
30 | };
31 | }
32 | }
33 |
34 | function TextDecoder(encoding) {
35 | if (utf8Encodings.indexOf(encoding) < 0 && typeof encoding !== 'undefined' && encoding != null) {
36 | throw new RangeError('Invalid encoding type. Only utf-8 is supported');
37 | }
38 | else {
39 | this.encoding = 'utf-8';
40 | this.decode = function (view, options) {
41 | if (typeof view === 'undefined') {
42 | return '';
43 | }
44 |
45 | var stream = (typeof options !== 'undefined' && stream in options) ? options.stream : false;
46 | if (typeof stream !== 'boolean') {
47 | throw new TypeError('stream option must be boolean');
48 | }
49 |
50 | if (!ArrayBuffer.isView(view)) {
51 | throw new TypeError('passed argument must be an array buffer view');
52 | } else {
53 | var arr = new Uint8Array(view.buffer, view.byteOffset, view.byteLength),
54 | charArr = new Array(arr.length);
55 | for (let i = 0; i < arr.length; i++) {
56 | charArr[i] = String.fromCharCode(arr[i]);
57 | }
58 | return decodeURIComponent(escape(charArr.join('')));
59 | }
60 | }
61 | }
62 | }
63 |
64 | module.exports = {
65 | TextEncoder,
66 | TextDecoder,
67 | };
68 |
69 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
70 | return __REQUIRE__(1615362415651);
71 | })()
72 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/miniprogram_npm/wrappy/index.js:
--------------------------------------------------------------------------------
1 | module.exports = (function() {
2 | var __MODS__ = {};
3 | var __DEFINE__ = function(modId, func, req) { var m = { exports: {}, _tempexports: {} }; __MODS__[modId] = { status: 0, func: func, req: req, m: m }; };
4 | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; };
5 | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } };
6 | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; };
7 | __DEFINE__(1615362415652, function(require, module, exports) {
8 | // Returns a wrapper function that returns a wrapped callback
9 | // The wrapper function should do some stuff, and return a
10 | // presumably different callback function.
11 | // This makes sure that own properties are retained, so that
12 | // decorations and such are not lost along the way.
13 | module.exports = wrappy
14 | function wrappy (fn, cb) {
15 | if (fn && cb) return wrappy(fn)(cb)
16 |
17 | if (typeof fn !== 'function')
18 | throw new TypeError('need wrapper function')
19 |
20 | Object.keys(fn).forEach(function (k) {
21 | wrapper[k] = fn[k]
22 | })
23 |
24 | return wrapper
25 |
26 | function wrapper() {
27 | var args = new Array(arguments.length)
28 | for (var i = 0; i < args.length; i++) {
29 | args[i] = arguments[i]
30 | }
31 | var ret = fn.apply(this, args)
32 | var cb = args[args.length-1]
33 | if (typeof ret === 'function' && ret !== cb) {
34 | Object.keys(cb).forEach(function (k) {
35 | ret[k] = cb[k]
36 | })
37 | }
38 | return ret
39 | }
40 | }
41 |
42 | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); })
43 | return __REQUIRE__(1615362415652);
44 | })()
45 | //# sourceMappingURL=index.js.map
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "red-sanyue-wechat-ar-tfjs",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "@tensorflow-models/blazeface": {
8 | "version": "0.0.7",
9 | "resolved": "https://registry.npm.taobao.org/@tensorflow-models/blazeface/download/@tensorflow-models/blazeface-0.0.7.tgz",
10 | "integrity": "sha1-ChZJmgzJf8h+Ea4feBQHMcX2O/I="
11 | },
12 | "@tensorflow-models/face-landmarks-detection": {
13 | "version": "0.0.3",
14 | "resolved": "https://registry.npm.taobao.org/@tensorflow-models/face-landmarks-detection/download/@tensorflow-models/face-landmarks-detection-0.0.3.tgz",
15 | "integrity": "sha1-b987SaUHlqzwi36jUPjqWlpF7KE=",
16 | "requires": {
17 | "@tensorflow-models/blazeface": "0.0.7",
18 | "rimraf": "3.0.2"
19 | }
20 | },
21 | "@tensorflow-models/handpose": {
22 | "version": "0.0.6",
23 | "resolved": "https://registry.nlark.com/@tensorflow-models/handpose/download/@tensorflow-models/handpose-0.0.6.tgz",
24 | "integrity": "sha1-nLODzipyNQGoPQAShBRdmjBwP3c=",
25 | "requires": {
26 | "rimraf": "3.0.2"
27 | }
28 | },
29 | "@tensorflow/tfjs-backend-cpu": {
30 | "version": "2.1.0",
31 | "resolved": "https://registry.npm.taobao.org/@tensorflow/tfjs-backend-cpu/download/@tensorflow/tfjs-backend-cpu-2.1.0.tgz",
32 | "integrity": "sha1-Bnj/P9aM5L8dRJP0kD777ZteyxA=",
33 | "requires": {
34 | "@types/seedrandom": "2.4.27",
35 | "seedrandom": "2.4.3"
36 | }
37 | },
38 | "@tensorflow/tfjs-backend-webgl": {
39 | "version": "2.1.0",
40 | "resolved": "https://registry.npm.taobao.org/@tensorflow/tfjs-backend-webgl/download/@tensorflow/tfjs-backend-webgl-2.1.0.tgz",
41 | "integrity": "sha1-9v6wmx4Dmj7IgpVl61lemCkltzQ=",
42 | "requires": {
43 | "@tensorflow/tfjs-backend-cpu": "2.1.0",
44 | "@types/offscreencanvas": "2019.3.0",
45 | "@types/seedrandom": "2.4.27",
46 | "@types/webgl-ext": "0.0.30",
47 | "@types/webgl2": "0.0.4",
48 | "seedrandom": "2.4.3"
49 | }
50 | },
51 | "@tensorflow/tfjs-converter": {
52 | "version": "2.1.0",
53 | "resolved": "https://registry.npm.taobao.org/@tensorflow/tfjs-converter/download/@tensorflow/tfjs-converter-2.1.0.tgz",
54 | "integrity": "sha1-PdIm8RyrQSzr8LP40rf2m7/umU8="
55 | },
56 | "@tensorflow/tfjs-core": {
57 | "version": "2.1.0",
58 | "resolved": "https://registry.npm.taobao.org/@tensorflow/tfjs-core/download/@tensorflow/tfjs-core-2.1.0.tgz",
59 | "integrity": "sha1-dGvj21bHlDuoSAxw91cIStScetE=",
60 | "requires": {
61 | "@types/offscreencanvas": "2019.3.0",
62 | "@types/seedrandom": "2.4.27",
63 | "@types/webgl-ext": "0.0.30",
64 | "@types/webgl2": "0.0.4",
65 | "node-fetch": "2.1.2",
66 | "seedrandom": "2.4.3"
67 | }
68 | },
69 | "@types/offscreencanvas": {
70 | "version": "2019.3.0",
71 | "resolved": "https://registry.npm.taobao.org/@types/offscreencanvas/download/@types/offscreencanvas-2019.3.0.tgz",
72 | "integrity": "sha1-MzZCjsfpGAz0Vm3+pdoE61hqZVM="
73 | },
74 | "@types/seedrandom": {
75 | "version": "2.4.27",
76 | "resolved": "https://registry.npm.taobao.org/@types/seedrandom/download/@types/seedrandom-2.4.27.tgz",
77 | "integrity": "sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE="
78 | },
79 | "@types/webgl-ext": {
80 | "version": "0.0.30",
81 | "resolved": "https://registry.npm.taobao.org/@types/webgl-ext/download/@types/webgl-ext-0.0.30.tgz",
82 | "integrity": "sha1-DOSYwWpBoj0VKJ4LhE2UWyXw+50="
83 | },
84 | "@types/webgl2": {
85 | "version": "0.0.4",
86 | "resolved": "https://registry.npm.taobao.org/@types/webgl2/download/@types/webgl2-0.0.4.tgz",
87 | "integrity": "sha1-w7D51rRlxmE46E5kyzvfg3PCwnk="
88 | },
89 | "abab": {
90 | "version": "2.0.0",
91 | "resolved": "https://registry.npm.taobao.org/abab/download/abab-2.0.0.tgz",
92 | "integrity": "sha1-q6CrTF7uLUx500h9hUUPsjduuw8="
93 | },
94 | "balanced-match": {
95 | "version": "1.0.0",
96 | "resolved": "https://registry.npm.taobao.org/balanced-match/download/balanced-match-1.0.0.tgz",
97 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
98 | },
99 | "base64-js": {
100 | "version": "1.3.1",
101 | "resolved": "https://registry.npm.taobao.org/base64-js/download/base64-js-1.3.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbase64-js%2Fdownload%2Fbase64-js-1.3.1.tgz",
102 | "integrity": "sha1-WOzoy3XdB+ce0IxzarxfrE2/jfE="
103 | },
104 | "brace-expansion": {
105 | "version": "1.1.11",
106 | "resolved": "https://registry.npm.taobao.org/brace-expansion/download/brace-expansion-1.1.11.tgz",
107 | "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=",
108 | "requires": {
109 | "balanced-match": "1.0.0",
110 | "concat-map": "0.0.1"
111 | }
112 | },
113 | "concat-map": {
114 | "version": "0.0.1",
115 | "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
116 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
117 | },
118 | "fetch-wechat": {
119 | "version": "0.0.3",
120 | "resolved": "https://registry.npm.taobao.org/fetch-wechat/download/fetch-wechat-0.0.3.tgz",
121 | "integrity": "sha1-J4nDMqJL+fQRS1gMAtKTRkbnTxI="
122 | },
123 | "fs.realpath": {
124 | "version": "1.0.0",
125 | "resolved": "https://registry.npm.taobao.org/fs.realpath/download/fs.realpath-1.0.0.tgz",
126 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
127 | },
128 | "glob": {
129 | "version": "7.1.6",
130 | "resolved": "https://registry.npm.taobao.org/glob/download/glob-7.1.6.tgz",
131 | "integrity": "sha1-FB8zuBp8JJLhJVlDB0gMRmeSeKY=",
132 | "requires": {
133 | "fs.realpath": "1.0.0",
134 | "inflight": "1.0.6",
135 | "inherits": "2.0.4",
136 | "minimatch": "3.0.4",
137 | "once": "1.4.0",
138 | "path-is-absolute": "1.0.1"
139 | }
140 | },
141 | "inflight": {
142 | "version": "1.0.6",
143 | "resolved": "https://registry.npm.taobao.org/inflight/download/inflight-1.0.6.tgz",
144 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
145 | "requires": {
146 | "once": "1.4.0",
147 | "wrappy": "1.0.2"
148 | }
149 | },
150 | "inherits": {
151 | "version": "2.0.4",
152 | "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.4.tgz",
153 | "integrity": "sha1-D6LGT5MpF8NDOg3tVTY6rjdBa3w="
154 | },
155 | "minimatch": {
156 | "version": "3.0.4",
157 | "resolved": "https://registry.npm.taobao.org/minimatch/download/minimatch-3.0.4.tgz",
158 | "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=",
159 | "requires": {
160 | "brace-expansion": "1.1.11"
161 | }
162 | },
163 | "node-fetch": {
164 | "version": "2.1.2",
165 | "resolved": "https://registry.npm.taobao.org/node-fetch/download/node-fetch-2.1.2.tgz?cache=0&sync_timestamp=1599309667528&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-fetch%2Fdownload%2Fnode-fetch-2.1.2.tgz",
166 | "integrity": "sha1-q4hOjn5X44qUR1POxwb3iNF2i7U="
167 | },
168 | "once": {
169 | "version": "1.4.0",
170 | "resolved": "https://registry.npm.taobao.org/once/download/once-1.4.0.tgz",
171 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
172 | "requires": {
173 | "wrappy": "1.0.2"
174 | }
175 | },
176 | "path-is-absolute": {
177 | "version": "1.0.1",
178 | "resolved": "https://registry.npm.taobao.org/path-is-absolute/download/path-is-absolute-1.0.1.tgz",
179 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
180 | },
181 | "rimraf": {
182 | "version": "3.0.2",
183 | "resolved": "https://registry.npm.taobao.org/rimraf/download/rimraf-3.0.2.tgz",
184 | "integrity": "sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho=",
185 | "requires": {
186 | "glob": "7.1.6"
187 | }
188 | },
189 | "seedrandom": {
190 | "version": "2.4.3",
191 | "resolved": "https://registry.npm.taobao.org/seedrandom/download/seedrandom-2.4.3.tgz",
192 | "integrity": "sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw="
193 | },
194 | "text-encoder": {
195 | "version": "0.0.4",
196 | "resolved": "https://registry.npm.taobao.org/text-encoder/download/text-encoder-0.0.4.tgz",
197 | "integrity": "sha1-++5Mb7JR3QLi9A+Zg93WjFwWbiw="
198 | },
199 | "threejs-miniprogram": {
200 | "version": "0.0.2",
201 | "resolved": "https://registry.npm.taobao.org/threejs-miniprogram/download/threejs-miniprogram-0.0.2.tgz",
202 | "integrity": "sha1-XKYB6hXNiuuazLYe5GeS7tq8uTM="
203 | },
204 | "wrappy": {
205 | "version": "1.0.2",
206 | "resolved": "https://registry.npm.taobao.org/wrappy/download/wrappy-1.0.2.tgz",
207 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "red-sanyue-wechat-ar-tfjs",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "Apache-2.0",
12 | "dependencies": {
13 | "@tensorflow-models/face-landmarks-detection": "0.0.3",
14 | "@tensorflow-models/handpose": "0.0.6",
15 | "@tensorflow/tfjs-backend-webgl": "2.1.0",
16 | "@tensorflow/tfjs-converter": "2.1.0",
17 | "@tensorflow/tfjs-core": "2.1.0",
18 | "abab": "2.0.0",
19 | "base64-js": "1.3.1",
20 | "fetch-wechat": "0.0.3",
21 | "text-encoder": "0.0.4",
22 | "threejs-miniprogram": "0.0.2"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/camera/camera.js:
--------------------------------------------------------------------------------
1 | const face = require('../../utils/faceBusiness.js')
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasWebGLId = 'canvasWebGL';
4 | // throttling
5 | const cameraFrameMax = 3;
6 | // a url of gltf model
7 | const modelUrl = '../../utils/cat_beard.png';
8 | // camera listener
9 | var listener = null;
10 |
11 | Page({
12 | data: {
13 | devicePosition: 'front',
14 | },
15 | async onReady() {
16 | var _that = this;
17 | wx.showLoading({
18 | title: 'Loading TFJS...',
19 | });
20 | await face.loadModel();
21 | wx.hideLoading();
22 | // load 3d model
23 | model.initThree(canvasWebGLId, modelUrl);
24 | _that.startTacking();
25 | },
26 | onUnload: function () {
27 | this.stopTacking();
28 | console.log('onUnload', 'listener is stop');
29 |
30 | model.stopAnimate();
31 | model.dispose();
32 | },
33 | startTacking() {
34 | var _that = this;
35 | var count = 0;
36 | const context = wx.createCameraContext();
37 |
38 | // real-time
39 | listener = context.onCameraFrame(async function (res) {
40 | // it is throttling
41 | if (count < cameraFrameMax) {
42 | count++;
43 | return;
44 | }
45 | count = 0;
46 | console.log('onCameraFrame:', res.width, res.height);
47 | const frame = {
48 | data: new Uint8Array(res.data),
49 | width: res.width,
50 | height: res.height,
51 | };
52 |
53 | // process
54 | var result = await face.detect(frame);
55 |
56 | if (result && result.prediction) {
57 | var canvasWidth = frame.width;
58 | var canvasHeight = frame.height;
59 |
60 | // set the rotation and position of the 3d model.
61 | model.setModel(result.prediction,
62 | canvasWidth,
63 | canvasHeight);
64 | } else {
65 | var message = 'No results.';
66 | wx.showToast({
67 | title: message,
68 | icon: 'none'
69 | });
70 | }
71 | });
72 | // start
73 | listener.start();
74 | console.log('startTacking', 'listener is start');
75 | },
76 | stopTacking() {
77 | if (listener) {
78 | listener.stop();
79 | }
80 | },
81 | changeDirection() {
82 | var status = this.data.devicePosition;
83 | if (status === 'back') {
84 | status = 'front';
85 | } else {
86 | status = 'back';
87 | }
88 | this.setData({
89 | devicePosition: status,
90 | });
91 | }
92 | })
93 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/camera/camera.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Access a camera"
3 | }
4 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/camera/camera.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/camera/camera.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 | camera{
8 | width: 375px;
9 | height: 500px;
10 | z-index: 1;
11 | margin:auto;
12 | }
13 |
14 | .canvasWebGL{
15 | width: 100%;
16 | height: 100%;
17 | z-index: 3;
18 | margin:auto;
19 | }
20 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/photo/photo.js:
--------------------------------------------------------------------------------
1 | const face = require('../../utils/faceBusiness.js');
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasId = 'canvas2d';
4 | const canvasWebGLId = 'canvasWebGL';
5 | const maxCanvasWidth = 375;
6 | // a url of sprite image
7 | const modelUrl = '../../utils/cat_beard.png';
8 |
9 | Page({
10 | data: {
11 | btnText: 'Take a photo',
12 | devicePosition: 'front',
13 | // if it is taking photo
14 | isRunning: true,
15 | },
16 | async onReady() {
17 | // load tfjs model
18 | wx.showLoading({
19 | title: 'Loading TFJS...',
20 | });
21 | await face.loadModel();
22 | wx.hideLoading();
23 |
24 | // load 3d model
25 | model.initThree(canvasWebGLId, modelUrl);
26 | },
27 | onUnload: function () {
28 | model.stopAnimate();
29 | model.dispose();
30 | },
31 | processPhoto(photoPath, imageWidth, imageHeight) {
32 | var _that = this;
33 | const ctx = wx.createCanvasContext(canvasId);
34 | // the width of the scale image
35 | var canvasWidth = imageWidth;
36 | if (canvasWidth > maxCanvasWidth) {
37 | canvasWidth = maxCanvasWidth;
38 | }
39 | // the height of the scale image
40 | var canvasHeight = Math.floor(canvasWidth * (imageHeight / imageWidth));
41 | // draw image on canvas
42 | ctx.drawImage(photoPath, 0, 0, canvasWidth, canvasHeight);
43 | // waiting for drawing
44 | ctx.draw(false, function () {
45 | // get image data from canvas
46 | wx.canvasGetImageData({
47 | canvasId: canvasId,
48 | x: 0,
49 | y: 0,
50 | width: canvasWidth,
51 | height: canvasHeight,
52 | async success(res) {
53 | console.log('size of frame:', res.width, res.height);
54 | const frame = {
55 | data: new Uint8Array(res.data),
56 | width: res.width,
57 | height: res.height,
58 | };
59 | // process
60 | var result = await face.detect(frame);
61 |
62 | if (result && result.prediction) {
63 | // set the rotation and position of the 3d model.
64 | model.setModel(result.prediction,
65 | canvasWidth,
66 | canvasHeight);
67 | // put the 3d model on the image
68 | model.setSceneBackground(frame);
69 | } else {
70 | var message = 'No results.';
71 | wx.showToast({
72 | title: message,
73 | icon: 'none'
74 | });
75 | }
76 |
77 |
78 | }
79 | });
80 | });
81 | },
82 | takePhoto() {
83 | var _that = this;
84 | const context = wx.createCameraContext();
85 | const ctx = wx.createCanvasContext(canvasId);
86 | if (_that.data.isRunning) {
87 | _that.setData({
88 | btnText: 'Retry',
89 | isRunning: false,
90 | });
91 | // take a photo
92 | context.takePhoto({
93 | quality: 'normal',
94 | success: (res) => {
95 | var photoPath = res.tempImagePath;
96 | //get size of image
97 | wx.getImageInfo({
98 | src: photoPath,
99 | success(res) {
100 | console.log('size of image:', res.width, res.height);
101 | _that.processPhoto(photoPath, res.width, res.height);
102 | }
103 | });
104 | }
105 | });
106 | }
107 | else {
108 | _that.setData({
109 | btnText: 'Take a photo',
110 | isRunning: true,
111 | });
112 | // clear 2d canvas
113 | ctx.clearRect(0, 0);
114 | ctx.draw();
115 | // clear 3d canvas
116 | model.clearSceneBackground();
117 | }
118 | },
119 | changeDirection() {
120 | var status = this.data.devicePosition;
121 | if (status === 'back') {
122 | status = 'front';
123 | } else {
124 | status = 'back';
125 | }
126 | this.setData({
127 | devicePosition: status,
128 | });
129 | }
130 | });
131 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/photo/photo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Take a photo"
3 | }
4 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/photo/photo.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/package_face_2d_mask/pages/photo/photo.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 |
8 | camera{
9 | width: 375px;
10 | height: 500px;
11 | z-index: 1;
12 | margin:auto;
13 | }
14 |
15 | .canvasWebGL{
16 | width: 375px;
17 | height: 500px;
18 | z-index: 3;
19 | margin:auto;
20 | }
21 |
22 | .canvas1{
23 | width: 375px;
24 | height: 500px;
25 | z-index: 2;
26 | margin:auto;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/package_face_2d_mask/utils/cat_beard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/package_face_2d_mask/utils/cat_beard.png
--------------------------------------------------------------------------------
/package_face_2d_mask/utils/faceBusiness.js:
--------------------------------------------------------------------------------
1 | const faceLandmarksDetection = require('@tensorflow-models/face-landmarks-detection');
2 | require('@tensorflow/tfjs-backend-webgl');
3 | const detectionConfidence = 0.8;
4 | const maxFaces = 1;
5 | var model;
6 |
7 | async function loadModel() {
8 | model = await faceLandmarksDetection.load(
9 | faceLandmarksDetection.SupportedPackages.mediapipeFacemesh, {
10 | shouldLoadIrisModel: false,
11 | detectionConfidence: detectionConfidence,
12 | maxFaces: maxFaces,
13 | });
14 | console.log('facemesh model is loaded.');
15 | }
16 |
17 | async function detect(frame) {
18 | if (!model) {
19 | console.log('facemesh model has not been loaded.');
20 | return;
21 | }
22 | var start = new Date();
23 | const predictions = await model.estimateFaces({
24 | input: frame,
25 | predictIrises: false,
26 | });
27 | var end = new Date() - start;
28 | console.log('detect', end, 'ms');
29 |
30 | return { prediction: predictions[0] };
31 | }
32 |
33 | module.exports = { loadModel, detect };
34 |
--------------------------------------------------------------------------------
/package_face_2d_mask/utils/modelBusiness.js:
--------------------------------------------------------------------------------
1 | const { createScopedThreejs } = require('threejs-miniprogram');
2 | // the scale of the image
3 | const initScale = 240;
4 | // index of the track points of the face
5 | const trackPointA = 0;
6 | const trackPointB = 61;
7 | const trackPointC = 291;
8 | var camera, scene, renderer;
9 | var canvas;
10 | var THREE;
11 | var mainModel, requestId;
12 | var canvasWidth, canvasHeight;
13 |
14 | function initThree(canvasId, modelUrl) {
15 | wx.createSelectorQuery()
16 | .select('#' + canvasId)
17 | .node()
18 | .exec((res) => {
19 | canvas = res[0].node;
20 | THREE = createScopedThreejs(canvas);
21 |
22 | initScene();
23 | loadModel(modelUrl);
24 | });
25 | }
26 |
27 | function initScene() {
28 | camera = new THREE.OrthographicCamera(1, 1, 1, 1, -1000, 1000);
29 | // set the camera
30 | setSize();
31 | scene = new THREE.Scene();
32 | // ambient light
33 | scene.add(new THREE.AmbientLight(0xffffff));
34 | // direction light
35 | var directionallight = new THREE.DirectionalLight(0xffffff, 1);
36 | directionallight.position.set(0, 0, 1000);
37 | scene.add(directionallight);
38 |
39 | // init render
40 | renderer = new THREE.WebGLRenderer({
41 | antialias: true,
42 | alpha: true,
43 | });
44 | const devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
45 | console.log('device pixel ratio', devicePixelRatio);
46 | renderer.setPixelRatio(devicePixelRatio);
47 | renderer.setSize(canvas.width, canvas.height);
48 |
49 | animate();
50 | }
51 |
52 | function loadModel(modelUrl) {
53 | wx.showLoading({
54 | title: 'Loading Sprite...',
55 | });
56 | const sprite_map = new THREE.TextureLoader().load(modelUrl);
57 | const sprite_material = new THREE.SpriteMaterial({ map: sprite_map });
58 | var sprite = new THREE.Sprite(sprite_material);
59 | sprite.scale.setScalar(initScale);
60 | mainModel = sprite;
61 | scene.add(mainModel);
62 | wx.hideLoading();
63 | console.log('loadSprite', 'success');
64 | }
65 |
66 | function updateModel(modelUrl) {
67 | // loading
68 | wx.showLoading({
69 | title: 'Loading Sprite...',
70 | });
71 | // sprite
72 | const sprite_map = new THREE.TextureLoader().load(modelUrl);
73 | const sprite_material = new THREE.SpriteMaterial({ map: sprite_map });
74 | var sprite = new THREE.Sprite(sprite_material);
75 | sprite.scale.setScalar(initScale);
76 | // remove old model
77 | scene.remove(mainModel);
78 | // save new model
79 | mainModel = sprite;
80 | // add new model
81 | scene.add(mainModel);
82 | wx.hideLoading();
83 | console.log('updateSprite', 'success');
84 | }
85 |
86 | function setSize() {
87 | if (!camera) {
88 | return;
89 | }
90 | const w = canvasWidth;
91 | const h = canvasHeight;
92 | camera.left = -0.5 * w;
93 | camera.right = 0.5 * w;
94 | camera.top = 0.5 * h;
95 | camera.bottom = -0.5 * h;
96 | camera.updateProjectionMatrix();
97 | }
98 |
99 | function setModel(prediction,
100 | _canvasWidth,
101 | _canvasHeight) {
102 |
103 | if (!mainModel) {
104 | console.log('setModel', '3d model is not loaded.');
105 | return;
106 | }
107 |
108 | if (_canvasWidth !== canvasWidth) {
109 | canvasWidth = _canvasWidth;
110 | canvasHeight = _canvasHeight;
111 | setSize();
112 | }
113 |
114 | const result = calcTriangle(prediction,
115 | trackPointA,
116 | trackPointB,
117 | trackPointC);
118 | console.log('calcTriangle', result);
119 |
120 | // rotation
121 | var rotation = new THREE.Euler();
122 | rotation.setFromRotationMatrix(result.rotation);
123 | mainModel.material.rotation = rotation.y;
124 | // position
125 | mainModel.position.copy(result.position);
126 | // scale
127 | mainModel.scale.setScalar(initScale * result.scale);
128 | }
129 |
130 | function getPosition(prediction, id) {
131 | var p = prediction.scaledMesh[id];
132 | var x = p[0] - 0.5 * canvasWidth;
133 | var y = 0.5 * canvasHeight - p[1];
134 | var z = p[2];
135 | return new THREE.Vector3(x, y, z);
136 | }
137 |
138 | function getScale(prediction, id1, id2) {
139 | var p1 = prediction.mesh[id1];
140 | var p1_scaled = prediction.scaledMesh[id1];
141 | var p2 = prediction.mesh[id2];
142 | var p2_scaled = prediction.scaledMesh[id2];
143 |
144 | var a = p2[0] - p1[0];
145 | var b = p2_scaled[0] - p1_scaled[0];
146 | return b / a;
147 | }
148 |
149 | function calcTriangle(prediction, id0, id1, id2) {
150 | var p0 = getPosition(prediction, id0);
151 | var p1 = getPosition(prediction, id1);
152 | var p2 = getPosition(prediction, id2);
153 |
154 | // position
155 | var triangle = new THREE.Triangle();
156 | triangle.set(p0, p1, p2);
157 | const center = new THREE.Vector3();
158 | triangle.getMidpoint(center);
159 |
160 | // rotation
161 | const rotation = new THREE.Matrix4();
162 | const x = p1.clone().sub(p2).normalize();
163 | const y = p1.clone().sub(p0).normalize();
164 | const z = new THREE.Vector3().crossVectors(x, y);
165 | const y2 = new THREE.Vector3().crossVectors(x, z).normalize();
166 | const z2 = new THREE.Vector3().crossVectors(x, y2).normalize();
167 | rotation.makeBasis(x, y2, z2);
168 |
169 | // scale
170 | var scale = getScale(prediction, id1, id2);
171 |
172 | return {
173 | position: center,
174 | rotation: rotation,
175 | scale: scale,
176 | };
177 | }
178 |
179 | function setSceneBackground(frame) {
180 | var texture = new THREE.DataTexture(frame.data,
181 | frame.width,
182 | frame.height,
183 | THREE.RGBAFormat);
184 | texture.flipY = true;
185 | texture.needsUpdate = true;
186 | scene.background = texture;
187 | }
188 |
189 | function clearSceneBackground() {
190 | scene.background = null;
191 | }
192 |
193 | function animate() {
194 | requestId = canvas.requestAnimationFrame(animate);
195 | renderer.render(scene, camera);
196 | }
197 |
198 | function stopAnimate() {
199 | if (canvas && requestId) {
200 | canvas.cancelAnimationFrame(requestId);
201 | }
202 | }
203 |
204 | function dispose() {
205 | camera = null;
206 | scene = null;
207 | renderer = null;
208 | canvas = null;
209 | THREE = null;
210 | mainModel = null;
211 | requestId = null;
212 | canvasWidth = null;
213 | canvasHeight = null;
214 | }
215 |
216 | module.exports = {
217 | initThree,
218 | stopAnimate,
219 | updateModel,
220 | setModel,
221 | setSceneBackground,
222 | clearSceneBackground,
223 | dispose,
224 | }
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/camera/camera.js:
--------------------------------------------------------------------------------
1 | const face = require('../../utils/faceBusiness.js')
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasWebGLId = 'canvasWebGL';
4 | // throttling
5 | const cameraFrameMax = 3;
6 | // a url of gltf model
7 | const modelUrl = 'https://m.sanyue.red/demo/gltf/sunglass.glb';
8 | // camera listener
9 | var listener = null;
10 |
11 | Page({
12 | data: {
13 | devicePosition: 'front',
14 | },
15 | async onReady() {
16 | var _that = this;
17 | wx.showLoading({
18 | title: 'Loading TFJS...',
19 | });
20 | await face.loadModel();
21 | wx.hideLoading();
22 |
23 | // load 3d model
24 | model.initThree(canvasWebGLId, modelUrl);
25 |
26 | _that.startTacking();
27 | },
28 | onUnload: function () {
29 | this.stopTacking();
30 | console.log('onUnload', 'listener is stop');
31 |
32 | model.stopAnimate();
33 | model.dispose();
34 | },
35 | startTacking() {
36 | var _that = this;
37 | var count = 0;
38 | const context = wx.createCameraContext();
39 |
40 | // real-time
41 | listener = context.onCameraFrame(async function (res) {
42 | // it is throttling
43 | if (count < cameraFrameMax) {
44 | count++;
45 | return;
46 | }
47 | count = 0;
48 | console.log('onCameraFrame:', res.width, res.height);
49 | const frame = {
50 | data: new Uint8Array(res.data),
51 | width: res.width,
52 | height: res.height,
53 | };
54 |
55 | // process
56 | var result = await face.detect(frame);
57 |
58 | if (result && result.prediction) {
59 | var canvasWidth = frame.width;
60 | var canvasHeight = frame.height;
61 |
62 | // set the rotation and position of the 3d model.
63 | model.setModel(result.prediction,
64 | canvasWidth,
65 | canvasHeight);
66 | } else {
67 | var message = 'No results.';
68 | wx.showToast({
69 | title: message,
70 | icon: 'none'
71 | });
72 | }
73 | });
74 | // start
75 | listener.start();
76 | console.log('startTacking', 'listener is start');
77 | },
78 | stopTacking() {
79 | if (listener) {
80 | listener.stop();
81 | }
82 | },
83 | changeDirection() {
84 | var status = this.data.devicePosition;
85 | if (status === 'back') {
86 | status = 'front';
87 | } else {
88 | status = 'back';
89 | }
90 | this.setData({
91 | devicePosition: status,
92 | });
93 | }
94 | })
95 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/camera/camera.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Access a camera"
3 | }
4 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/camera/camera.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/camera/camera.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 | camera{
8 | width: 375px;
9 | height: 500px;
10 | z-index: 1;
11 | margin:auto;
12 | }
13 |
14 | .canvasWebGL{
15 | width: 100%;
16 | height: 100%;
17 | z-index: 3;
18 | margin:auto;
19 | }
20 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/photo/photo.js:
--------------------------------------------------------------------------------
1 | const face = require('../../utils/faceBusiness.js');
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasId = 'canvas2d';
4 | const canvasWebGLId = 'canvasWebGL';
5 | const maxCanvasWidth = 375;
6 | // a url of gltf model
7 | const modelUrl = 'https://m.sanyue.red/demo/gltf/sunglass.glb';
8 |
9 | Page({
10 | data: {
11 | btnText: 'Take a photo',
12 | devicePosition: 'front',
13 | // if it is taking photo
14 | isRunning: true,
15 | },
16 | async onReady() {
17 | // load tfjs model
18 | wx.showLoading({
19 | title: 'Loading TFJS...',
20 | });
21 | await face.loadModel();
22 | wx.hideLoading();
23 |
24 | // load 3d model
25 | model.initThree(canvasWebGLId, modelUrl);
26 | },
27 | onUnload: function () {
28 | model.stopAnimate();
29 | model.dispose();
30 | },
31 | processPhoto(photoPath, imageWidth, imageHeight) {
32 | var _that = this;
33 | const ctx = wx.createCanvasContext(canvasId);
34 | // the width of the scale image
35 | var canvasWidth = imageWidth;
36 | if (canvasWidth > maxCanvasWidth) {
37 | canvasWidth = maxCanvasWidth;
38 | }
39 | // the height of the scale image
40 | var canvasHeight = Math.floor(canvasWidth * (imageHeight / imageWidth));
41 | // draw image on canvas
42 | ctx.drawImage(photoPath, 0, 0, canvasWidth, canvasHeight);
43 | // waiting for drawing
44 | ctx.draw(false, function () {
45 | // get image data from canvas
46 | wx.canvasGetImageData({
47 | canvasId: canvasId,
48 | x: 0,
49 | y: 0,
50 | width: canvasWidth,
51 | height: canvasHeight,
52 | async success(res) {
53 | console.log('size of frame:', res.width, res.height);
54 | const frame = {
55 | data: new Uint8Array(res.data),
56 | width: res.width,
57 | height: res.height,
58 | };
59 | // process
60 | var result = await face.detect(frame);
61 |
62 | if (result && result.prediction) {
63 | // set the rotation and position of the 3d model.
64 | model.setModel(result.prediction,
65 | canvasWidth,
66 | canvasHeight);
67 | // put the 3d model on the image
68 | model.setSceneBackground(frame);
69 | } else {
70 | var message = 'No results.';
71 | wx.showToast({
72 | title: message,
73 | icon: 'none'
74 | });
75 | }
76 |
77 |
78 | }
79 | });
80 | });
81 | },
82 | takePhoto() {
83 | var _that = this;
84 | const context = wx.createCameraContext();
85 | const ctx = wx.createCanvasContext(canvasId);
86 | if (_that.data.isRunning) {
87 | _that.setData({
88 | btnText: 'Retry',
89 | isRunning: false,
90 | });
91 | // take a photo
92 | context.takePhoto({
93 | quality: 'normal',
94 | success: (res) => {
95 | var photoPath = res.tempImagePath;
96 | //get size of image
97 | wx.getImageInfo({
98 | src: photoPath,
99 | success(res) {
100 | console.log('size of image:', res.width, res.height);
101 | _that.processPhoto(photoPath, res.width, res.height);
102 | }
103 | });
104 | }
105 | });
106 | }
107 | else {
108 | _that.setData({
109 | btnText: 'Take a photo',
110 | isRunning: true,
111 | });
112 | // clear 2d canvas
113 | ctx.clearRect(0, 0);
114 | ctx.draw();
115 | // clear 3d canvas
116 | model.clearSceneBackground();
117 | }
118 | },
119 | changeDirection() {
120 | var status = this.data.devicePosition;
121 | if (status === 'back') {
122 | status = 'front';
123 | } else {
124 | status = 'back';
125 | }
126 | this.setData({
127 | devicePosition: status,
128 | });
129 | }
130 | });
131 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/photo/photo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Take a photo"
3 | }
4 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/photo/photo.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/package_face_3d_mask/pages/photo/photo.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 |
8 | camera{
9 | width: 375px;
10 | height: 500px;
11 | z-index: 1;
12 | margin:auto;
13 | }
14 |
15 | .canvasWebGL{
16 | width: 375px;
17 | height: 500px;
18 | z-index: 3;
19 | margin:auto;
20 | }
21 |
22 | .canvas1{
23 | width: 375px;
24 | height: 500px;
25 | z-index: 2;
26 | margin:auto;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/package_face_3d_mask/utils/faceBusiness.js:
--------------------------------------------------------------------------------
1 | const faceLandmarksDetection = require('@tensorflow-models/face-landmarks-detection');
2 | require('@tensorflow/tfjs-backend-webgl');
3 | const detectionConfidence = 0.8;
4 | const maxFaces = 1;
5 | var model;
6 |
7 | async function loadModel() {
8 | model = await faceLandmarksDetection.load(
9 | faceLandmarksDetection.SupportedPackages.mediapipeFacemesh, {
10 | shouldLoadIrisModel: false,
11 | detectionConfidence: detectionConfidence,
12 | maxFaces: maxFaces,
13 | });
14 | console.log('facemesh model is loaded.');
15 | }
16 |
17 | async function detect(frame) {
18 | if (!model) {
19 | console.log('facemesh model has not been loaded.');
20 | return;
21 | }
22 | var start = new Date();
23 | const predictions = await model.estimateFaces({
24 | input: frame,
25 | predictIrises: false,
26 | });
27 | var end = new Date() - start;
28 | console.log('detect', end, 'ms');
29 |
30 | return { prediction: predictions[0] };
31 | }
32 |
33 | module.exports = { loadModel, detect };
34 |
--------------------------------------------------------------------------------
/package_face_3d_mask/utils/modelBusiness.js:
--------------------------------------------------------------------------------
1 | const { createScopedThreejs } = require('threejs-miniprogram');
2 | const { registerGLTFLoader } = require('./GLTFLoader.js');
3 | // the scale of the 3d model
4 | const initScale = 0.19;
5 | // index of the track points of the face
6 | const trackPointA = 168;
7 | const trackPointB = 122;
8 | const trackPointC = 351;
9 | var camera, scene, renderer;
10 | var canvas;
11 | var THREE;
12 | var mainModel, requestId;
13 | var canvasWidth, canvasHeight;
14 |
15 | function initThree(canvasId, modelUrl) {
16 | wx.createSelectorQuery()
17 | .select('#' + canvasId)
18 | .node()
19 | .exec((res) => {
20 | canvas = res[0].node;
21 | THREE = createScopedThreejs(canvas);
22 |
23 | initScene();
24 | loadModel(modelUrl);
25 | });
26 | }
27 |
28 | function initScene() {
29 | camera = new THREE.OrthographicCamera(1, 1, 1, 1, -1000, 1000);
30 | // set the camera
31 | setSize();
32 | scene = new THREE.Scene();
33 | // ambient light
34 | scene.add(new THREE.AmbientLight(0xffffff));
35 | // direction light
36 | var directionallight = new THREE.DirectionalLight(0xffffff, 1);
37 | directionallight.position.set(0, 0, 1000);
38 | scene.add(directionallight);
39 |
40 | // init render
41 | renderer = new THREE.WebGLRenderer({
42 | antialias: true,
43 | alpha: true,
44 | });
45 | const devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
46 | console.log('device pixel ratio', devicePixelRatio);
47 | renderer.setPixelRatio(devicePixelRatio);
48 | renderer.setSize(canvas.width, canvas.height);
49 |
50 | animate();
51 | }
52 |
53 | function loadModel(modelUrl) {
54 | registerGLTFLoader(THREE);
55 | var loader = new THREE.GLTFLoader();
56 | wx.showLoading({
57 | title: 'Loading 3D...',
58 | });
59 | loader.load(modelUrl,
60 | function (gltf) {
61 | console.log('loadModel', 'success');
62 | var model = gltf.scene;
63 | model.scale.setScalar(initScale);
64 | // save model
65 | mainModel = model;
66 | scene.add(model);
67 | wx.hideLoading();
68 | },
69 | null,
70 | function (error) {
71 | console.log('loadModel', error);
72 | wx.hideLoading();
73 | wx.showToast({
74 | title: 'Loading model failed.',
75 | icon: 'none',
76 | duration: 3000,
77 | });
78 | });
79 | }
80 |
81 | function updateModel(modelUrl) {
82 | var loader = new THREE.GLTFLoader();
83 | // loading
84 | wx.showLoading({
85 | title: 'Loading 3D...',
86 | });
87 | loader.load(modelUrl,
88 | function (gltf) {
89 | console.log('updateModel', 'success');
90 | var model = gltf.scene;
91 | model.scale.setScalar(initScale);
92 | // remove old model
93 | scene.remove(mainModel);
94 | // save new model
95 | mainModel = model;
96 | // add new model
97 | scene.add(model);
98 | wx.hideLoading();
99 | },
100 | null,
101 | function (error) {
102 | console.log('updateModel', error);
103 | wx.hideLoading();
104 | wx.showToast({
105 | title: 'Loading model failed.',
106 | icon: 'none',
107 | duration: 3000,
108 | });
109 | });
110 |
111 | wx.hideLoading();
112 | }
113 |
114 | function setSize() {
115 | if (!camera) {
116 | return;
117 | }
118 | const w = canvasWidth;
119 | const h = canvasHeight;
120 | camera.left = -0.5 * w;
121 | camera.right = 0.5 * w;
122 | camera.top = 0.5 * h;
123 | camera.bottom = -0.5 * h;
124 | camera.updateProjectionMatrix();
125 | }
126 |
127 | function setModel(prediction,
128 | _canvasWidth,
129 | _canvasHeight) {
130 |
131 | if (!mainModel) {
132 | console.log('setModel', '3d model is not loaded.');
133 | return;
134 | }
135 |
136 | if (_canvasWidth !== canvasWidth) {
137 | canvasWidth = _canvasWidth;
138 | canvasHeight = _canvasHeight;
139 | setSize();
140 | }
141 |
142 | const result = calcTriangle(prediction,
143 | trackPointA,
144 | trackPointB,
145 | trackPointC);
146 | console.log('calcTriangle', result);
147 |
148 |
149 | // rotation
150 | mainModel.rotation.setFromRotationMatrix(
151 | result.rotation);
152 | // position
153 | mainModel.position.copy(result.position);
154 | // scal
155 | mainModel.scale.setScalar(initScale * result.scale);
156 | }
157 |
158 | function getPosition(prediction, id) {
159 | var p = prediction.scaledMesh[id];
160 | var x = p[0] - 0.5 * canvasWidth;
161 | var y = 0.5 * canvasHeight - p[1];
162 | var z = p[2];
163 | return new THREE.Vector3(x, y, z);
164 | }
165 |
166 | function getScale(prediction, id1, id2) {
167 | var p1 = prediction.mesh[id1];
168 | var p1_scaled = prediction.scaledMesh[id1];
169 | var p2 = prediction.mesh[id2];
170 | var p2_scaled = prediction.scaledMesh[id2];
171 |
172 | var a = p2[0] - p1[0];
173 | var b = p2_scaled[0] - p1_scaled[0];
174 | return b / a;
175 | }
176 |
177 | function calcTriangle(prediction, id0, id1, id2) {
178 | var p0 = getPosition(prediction, id0);
179 | var p1 = getPosition(prediction, id1);
180 | var p2 = getPosition(prediction, id2);
181 |
182 | // position
183 | var triangle = new THREE.Triangle();
184 | triangle.set(p0, p1, p2);
185 | const center = new THREE.Vector3();
186 | triangle.getMidpoint(center);
187 |
188 | // rotation
189 | const rotation = new THREE.Matrix4();
190 | const x = p1.clone().sub(p2).normalize();
191 | const y = p1.clone().sub(p0).normalize();
192 | const z = new THREE.Vector3().crossVectors(x, y);
193 | const y2 = new THREE.Vector3().crossVectors(x, z).normalize();
194 | const z2 = new THREE.Vector3().crossVectors(x, y2).normalize();
195 | rotation.makeBasis(x, y2, z2);
196 |
197 | // scale
198 | var scale = getScale(prediction, id1, id2);
199 |
200 | return {
201 | position: center,
202 | rotation: rotation,
203 | scale: scale,
204 | };
205 | }
206 |
207 | function setSceneBackground(frame) {
208 | var texture = new THREE.DataTexture(frame.data,
209 | frame.width,
210 | frame.height,
211 | THREE.RGBAFormat);
212 | texture.flipY = true;
213 | texture.needsUpdate = true;
214 | scene.background = texture;
215 | }
216 |
217 | function clearSceneBackground() {
218 | scene.background = null;
219 | }
220 |
221 | function animate() {
222 | requestId = canvas.requestAnimationFrame(animate);
223 | renderer.render(scene, camera);
224 | }
225 |
226 | function stopAnimate() {
227 | if (canvas && requestId) {
228 | canvas.cancelAnimationFrame(requestId);
229 | }
230 | }
231 |
232 | function dispose() {
233 | camera = null;
234 | scene = null;
235 | renderer = null;
236 | canvas = null;
237 | THREE = null;
238 | mainModel = null;
239 | requestId = null;
240 | canvasWidth = null;
241 | canvasHeight = null;
242 | }
243 |
244 | module.exports = {
245 | initThree,
246 | stopAnimate,
247 | updateModel,
248 | setModel,
249 | setSceneBackground,
250 | clearSceneBackground,
251 | dispose,
252 | }
--------------------------------------------------------------------------------
/package_handpose_mask/pages/camera/camera.js:
--------------------------------------------------------------------------------
1 | const hand = require('../../utils/handBusiness.js');
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasWebGLId = 'canvasWebGL';
4 | // a url of gltf model
5 | const modelUrl = '../../utils/cat_beard.png';
6 | // camera listener
7 | var listener = null;
8 |
9 | Page({
10 | // throttling for Android
11 | intervalTimeout: 500,
12 | data: {
13 | devicePosition: 'back',
14 | },
15 | onReady() {
16 | const system = wx.getSystemInfoSync().system;
17 | // if iOS
18 | if (system.indexOf('iOS') !== -1) {
19 | // throttling for iOS
20 | this.intervalTimeout = 3000;
21 | }
22 | },
23 | async onLoad() {
24 | var _that = this;
25 | wx.showLoading({
26 | title: 'Loading TFJS...',
27 | });
28 | await hand.loadModel();
29 | wx.hideLoading();
30 |
31 | setTimeout(function () {
32 | // load 3d model
33 | model.initThree(canvasWebGLId, modelUrl);
34 | }, 150)
35 | _that.startTacking();
36 | },
37 | onUnload: function () {
38 | this.stopTacking();
39 | console.log('onUnload', 'listener is stop');
40 |
41 | model.stopAnimate();
42 | model.dispose();
43 | },
44 | async onCameraFrame_callback(frame,
45 | canvasWidth,
46 | canvasHeight) {
47 |
48 | // process
49 | var result = await hand.detect(frame);
50 |
51 | if (result && result.prediction.length > 0) {
52 | var canvasWidth = frame.width;
53 | var canvasHeight = frame.height;
54 |
55 | // set the rotation and position of the 3d model.
56 | model.setModel(result.prediction[0],
57 | canvasWidth,
58 | canvasHeight);
59 | } else {
60 | var message = 'No results.';
61 | console.log('onCameraFrame_callback', message)
62 | }
63 |
64 | },
65 | startTacking() {
66 | var _that = this;
67 | const context = wx.createCameraContext();
68 |
69 | // real-time
70 | var frameData;
71 | var canvasWidth;
72 | var canvasHeight;
73 | this.listener = context.onCameraFrame(function (res) {
74 | frameData = {
75 | data: new Uint8Array(res.data),
76 | width: res.width,
77 | height: res.height,
78 | };;
79 | canvasWidth = res.width;
80 | canvasHeight = res.height;
81 | // console.log('onCameraFrame:', res.width, res.height);
82 | });
83 |
84 | this.intervalId = setInterval(function () {
85 | if (frameData) {
86 | _that.onCameraFrame_callback(frameData,
87 | canvasWidth,
88 | canvasHeight);
89 | }
90 | }, this.intervalTimeout);
91 |
92 | // start
93 | this.listener.start();
94 | console.log('startTacking', 'listener is running');
95 | },
96 | stopTacking() {
97 | if (this.listener) {
98 | this.listener.stop();
99 | this.listener = null;
100 | }
101 | clearInterval(this.intervalId);
102 | },
103 | changeDirection() {
104 | var status = this.data.devicePosition;
105 | if (status === 'back') {
106 | status = 'front';
107 | } else {
108 | status = 'back';
109 | }
110 | this.setData({
111 | devicePosition: status,
112 | });
113 | }
114 | })
115 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/camera/camera.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Access a camera"
3 | }
4 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/camera/camera.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/camera/camera.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 | camera{
8 | width: 375px;
9 | height: 500px;
10 | z-index: 1;
11 | margin:auto;
12 | }
13 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/photo/photo.js:
--------------------------------------------------------------------------------
1 | const hand = require('../../utils/handBusiness.js');
2 | const model = require('../../utils/modelBusiness.js');
3 | const canvasId = 'canvas2d'
4 | const canvasWebGLId = 'canvasWebGL';
5 | const maxCanvasWidth = 375;
6 | // a url of gltf model
7 | const modelUrl = '../../utils/cat_beard.png';
8 |
9 | Page({
10 | data: {
11 | btnText: 'Take a photo',
12 | devicePosition: 'back',
13 | // if it is taking photo
14 | isRunning: true,
15 | },
16 | async onLoad() {
17 | // var _that = this;
18 | // load tfjs model
19 | wx.showLoading({
20 | title: 'Loading TFJS...',
21 | });
22 | await hand.loadModel();
23 | wx.hideLoading();
24 |
25 | setTimeout(function () {
26 | // load 3d model
27 | model.initThree(canvasWebGLId, modelUrl);
28 | }, 150)
29 |
30 | },
31 | onUnload: function () {
32 | model.stopAnimate();
33 | model.dispose();
34 | },
35 | processPhoto(photoPath, imageWidth, imageHeight) {
36 | var _that = this;
37 | const ctx = wx.createCanvasContext(canvasId);
38 | // the width of the scale image
39 | var canvasWidth = imageWidth;
40 | if (canvasWidth > maxCanvasWidth) {
41 | canvasWidth = maxCanvasWidth;
42 | }
43 | // the height of the scale image
44 | var canvasHeight = Math.floor(canvasWidth * (imageHeight / imageWidth));
45 | // draw image on canvas
46 | ctx.drawImage(photoPath, 0, 0, canvasWidth, canvasHeight);
47 | // waiting for drawing
48 | ctx.draw(false, function () {
49 | // get image data from canvas
50 | wx.canvasGetImageData({
51 | canvasId: canvasId,
52 | x: 0,
53 | y: 0,
54 | width: canvasWidth,
55 | height: canvasHeight,
56 | async success(res) {
57 | console.log('size of frame:', res.width, res.height);
58 | const frame = {
59 | data: new Uint8Array(res.data),
60 | width: res.width,
61 | height: res.height,
62 | };
63 | // process
64 | var result = await hand.detect(frame);
65 |
66 | if (result && result.prediction.length > 0) {
67 | // set the rotation and position of the 3d model.
68 | model.setModel(result.prediction[0],
69 | canvasWidth,
70 | canvasHeight);
71 | // put the 3d model on the image
72 | model.setSceneBackground(frame);
73 | } else {
74 | var message = 'No results.';
75 | console.log('processPhoto', message)
76 | wx.showToast({
77 | title: message,
78 | icon: 'none'
79 | });
80 | }
81 | }
82 | });
83 | });
84 | },
85 | takePhoto() {
86 | var _that = this;
87 | const context = wx.createCameraContext();
88 | const ctx = wx.createCanvasContext(canvasId);
89 | if (_that.data.isRunning) {
90 | _that.setData({
91 | btnText: 'Retry',
92 | isRunning: false,
93 | });
94 | // take a photo
95 | context.takePhoto({
96 | quality: 'normal',
97 | success: (res) => {
98 | var photoPath = res.tempImagePath;
99 | //get size of image
100 | wx.getImageInfo({
101 | src: photoPath,
102 | success(res) {
103 | console.log('size of image:', res.width, res.height);
104 | _that.processPhoto(photoPath, res.width, res.height);
105 | }
106 | });
107 | }
108 | });
109 | }
110 | else {
111 | _that.setData({
112 | btnText: 'Take a photo',
113 | isRunning: true,
114 | });
115 | // clear 2d canvas
116 | ctx.clearRect(0, 0);
117 | ctx.draw();
118 | // clear 3d canvas
119 | model.clearSceneBackground();
120 | }
121 | },
122 | changeDirection() {
123 | var status = this.data.devicePosition;
124 | if (status === 'back') {
125 | status = 'front';
126 | } else {
127 | status = 'back';
128 | }
129 | this.setData({
130 | devicePosition: status,
131 | });
132 | }
133 | });
134 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/photo/photo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Take a photo"
3 | }
4 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/photo/photo.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/package_handpose_mask/pages/photo/photo.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 |
8 | camera{
9 | width: 375px;
10 | height: 500px;
11 | z-index: 1;
12 | margin:auto;
13 | }
14 |
15 | .canvasWebGL{
16 | width: 375px;
17 | height: 500px;
18 | z-index: 3;
19 | margin:auto;
20 | }
21 |
22 | .canvas1{
23 | width: 375px;
24 | height: 500px;
25 | z-index: 2;
26 | margin:auto;
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/package_handpose_mask/utils/cat_beard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sanyuered/WeChat-MiniProgram-AR-TFJS/5152b650c33a5fadc4be16496441ec0e02c79329/package_handpose_mask/utils/cat_beard.png
--------------------------------------------------------------------------------
/package_handpose_mask/utils/handBusiness.js:
--------------------------------------------------------------------------------
1 | const handpose = require('@tensorflow-models/handpose');
2 | require('@tensorflow/tfjs-backend-webgl');
3 | var model;
4 | const flipHorizontal = false;
5 |
6 | async function loadModel() {
7 | model = await handpose.load();
8 | console.log('handpose model is loaded.');
9 | }
10 |
11 | async function detect(frame) {
12 | if (!model) {
13 | console.log('handpose model has not been loaded.');
14 | return;
15 | }
16 | var start = new Date();
17 | const predictions = await model.estimateHands(
18 | frame,
19 | flipHorizontal
20 | );
21 | var end = new Date() - start;
22 | console.log('detect', end, 'ms');
23 |
24 | return { prediction: predictions };
25 | }
26 |
27 | module.exports = { loadModel, detect };
28 |
--------------------------------------------------------------------------------
/package_handpose_mask/utils/modelBusiness.js:
--------------------------------------------------------------------------------
1 | const { createScopedThreejs } = require('threejs-miniprogram');
2 | // the scale of the image
3 | const initScale = 240;
4 | // index of the track points of the face
5 | const trackPointA = 8;
6 | var camera, scene, renderer;
7 | var canvas;
8 | var THREE;
9 | var mainModel, requestId;
10 | var canvasWidth, canvasHeight;
11 |
12 | function initThree(canvasId, modelUrl) {
13 | wx.createSelectorQuery()
14 | .select('#' + canvasId)
15 | .node()
16 | .exec((res) => {
17 | canvas = res[0].node;
18 | THREE = createScopedThreejs(canvas);
19 |
20 | initScene();
21 | loadModel(modelUrl);
22 | });
23 | }
24 |
25 | function initScene() {
26 | camera = new THREE.OrthographicCamera(1, 1, 1, 1, -1000, 1000);
27 | // set the camera
28 | setSize();
29 | scene = new THREE.Scene();
30 | // ambient light
31 | scene.add(new THREE.AmbientLight(0xffffff));
32 | // direction light
33 | var directionallight = new THREE.DirectionalLight(0xffffff, 1);
34 | directionallight.position.set(0, 0, 1000);
35 | scene.add(directionallight);
36 |
37 | // init render
38 | renderer = new THREE.WebGLRenderer({
39 | antialias: true,
40 | alpha: true,
41 | });
42 | const devicePixelRatio = wx.getSystemInfoSync().pixelRatio;
43 | console.log('device pixel ratio', devicePixelRatio);
44 | renderer.setPixelRatio(devicePixelRatio);
45 | renderer.setSize(canvas.width, canvas.height);
46 |
47 | animate();
48 | }
49 |
50 | function loadModel(modelUrl) {
51 | wx.showLoading({
52 | title: 'Loading Sprite...',
53 | });
54 | const sprite_map = new THREE.TextureLoader().load(modelUrl);
55 | const sprite_material = new THREE.SpriteMaterial({ map: sprite_map });
56 | var sprite = new THREE.Sprite(sprite_material);
57 | sprite.scale.setScalar(initScale);
58 | mainModel = sprite;
59 | scene.add(mainModel);
60 | wx.hideLoading();
61 | console.log('loadSprite', 'success');
62 | }
63 |
64 | function updateModel(modelUrl) {
65 | // loading
66 | wx.showLoading({
67 | title: 'Loading Sprite...',
68 | });
69 | // sprite
70 | const sprite_map = new THREE.TextureLoader().load(modelUrl);
71 | const sprite_material = new THREE.SpriteMaterial({ map: sprite_map });
72 | var sprite = new THREE.Sprite(sprite_material);
73 | sprite.scale.setScalar(initScale);
74 | // remove old model
75 | scene.remove(mainModel);
76 | // save new model
77 | mainModel = sprite;
78 | // add new model
79 | scene.add(mainModel);
80 | wx.hideLoading();
81 | console.log('updateSprite', 'success');
82 | }
83 |
84 | function setSize() {
85 | if (!camera) {
86 | return;
87 | }
88 | const w = canvasWidth;
89 | const h = canvasHeight;
90 | camera.left = -0.5 * w;
91 | camera.right = 0.5 * w;
92 | camera.top = 0.5 * h;
93 | camera.bottom = -0.5 * h;
94 | camera.updateProjectionMatrix();
95 | }
96 |
97 | function getPosition(prediction, id) {
98 | var p = prediction.landmarks[id];
99 | var x = p[0] - 0.5 * canvasWidth;
100 | var y = 0.5 * canvasHeight - p[1];
101 | var z = p[2];
102 | return new THREE.Vector3(x, y, z);
103 | }
104 |
105 | function setModel(prediction,
106 | _canvasWidth,
107 | _canvasHeight) {
108 |
109 | if (!mainModel) {
110 | console.log('setModel', '3d model is not loaded.');
111 | return;
112 | }
113 |
114 | if (_canvasWidth !== canvasWidth) {
115 | canvasWidth = _canvasWidth;
116 | canvasHeight = _canvasHeight;
117 | setSize();
118 | }
119 |
120 | var position = getPosition(prediction, trackPointA);
121 | console.log('setModel', position);
122 |
123 | // position
124 | mainModel.position.copy(position);
125 |
126 | }
127 |
128 | function setSceneBackground(frame) {
129 | var texture = new THREE.DataTexture(frame.data,
130 | frame.width,
131 | frame.height,
132 | THREE.RGBAFormat);
133 | texture.flipY = true;
134 | texture.needsUpdate = true;
135 | scene.background = texture;
136 | }
137 |
138 | function clearSceneBackground() {
139 | scene.background = null;
140 | }
141 |
142 | function animate() {
143 | requestId = canvas.requestAnimationFrame(animate);
144 | renderer.render(scene, camera);
145 | }
146 |
147 | function stopAnimate() {
148 | if (canvas && requestId) {
149 | canvas.cancelAnimationFrame(requestId);
150 | }
151 | }
152 |
153 | function dispose() {
154 | camera = null;
155 | scene = null;
156 | renderer = null;
157 | canvas = null;
158 | THREE = null;
159 | mainModel = null;
160 | requestId = null;
161 | canvasWidth = null;
162 | canvasHeight = null;
163 | }
164 |
165 | module.exports = {
166 | initThree,
167 | stopAnimate,
168 | updateModel,
169 | setModel,
170 | setSceneBackground,
171 | clearSceneBackground,
172 | dispose,
173 | }
--------------------------------------------------------------------------------
/package_mobilenet/pages/camera/camera.js:
--------------------------------------------------------------------------------
1 | const mobilenet = require('../../utils/mobilenet.js');
2 |
3 | Page({
4 | listener:null,
5 | // throttling
6 | intervalTimeout: 1000,
7 | mobilenetModel:null,
8 | data: {
9 | devicePosition: 'back',
10 | result:'',
11 | },
12 | async onReady() {
13 | const system = wx.getSystemInfoSync().system;
14 | var _that = this;
15 | wx.showLoading({
16 | title: 'Loading TFJS...',
17 | });
18 | await this.initMobilenet()
19 | wx.hideLoading();
20 |
21 | _that.startTacking();
22 | },
23 | onUnload: function () {
24 | this.stopTacking();
25 | console.log('onUnload', 'listener is stop');
26 | },
27 | startTacking() {
28 | var _that = this;
29 | const context = wx.createCameraContext();
30 |
31 | // real-time
32 | var frameData;
33 | var canvasWidth;
34 | var canvasHeight;
35 | this.listener = context.onCameraFrame(function (res) {
36 | frameData = {
37 | data: new Uint8Array(res.data),
38 | width: res.width,
39 | height: res.height,
40 | };;
41 | canvasWidth = res.width;
42 | canvasHeight = res.height;
43 | // console.log('onCameraFrame:', res.width, res.height);
44 | });
45 |
46 | this.intervalId = setInterval(async function () {
47 | if (frameData) {
48 | // process
49 | await _that.executeMobilenet(frameData);
50 | }
51 | }, this.intervalTimeout);
52 |
53 | // start
54 | this.listener.start();
55 | console.log('startTacking', 'listener is running');
56 | },
57 | stopTacking() {
58 | if (this.listener) {
59 | this.listener.stop();
60 | this.listener = null;
61 | }
62 | clearInterval(this.intervalId);
63 | },
64 | changeDirection() {
65 | var status = this.data.devicePosition;
66 | if (status === 'back') {
67 | status = 'front';
68 | } else {
69 | status = 'back';
70 | }
71 | this.setData({
72 | devicePosition: status,
73 | });
74 | },
75 | async initMobilenet() {
76 | // Load the model.
77 | this.mobilenetModel = await mobilenet.load({
78 | version:2,
79 | alpha:0.5,
80 | });
81 | this.setData({ result: 'model loaded.' });
82 | console.log('initMobilenet', 'model loaded');
83 | },
84 | async executeMobilenet(frame) {
85 | if (!this.mobilenetModel) {
86 | return
87 | }
88 | const img = frame
89 | // Classify the image.
90 | const predictions = await this.mobilenetModel.classify(img);
91 | this.setData({ result: predictions[0].className+",概率:"+predictions[0].probability.toFixed(2) });
92 | console.log('executeMobilenet', predictions);
93 | },
94 | })
95 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/camera/camera.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Access a camera"
3 | }
4 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/camera/camera.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
14 |
15 |
16 |
17 | {{result}}
18 |
19 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/camera/camera.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 | camera{
8 | width: 375px;
9 | height: 500px;
10 | z-index: 1;
11 | margin:auto;
12 | }
13 |
14 | .canvasWebGL{
15 | width: 100%;
16 | height: 100%;
17 | z-index: 3;
18 | margin:auto;
19 | }
20 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/photo/photo.js:
--------------------------------------------------------------------------------
1 | const mobilenet = require('../../utils/mobilenet.js');
2 | const canvasId = 'canvas2d'
3 | const maxCanvasWidth = 375;
4 |
5 | Page({
6 | mobilenetModel: null,
7 | data: {
8 | btnText: 'Take a photo',
9 | devicePosition: 'back',
10 | // if it is taking photo
11 | isRunning: true,
12 | result: '',
13 | },
14 | async onReady() {
15 | // var _that = this;
16 | // load tfjs model
17 | wx.showLoading({
18 | title: 'Loading TFJS...',
19 | });
20 | await this.initMobilenet()
21 | wx.hideLoading();
22 | },
23 | onUnload: function () {
24 |
25 | },
26 | processPhoto(photoPath, imageWidth, imageHeight) {
27 | var _that = this;
28 | const ctx = wx.createCanvasContext(canvasId);
29 | // the width of the scale image
30 | var canvasWidth = imageWidth;
31 | if (canvasWidth > maxCanvasWidth) {
32 | canvasWidth = maxCanvasWidth;
33 | }
34 | // the height of the scale image
35 | var canvasHeight = Math.floor(canvasWidth * (imageHeight / imageWidth));
36 | // draw image on canvas
37 | ctx.drawImage(photoPath, 0, 0, canvasWidth, canvasHeight);
38 | // waiting for drawing
39 | ctx.draw(false, function () {
40 | // get image data from canvas
41 | wx.canvasGetImageData({
42 | canvasId: canvasId,
43 | x: 0,
44 | y: 0,
45 | width: canvasWidth,
46 | height: canvasHeight,
47 | async success(res) {
48 | console.log('size of frame:', res.width, res.height);
49 | const frame = {
50 | data: new Uint8Array(res.data),
51 | width: res.width,
52 | height: res.height,
53 | };
54 | // process
55 | await _that.executeMobilenet(frame);
56 |
57 | }
58 | });
59 | });
60 | },
61 | takePhoto() {
62 | var _that = this;
63 | const context = wx.createCameraContext();
64 | const ctx = wx.createCanvasContext(canvasId);
65 | if (_that.data.isRunning) {
66 | _that.setData({
67 | btnText: 'Retry',
68 | isRunning: false,
69 | });
70 | // take a photo
71 | context.takePhoto({
72 | quality: 'normal',
73 | success: (res) => {
74 | var photoPath = res.tempImagePath;
75 | //get size of image
76 | wx.getImageInfo({
77 | src: photoPath,
78 | success(res) {
79 | console.log('size of image:', res.width, res.height);
80 | _that.processPhoto(photoPath, res.width, res.height);
81 | }
82 | });
83 | }
84 | });
85 | }
86 | else {
87 | _that.setData({
88 | btnText: 'Take a photo',
89 | isRunning: true,
90 | });
91 | // clear 2d canvas
92 | ctx.clearRect(0, 0);
93 | ctx.draw();
94 | }
95 | },
96 | changeDirection() {
97 | var status = this.data.devicePosition;
98 | if (status === 'back') {
99 | status = 'front';
100 | } else {
101 | status = 'back';
102 | }
103 | this.setData({
104 | devicePosition: status,
105 | });
106 | },
107 | async initMobilenet() {
108 | // Load the model.
109 | this.mobilenetModel = await mobilenet.load({
110 | version: 2,
111 | alpha: 0.5,
112 | });
113 | this.setData({ result: 'model loaded.' });
114 | console.log('initMobilenet', 'model loaded');
115 | },
116 | async executeMobilenet(frame) {
117 | if (!this.mobilenetModel) {
118 | return
119 | }
120 | const img = frame
121 | // Classify the image.
122 | const predictions = await this.mobilenetModel.classify(img);
123 | this.setData({ result: predictions[0].className + ",概率:" + predictions[0].probability.toFixed(2) });
124 | console.log('executeMobilenet', predictions);
125 | },
126 | });
127 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/photo/photo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "Take a photo"
3 | }
4 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/photo/photo.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 | {{result}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package_mobilenet/pages/photo/photo.wxss:
--------------------------------------------------------------------------------
1 | .page__bd{
2 | padding-bottom:0;
3 | }
4 | .page__bd_spacing{
5 | padding-top:10px;
6 | }
7 |
8 | camera{
9 | width: 375px;
10 | height: 500px;
11 | z-index: 1;
12 | margin:auto;
13 | }
14 |
15 | .canvas1{
16 | width: 375px;
17 | height: 500px;
18 | z-index: 2;
19 | margin:auto;
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/package_mobilenet/utils/mobilenet.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @license
3 | * Copyright 2019 Google LLC. All Rights Reserved.
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | * =============================================================================
16 | */
17 |
18 | import * as tfconv from '@tensorflow/tfjs-converter';
19 | import * as tf from '@tensorflow/tfjs-core';
20 |
21 | import { IMAGENET_CLASSES } from './imagenet_classes.js';
22 |
23 | const IMAGE_SIZE = 224;
24 |
25 | const EMBEDDING_NODES = {
26 | '1.00': 'module_apply_default/MobilenetV1/Logits/global_pool',
27 | '2.00': 'module_apply_default/MobilenetV2/Logits/AvgPool'
28 | };
29 |
30 | const MODEL_INFO = {
31 | '1.00': {
32 | '0.25': {
33 | url:
34 | 'https://tfhub.dev/google/imagenet/mobilenet_v1_025_224/classification/1',
35 | inputRange: [0, 1]
36 | },
37 | '0.50': {
38 | url:
39 | 'https://tfhub.dev/google/imagenet/mobilenet_v1_050_224/classification/1',
40 | inputRange: [0, 1]
41 | },
42 | '0.75': {
43 | url:
44 | 'https://tfhub.dev/google/imagenet/mobilenet_v1_075_224/classification/1',
45 | inputRange: [0, 1]
46 | },
47 | '1.00': {
48 | url:
49 | 'https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1',
50 | inputRange: [0, 1]
51 | }
52 | }, // mobilenet_model_path
53 | '2.00': {
54 | '0.50': {
55 | url:
56 | 'https://m.sanyue.red/demo/tfjs/mobilenet_v2_050_224',
57 | inputRange: [0, 1]
58 | },
59 | '0.75': {
60 | url:
61 | 'https://tfhub.dev/google/imagenet/mobilenet_v2_075_224/classification/2',
62 | inputRange: [0, 1]
63 | },
64 | '1.00': {
65 | url:
66 | 'https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/classification/2',
67 | inputRange: [0, 1]
68 | }
69 | }
70 | };
71 |
72 | const STORAGE_KEY = 'mobilenet_model';
73 |
74 | // See ModelConfig documentation for expectations of provided fields.
75 | export async function load(modelConfig = {
76 | version: 1,
77 | alpha: 1.0
78 | }) {
79 | if (tf == null) {
80 | throw new Error(
81 | `Cannot find TensorFlow.js. If you are using a