facebetter 1.0.14 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -0
- package/dist/facebetter.esm.js +586 -161
- package/dist/facebetter.esm.js.map +1 -1
- package/dist/facebetter.js +586 -161
- package/dist/facebetter.js.map +1 -1
- package/package.json +2 -2
package/dist/facebetter.esm.js
CHANGED
|
@@ -47,7 +47,13 @@ class EngineConfig {
|
|
|
47
47
|
this.appId = config.appId || null;
|
|
48
48
|
this.appKey = config.appKey || null;
|
|
49
49
|
this.licenseJson = config.licenseJson || null;
|
|
50
|
-
this.resourcePath = '/
|
|
50
|
+
this.resourcePath = '/resource.fbd';
|
|
51
|
+
/**
|
|
52
|
+
* Whether to use an external GL context (native platforms only).
|
|
53
|
+
* In Web/WASM environments, this field is kept for configuration structure alignment,
|
|
54
|
+
* but it does not take effect in the current implementation.
|
|
55
|
+
*/
|
|
56
|
+
this.externalContext = !!config.externalContext;
|
|
51
57
|
}
|
|
52
58
|
|
|
53
59
|
/**
|
|
@@ -55,11 +61,11 @@ class EngineConfig {
|
|
|
55
61
|
* @returns {boolean} True if valid
|
|
56
62
|
*/
|
|
57
63
|
isValid() {
|
|
58
|
-
//
|
|
64
|
+
// If licenseJson is provided, use it for validation
|
|
59
65
|
if (this.licenseJson) {
|
|
60
66
|
return typeof this.licenseJson === 'string' && this.licenseJson.trim() !== '';
|
|
61
67
|
}
|
|
62
|
-
//
|
|
68
|
+
// Otherwise appId and appKey are required
|
|
63
69
|
return this.appId && typeof this.appId === 'string' && this.appId.trim() !== '' &&
|
|
64
70
|
this.appKey && typeof this.appKey === 'string' && this.appKey.trim() !== '';
|
|
65
71
|
}
|
|
@@ -82,61 +88,87 @@ class EngineConfig {
|
|
|
82
88
|
* Beauty type enumeration
|
|
83
89
|
*/
|
|
84
90
|
const BeautyType$1 = {
|
|
85
|
-
Basic: 0,
|
|
86
|
-
Reshape: 1,
|
|
87
|
-
Makeup: 2,
|
|
88
|
-
VirtualBackground: 3
|
|
91
|
+
Basic: 0, // Basic beauty (smoothing, whitening, etc.)
|
|
92
|
+
Reshape: 1, // Face reshaping (face thinning, big eyes, etc.)
|
|
93
|
+
Makeup: 2, // Makeup effects (lipstick, blush, etc.)
|
|
94
|
+
VirtualBackground: 3, // Virtual background (blur, image replacement)
|
|
95
|
+
ChromaKey: 4, // Chroma key (green screen removal)
|
|
96
|
+
Filter: 5, // LUT based filter
|
|
97
|
+
Sticker: 6 // 2D/3D sticker
|
|
89
98
|
};
|
|
90
99
|
|
|
91
100
|
/**
|
|
92
101
|
* Basic beauty parameter enumeration
|
|
102
|
+
* All values should be in range [0.0, 1.0]
|
|
93
103
|
*/
|
|
94
104
|
const BasicParam$1 = {
|
|
95
|
-
Smoothing: 0, //
|
|
96
|
-
Sharpening: 1,
|
|
97
|
-
Whitening: 2, //
|
|
98
|
-
Rosiness: 3 //
|
|
105
|
+
Smoothing: 0, // Skin smoothing (0.0: none, 1.0: maximum)
|
|
106
|
+
Sharpening: 1, // Image sharpening (0.0: none, 1.0: maximum)
|
|
107
|
+
Whitening: 2, // Skin whitening (0.0: none, 1.0: maximum)
|
|
108
|
+
Rosiness: 3 // Skin rosiness (0.0: none, 1.0: maximum)
|
|
99
109
|
};
|
|
100
110
|
|
|
101
111
|
/**
|
|
102
112
|
* Face reshape parameter enumeration
|
|
113
|
+
* All values should be in range [0.0, 1.0]
|
|
103
114
|
*/
|
|
104
115
|
const ReshapeParam$1 = {
|
|
105
|
-
|
|
106
|
-
FaceVShape: 1,
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
Cheekbone: 4,
|
|
110
|
-
Jawbone: 5,
|
|
111
|
-
Chin: 6,
|
|
112
|
-
|
|
113
|
-
EyeSize: 8,
|
|
114
|
-
EyeDistance: 9
|
|
116
|
+
FaceThinning: 0, // Face thinning (0.0: none, 1.0: maximum)
|
|
117
|
+
FaceVShape: 1, // V-shape face (0.0: none, 1.0: maximum)
|
|
118
|
+
FaceNarrowing: 2, // Face narrowing (0.0: none, 1.0: maximum)
|
|
119
|
+
FaceShortening: 3,// Face shortening (0.0: none, 1.0: maximum)
|
|
120
|
+
Cheekbone: 4, // Cheekbone slimming (0.0: none, 1.0: maximum)
|
|
121
|
+
Jawbone: 5, // Jawbone slimming (0.0: none, 1.0: maximum)
|
|
122
|
+
Chin: 6, // Chin length adjustment (0.0: none, 1.0: maximum)
|
|
123
|
+
NoseSlimming: 7, // Nose slimming (0.0: none, 1.0: maximum)
|
|
124
|
+
EyeSize: 8, // Eye size (0.0: normal, 1.0: maximum)
|
|
125
|
+
EyeDistance: 9 // Eye distance (0.0: normal, 1.0: maximum)
|
|
115
126
|
};
|
|
116
127
|
|
|
117
128
|
/**
|
|
118
129
|
* Makeup parameter enumeration
|
|
130
|
+
* All values should be in range [0.0, 1.0]
|
|
119
131
|
*/
|
|
120
132
|
const MakeupParam$1 = {
|
|
121
|
-
Lipstick: 0, //
|
|
122
|
-
Blush: 1 //
|
|
133
|
+
Lipstick: 0, // Lipstick intensity (0.0: none, 1.0: maximum)
|
|
134
|
+
Blush: 1 // Blush intensity (0.0: none, 1.0: maximum)
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Chroma Key parameter enumeration
|
|
139
|
+
*/
|
|
140
|
+
const ChromaKeyParam$1 = {
|
|
141
|
+
KeyColor: 0, // Key color (0.0: Green, 1.0: Blue, 2.0: Red)
|
|
142
|
+
Similarity: 1, // Color similarity (0.0 - 1.0)
|
|
143
|
+
Smoothness: 2, // Edge smoothness (0.0 - 1.0)
|
|
144
|
+
Desaturation: 3 // Spill desaturation (0.0 - 1.0)
|
|
123
145
|
};
|
|
124
146
|
|
|
125
147
|
/**
|
|
126
148
|
* Background mode enumeration
|
|
127
149
|
*/
|
|
128
150
|
const BackgroundMode$1 = {
|
|
129
|
-
None: 0, //
|
|
130
|
-
Blur: 1, //
|
|
131
|
-
Image: 2 //
|
|
151
|
+
None: 0, // No background processing
|
|
152
|
+
Blur: 1, // Blurred background
|
|
153
|
+
Image: 2 // Background image replacement
|
|
132
154
|
};
|
|
133
155
|
|
|
134
156
|
/**
|
|
135
|
-
*
|
|
157
|
+
* Frame type enumeration
|
|
136
158
|
*/
|
|
137
|
-
const
|
|
138
|
-
Image: 0, //
|
|
139
|
-
Video: 1 //
|
|
159
|
+
const FrameType$1 = {
|
|
160
|
+
Image: 0, // Image mode
|
|
161
|
+
Video: 1 // Video mode
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Mirror mode enumeration (apply to input before processing)
|
|
166
|
+
*/
|
|
167
|
+
const MirrorMode$1 = {
|
|
168
|
+
None: 0, // No mirror
|
|
169
|
+
Horizontal: 1, // Mirror horizontally (e.g. front camera selfie)
|
|
170
|
+
Vertical: 2, // Mirror vertically
|
|
171
|
+
Both: 3 // Mirror both axes
|
|
140
172
|
};
|
|
141
173
|
|
|
142
174
|
/**
|
|
@@ -172,8 +204,10 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
172
204
|
BackgroundMode: BackgroundMode$1,
|
|
173
205
|
BasicParam: BasicParam$1,
|
|
174
206
|
BeautyType: BeautyType$1,
|
|
207
|
+
ChromaKeyParam: ChromaKeyParam$1,
|
|
208
|
+
FrameType: FrameType$1,
|
|
175
209
|
MakeupParam: MakeupParam$1,
|
|
176
|
-
|
|
210
|
+
MirrorMode: MirrorMode$1,
|
|
177
211
|
ReshapeParam: ReshapeParam$1,
|
|
178
212
|
VirtualBackgroundOptions: VirtualBackgroundOptions$1
|
|
179
213
|
});
|
|
@@ -211,7 +245,7 @@ class BeautyEffectEngine {
|
|
|
211
245
|
throw new FacebetterError('Platform API is required');
|
|
212
246
|
}
|
|
213
247
|
|
|
214
|
-
//
|
|
248
|
+
// If an EngineConfig instance is passed, use it directly; otherwise create a new EngineConfig
|
|
215
249
|
let engineConfig;
|
|
216
250
|
if (config instanceof EngineConfig) {
|
|
217
251
|
engineConfig = config;
|
|
@@ -229,20 +263,23 @@ class BeautyEffectEngine {
|
|
|
229
263
|
this.appId = engineConfig.appId;
|
|
230
264
|
this.appKey = engineConfig.appKey;
|
|
231
265
|
this.licenseJson = engineConfig.licenseJson;
|
|
232
|
-
this.resourcePath = '/
|
|
266
|
+
this.resourcePath = '/resource.fbd';
|
|
233
267
|
this.enginePtr = null;
|
|
234
268
|
this.initialized = false;
|
|
235
269
|
this.srcBufferPtr = null;
|
|
236
270
|
this.dstBufferPtr = null;
|
|
237
271
|
this.bufferSize = 0;
|
|
238
272
|
|
|
273
|
+
// Callback related state
|
|
274
|
+
this._callbackSharedBufferPtr = null;
|
|
275
|
+
this._callbackSharedBufferSize = 0;
|
|
276
|
+
|
|
239
277
|
// Store platform API
|
|
240
278
|
this._platformAPI = platformAPI;
|
|
241
279
|
this._loadWasmModule = platformAPI.loadWasmModule;
|
|
242
280
|
this._getWasmModule = platformAPI.getWasmModule;
|
|
243
281
|
this._getWasmBuffer = platformAPI.getWasmBuffer;
|
|
244
282
|
this._toImageData = platformAPI.toImageData;
|
|
245
|
-
this._verifyAppKeyOnline = platformAPI.verifyAppKeyOnline;
|
|
246
283
|
this._ensureGPUPixelCanvas = platformAPI.ensureGPUPixelCanvas;
|
|
247
284
|
this._cleanupGPUPixelCanvas = platformAPI.cleanupGPUPixelCanvas;
|
|
248
285
|
|
|
@@ -320,23 +357,22 @@ class BeautyEffectEngine {
|
|
|
320
357
|
* @returns {Promise<void>} Promise that resolves when initialization is complete
|
|
321
358
|
*/
|
|
322
359
|
async init(options = {}) {
|
|
323
|
-
//
|
|
360
|
+
// Concurrency control: if already initialized, return immediately
|
|
324
361
|
if (this.initialized) {
|
|
325
362
|
return;
|
|
326
363
|
}
|
|
327
364
|
|
|
328
|
-
//
|
|
365
|
+
// Concurrency control: if initialization is in progress, return the same Promise
|
|
329
366
|
if (this._initPromise) {
|
|
330
367
|
return this._initPromise;
|
|
331
368
|
}
|
|
332
369
|
|
|
333
|
-
//
|
|
370
|
+
// Create initialization Promise
|
|
334
371
|
this._initPromise = (async () => {
|
|
335
372
|
try {
|
|
336
373
|
const wasmTimeout = options.timeout || 30000;
|
|
337
|
-
const authTimeout = options.authTimeout || 10000;
|
|
338
374
|
|
|
339
|
-
//
|
|
375
|
+
// Wait for WASM module loading (with timeout)
|
|
340
376
|
try {
|
|
341
377
|
await Promise.race([
|
|
342
378
|
this._wasmLoadPromise,
|
|
@@ -348,48 +384,60 @@ class BeautyEffectEngine {
|
|
|
348
384
|
|
|
349
385
|
const Module = this._getWasmModule();
|
|
350
386
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
);
|
|
387
|
+
// Setup usage report proxy for WASM
|
|
388
|
+
if (!Module.onReportUsage) {
|
|
389
|
+
Module.onReportUsage = async (payloadJson) => {
|
|
390
|
+
try {
|
|
391
|
+
const url = 'https://facebetter.pixpark.net/facebetter/v1/report';
|
|
392
|
+
const response = await fetch(url, {
|
|
393
|
+
method: 'POST',
|
|
394
|
+
headers: {
|
|
395
|
+
'Content-Type': 'application/json'
|
|
396
|
+
},
|
|
397
|
+
body: payloadJson
|
|
398
|
+
});
|
|
399
|
+
return response.ok;
|
|
400
|
+
} catch (error) {
|
|
401
|
+
return false;
|
|
367
402
|
}
|
|
403
|
+
};
|
|
404
|
+
}
|
|
368
405
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
406
|
+
// Setup online auth proxy for WASM
|
|
407
|
+
if (!Module.onOnlineAuth) {
|
|
408
|
+
Module.onOnlineAuth = async (payloadJson) => {
|
|
409
|
+
try {
|
|
410
|
+
const url = 'https://facebetter.pixpark.net/facebetter/v1/auth';
|
|
411
|
+
const response = await fetch(url, {
|
|
412
|
+
method: 'POST',
|
|
413
|
+
headers: {
|
|
414
|
+
'Content-Type': 'application/json'
|
|
415
|
+
},
|
|
416
|
+
body: payloadJson
|
|
417
|
+
});
|
|
418
|
+
if (!response.ok) {
|
|
419
|
+
console.warn('[JS Engine] Online auth fetch failed with status:', response.status);
|
|
420
|
+
return "";
|
|
421
|
+
}
|
|
422
|
+
return await response.text();
|
|
423
|
+
} catch (error) {
|
|
424
|
+
console.error('[JS Engine] Online auth fetch exception:', error);
|
|
425
|
+
return "";
|
|
378
426
|
}
|
|
379
|
-
|
|
380
|
-
}
|
|
427
|
+
};
|
|
381
428
|
}
|
|
382
429
|
|
|
383
|
-
//
|
|
384
|
-
// 如果通过 appId/appKey 获取到了响应,则使用响应作为 licenseJson
|
|
385
|
-
// WASM 层只需要验证 licenseJson,不需要发送 HTTP 请求
|
|
430
|
+
// Create engine instance, auth (online/offline) is handled by WASM layer via onOnlineAuth
|
|
386
431
|
const enginePtr = Module.ccall(
|
|
387
|
-
'
|
|
432
|
+
'CreateBeautyEffectEngineEx',
|
|
388
433
|
'number',
|
|
389
|
-
['string', 'string'],
|
|
434
|
+
['string', 'string', 'string', 'string', 'number'],
|
|
390
435
|
[
|
|
391
436
|
this.resourcePath,
|
|
392
|
-
|
|
437
|
+
this.licenseJson || '',
|
|
438
|
+
this.appId || '',
|
|
439
|
+
this.appKey || '',
|
|
440
|
+
this.config.externalContext ? 1 : 0
|
|
393
441
|
]
|
|
394
442
|
);
|
|
395
443
|
|
|
@@ -402,9 +450,9 @@ class BeautyEffectEngine {
|
|
|
402
450
|
|
|
403
451
|
this.enginePtr = enginePtr;
|
|
404
452
|
this.initialized = true;
|
|
405
|
-
this._initPromise = null; //
|
|
453
|
+
this._initPromise = null; // Clear Promise cache, allow re-initialization (if needed)
|
|
406
454
|
} catch (error) {
|
|
407
|
-
this._initPromise = null; //
|
|
455
|
+
this._initPromise = null; // Clear Promise cache, allow retry
|
|
408
456
|
throw error;
|
|
409
457
|
}
|
|
410
458
|
})();
|
|
@@ -432,11 +480,18 @@ class BeautyEffectEngine {
|
|
|
432
480
|
this.dstBufferPtr = null;
|
|
433
481
|
}
|
|
434
482
|
|
|
483
|
+
// Clean up shared memory
|
|
484
|
+
if (this._callbackSharedBufferPtr) {
|
|
485
|
+
Module._free(this._callbackSharedBufferPtr);
|
|
486
|
+
this._callbackSharedBufferPtr = null;
|
|
487
|
+
this._callbackSharedBufferSize = 0;
|
|
488
|
+
}
|
|
489
|
+
|
|
435
490
|
Module.ccall('DestroyBeautyEffectEngine', null, ['number'], [this.enginePtr]);
|
|
436
491
|
this.enginePtr = null;
|
|
437
492
|
this.initialized = false;
|
|
438
493
|
this.bufferSize = 0;
|
|
439
|
-
this._initPromise = null; //
|
|
494
|
+
this._initPromise = null; // Clear initialization Promise
|
|
440
495
|
|
|
441
496
|
// Clean up offscreen canvas
|
|
442
497
|
if (this._offscreenCanvas) {
|
|
@@ -541,7 +596,7 @@ class BeautyEffectEngine {
|
|
|
541
596
|
|
|
542
597
|
/**
|
|
543
598
|
* Sets a basic beauty parameter
|
|
544
|
-
* @param {number} param - Parameter (use BasicParam enum)
|
|
599
|
+
* @param {number} param - Parameter (use BasicParam enum, e.g., BasicParam.Smoothing)
|
|
545
600
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
546
601
|
*/
|
|
547
602
|
setBasicParam(param, value) {
|
|
@@ -551,7 +606,7 @@ class BeautyEffectEngine {
|
|
|
551
606
|
|
|
552
607
|
/**
|
|
553
608
|
* Sets a reshape parameter
|
|
554
|
-
* @param {number} param - Parameter (use ReshapeParam enum)
|
|
609
|
+
* @param {number} param - Parameter (use ReshapeParam enum, e.g., ReshapeParam.FaceThinning)
|
|
555
610
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
556
611
|
*/
|
|
557
612
|
setReshapeParam(param, value) {
|
|
@@ -561,7 +616,7 @@ class BeautyEffectEngine {
|
|
|
561
616
|
|
|
562
617
|
/**
|
|
563
618
|
* Sets a makeup parameter
|
|
564
|
-
* @param {number} param - Parameter (use MakeupParam enum)
|
|
619
|
+
* @param {number} param - Parameter (use MakeupParam enum, e.g., MakeupParam.Lipstick)
|
|
565
620
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
566
621
|
*/
|
|
567
622
|
setMakeupParam(param, value) {
|
|
@@ -570,7 +625,253 @@ class BeautyEffectEngine {
|
|
|
570
625
|
}
|
|
571
626
|
|
|
572
627
|
/**
|
|
573
|
-
*
|
|
628
|
+
* Sets chroma key parameter
|
|
629
|
+
* @param {number} param - Parameter (use ChromaKeyParam enum, e.g., ChromaKeyParam.Similarity)
|
|
630
|
+
* @param {number} value - Parameter value (KeyColor: 0.0=Green, 1.0=Blue, 2.0=Red; others 0.0-1.0)
|
|
631
|
+
*/
|
|
632
|
+
setChromaKeyParam(param, value) {
|
|
633
|
+
this._ensureInitialized();
|
|
634
|
+
// For KeyColor, values are 0, 1, 2, not 0.0-1.0
|
|
635
|
+
if (param === 0) { // ChromaKeyParam.KeyColor
|
|
636
|
+
const Module = this._getWasmModule();
|
|
637
|
+
const result = Module.ccall(
|
|
638
|
+
'SetBeautyParamChromaKey',
|
|
639
|
+
'number',
|
|
640
|
+
['number', 'number', 'number'],
|
|
641
|
+
[this.enginePtr, param, value]
|
|
642
|
+
);
|
|
643
|
+
checkResult(result, `Failed to set chroma key parameter`);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
this._setBeautyParam('SetBeautyParamChromaKey', param, value);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Sets a LUT-based filter
|
|
651
|
+
* @param {string} filterId - Unique identifier of the filter (e.g., "chuxin"). Pass "" to clear.
|
|
652
|
+
*/
|
|
653
|
+
setFilter(filterId) {
|
|
654
|
+
this._ensureInitialized();
|
|
655
|
+
const Module = this._getWasmModule();
|
|
656
|
+
const result = Module.ccall(
|
|
657
|
+
'SetFilter',
|
|
658
|
+
'number',
|
|
659
|
+
['number', 'string'],
|
|
660
|
+
[this.enginePtr, filterId || '']
|
|
661
|
+
);
|
|
662
|
+
checkResult(result, 'Failed to set filter');
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Sets the intensity of the current filter
|
|
667
|
+
* @param {number} intensity - Filter intensity (0.0 - 1.0)
|
|
668
|
+
*/
|
|
669
|
+
setFilterIntensity(intensity) {
|
|
670
|
+
this._ensureInitialized();
|
|
671
|
+
const Module = this._getWasmModule();
|
|
672
|
+
const result = Module.ccall(
|
|
673
|
+
'SetFilterIntensity',
|
|
674
|
+
'number',
|
|
675
|
+
['number', 'number'],
|
|
676
|
+
[this.enginePtr, intensity]
|
|
677
|
+
);
|
|
678
|
+
checkResult(result, 'Failed to set filter intensity');
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
/**
|
|
682
|
+
* Sets a 2D sticker
|
|
683
|
+
* @param {string} stickerId - Unique identifier of the sticker (e.g., "樱花"). Pass "" to clear.
|
|
684
|
+
*/
|
|
685
|
+
setSticker(stickerId) {
|
|
686
|
+
this._ensureInitialized();
|
|
687
|
+
const Module = this._getWasmModule();
|
|
688
|
+
const result = Module.ccall(
|
|
689
|
+
'SetSticker',
|
|
690
|
+
'number',
|
|
691
|
+
['number', 'string'],
|
|
692
|
+
[this.enginePtr, stickerId || '']
|
|
693
|
+
);
|
|
694
|
+
checkResult(result, 'Failed to set sticker');
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Registers a filter from a file path or data
|
|
699
|
+
* @param {string} filterId - Unique identifier for the filter
|
|
700
|
+
* @param {string|Uint8Array} resource - Path to .fbd file or Uint8Array data
|
|
701
|
+
*/
|
|
702
|
+
registerFilter(filterId, resource) {
|
|
703
|
+
this._ensureInitialized();
|
|
704
|
+
const Module = this._getWasmModule();
|
|
705
|
+
|
|
706
|
+
if (typeof resource === 'string') {
|
|
707
|
+
const result = Module.ccall(
|
|
708
|
+
'RegisterFilterPath',
|
|
709
|
+
'number',
|
|
710
|
+
['number', 'string', 'string'],
|
|
711
|
+
[this.enginePtr, filterId, resource]
|
|
712
|
+
);
|
|
713
|
+
checkResult(result, `Failed to register filter path: ${filterId}`);
|
|
714
|
+
} else if (resource instanceof Uint8Array) {
|
|
715
|
+
const dataPtr = Module._malloc(resource.length);
|
|
716
|
+
Module.HEAPU8.set(resource, dataPtr);
|
|
717
|
+
try {
|
|
718
|
+
const result = Module.ccall(
|
|
719
|
+
'RegisterFilterData',
|
|
720
|
+
'number',
|
|
721
|
+
['number', 'string', 'number', 'number'],
|
|
722
|
+
[this.enginePtr, filterId, dataPtr, resource.length]
|
|
723
|
+
);
|
|
724
|
+
checkResult(result, `Failed to register filter data: ${filterId}`);
|
|
725
|
+
} finally {
|
|
726
|
+
Module._free(dataPtr);
|
|
727
|
+
}
|
|
728
|
+
} else {
|
|
729
|
+
throw new FacebetterError('Resource must be a string path or Uint8Array data');
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Registers a sticker from a file path or data
|
|
735
|
+
* @param {string} stickerId - Unique identifier for the sticker
|
|
736
|
+
* @param {string|Uint8Array} resource - Path to .fbd file or Uint8Array data
|
|
737
|
+
*/
|
|
738
|
+
registerSticker(stickerId, resource) {
|
|
739
|
+
this._ensureInitialized();
|
|
740
|
+
const Module = this._getWasmModule();
|
|
741
|
+
|
|
742
|
+
if (typeof resource === 'string') {
|
|
743
|
+
const result = Module.ccall(
|
|
744
|
+
'RegisterStickerPath',
|
|
745
|
+
'number',
|
|
746
|
+
['number', 'string', 'string'],
|
|
747
|
+
[this.enginePtr, stickerId, resource]
|
|
748
|
+
);
|
|
749
|
+
checkResult(result, `Failed to register sticker path: ${stickerId}`);
|
|
750
|
+
} else if (resource instanceof Uint8Array) {
|
|
751
|
+
const dataPtr = Module._malloc(resource.length);
|
|
752
|
+
Module.HEAPU8.set(resource, dataPtr);
|
|
753
|
+
try {
|
|
754
|
+
const result = Module.ccall(
|
|
755
|
+
'RegisterStickerData',
|
|
756
|
+
'number',
|
|
757
|
+
['number', 'string', 'number', 'number'],
|
|
758
|
+
[this.enginePtr, stickerId, dataPtr, resource.length]
|
|
759
|
+
);
|
|
760
|
+
checkResult(result, `Failed to register sticker data: ${stickerId}`);
|
|
761
|
+
} finally {
|
|
762
|
+
Module._free(dataPtr);
|
|
763
|
+
}
|
|
764
|
+
} else {
|
|
765
|
+
throw new FacebetterError('Resource must be a string path or Uint8Array data');
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/**
|
|
770
|
+
* Unregisters a specific filter
|
|
771
|
+
* @param {string} filterId - Filter ID to unregister
|
|
772
|
+
*/
|
|
773
|
+
unregisterFilter(filterId) {
|
|
774
|
+
this._ensureInitialized();
|
|
775
|
+
const Module = this._getWasmModule();
|
|
776
|
+
const result = Module.ccall(
|
|
777
|
+
'UnregisterFilter',
|
|
778
|
+
'number',
|
|
779
|
+
['number', 'string'],
|
|
780
|
+
[this.enginePtr, filterId]
|
|
781
|
+
);
|
|
782
|
+
checkResult(result, `Failed to unregister filter: ${filterId}`);
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/**
|
|
786
|
+
* Unregisters all filters
|
|
787
|
+
*/
|
|
788
|
+
unregisterAllFilters() {
|
|
789
|
+
this._ensureInitialized();
|
|
790
|
+
const Module = this._getWasmModule();
|
|
791
|
+
const result = Module.ccall(
|
|
792
|
+
'UnregisterAllFilters',
|
|
793
|
+
'number',
|
|
794
|
+
['number'],
|
|
795
|
+
[this.enginePtr]
|
|
796
|
+
);
|
|
797
|
+
checkResult(result, 'Failed to unregister all filters');
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Unregisters a specific sticker
|
|
802
|
+
* @param {string} stickerId - Sticker ID to unregister
|
|
803
|
+
*/
|
|
804
|
+
unregisterSticker(stickerId) {
|
|
805
|
+
this._ensureInitialized();
|
|
806
|
+
const Module = this._getWasmModule();
|
|
807
|
+
const result = Module.ccall(
|
|
808
|
+
'UnregisterSticker',
|
|
809
|
+
'number',
|
|
810
|
+
['number', 'string'],
|
|
811
|
+
[this.enginePtr, stickerId]
|
|
812
|
+
);
|
|
813
|
+
checkResult(result, `Failed to unregister sticker: ${stickerId}`);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* Unregisters all stickers
|
|
818
|
+
*/
|
|
819
|
+
unregisterAllStickers() {
|
|
820
|
+
this._ensureInitialized();
|
|
821
|
+
const Module = this._getWasmModule();
|
|
822
|
+
const result = Module.ccall(
|
|
823
|
+
'UnregisterAllStickers',
|
|
824
|
+
'number',
|
|
825
|
+
['number'],
|
|
826
|
+
[this.enginePtr]
|
|
827
|
+
);
|
|
828
|
+
checkResult(result, 'Failed to unregister all stickers');
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/**
|
|
832
|
+
* Gets the list of registered filter IDs
|
|
833
|
+
* @returns {string[]} Array of registered filter IDs
|
|
834
|
+
*/
|
|
835
|
+
getRegisteredFilters() {
|
|
836
|
+
this._ensureInitialized();
|
|
837
|
+
const Module = this._getWasmModule();
|
|
838
|
+
const jsonStr = Module.ccall(
|
|
839
|
+
'GetRegisteredFilters',
|
|
840
|
+
'string',
|
|
841
|
+
['number'],
|
|
842
|
+
[this.enginePtr]
|
|
843
|
+
);
|
|
844
|
+
try {
|
|
845
|
+
return JSON.parse(jsonStr || '[]');
|
|
846
|
+
} catch (e) {
|
|
847
|
+
console.error('Failed to parse registered filters JSON:', e);
|
|
848
|
+
return [];
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Gets the list of registered sticker IDs
|
|
854
|
+
* @returns {string[]} Array of registered sticker IDs
|
|
855
|
+
*/
|
|
856
|
+
getRegisteredStickers() {
|
|
857
|
+
this._ensureInitialized();
|
|
858
|
+
const Module = this._getWasmModule();
|
|
859
|
+
const jsonStr = Module.ccall(
|
|
860
|
+
'GetRegisteredStickers',
|
|
861
|
+
'string',
|
|
862
|
+
['number'],
|
|
863
|
+
[this.enginePtr]
|
|
864
|
+
);
|
|
865
|
+
try {
|
|
866
|
+
return JSON.parse(jsonStr || '[]');
|
|
867
|
+
} catch (e) {
|
|
868
|
+
console.error('Failed to parse registered stickers JSON:', e);
|
|
869
|
+
return [];
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
/**
|
|
874
|
+
* Internal method to set beauty parameters
|
|
574
875
|
* @private
|
|
575
876
|
*/
|
|
576
877
|
_setBeautyParam(functionName, param, value) {
|
|
@@ -589,6 +890,139 @@ class BeautyEffectEngine {
|
|
|
589
890
|
checkResult(result, `Failed to set beauty parameter`);
|
|
590
891
|
}
|
|
591
892
|
|
|
893
|
+
/**
|
|
894
|
+
* Sets engine callbacks (face landmarks detection)
|
|
895
|
+
* @param {Object} callbacks - Callback functions
|
|
896
|
+
* @param {Function} callbacks.onFaceLandmarks - Callback for face landmarks detection
|
|
897
|
+
* @param {number} [callbacks.maxFaces=10] - Maximum number of faces to support (affects shared buffer size)
|
|
898
|
+
*/
|
|
899
|
+
setCallbacks(callbacks) {
|
|
900
|
+
this._ensureInitialized();
|
|
901
|
+
const Module = this._getWasmModule();
|
|
902
|
+
|
|
903
|
+
// Initialize callback storage (if it doesn't exist)
|
|
904
|
+
if (!Module._face_landmarks_callbacks) {
|
|
905
|
+
Module._face_landmarks_callbacks = [];
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
let callbackId = 0;
|
|
909
|
+
let sharedBufferPtr = null;
|
|
910
|
+
let sharedBufferSize = 0;
|
|
911
|
+
|
|
912
|
+
if (callbacks && callbacks.onFaceLandmarks) {
|
|
913
|
+
// Get max faces (default 10)
|
|
914
|
+
const maxFaces = callbacks.maxFaces || 10;
|
|
915
|
+
|
|
916
|
+
// Pre-allocate shared memory
|
|
917
|
+
// Metadata: 2 ints (frame_number, face_count) = 8 bytes
|
|
918
|
+
// Face data: maxFaces * 343 floats * 4 bytes = maxFaces * 1372 bytes
|
|
919
|
+
const metadataSize = 2 * 4; // 2 ints
|
|
920
|
+
const faceDataSize = maxFaces * 343 * 4; // 343 floats per face
|
|
921
|
+
sharedBufferSize = metadataSize + faceDataSize;
|
|
922
|
+
sharedBufferPtr = Module._malloc(sharedBufferSize);
|
|
923
|
+
|
|
924
|
+
if (!sharedBufferPtr) {
|
|
925
|
+
throw new FacebetterError('Failed to allocate shared buffer for callbacks');
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// Register callback function (internal wrapper, reads data from shared memory)
|
|
929
|
+
// Push first, then get index as callbackId (allows callbackId to be 0)
|
|
930
|
+
Module._face_landmarks_callbacks.push(
|
|
931
|
+
(frameNumber, faceCount, dataPtr) => {
|
|
932
|
+
// Read data from shared memory (zero-copy)
|
|
933
|
+
const heap = Module.HEAPF32;
|
|
934
|
+
const dataOffset = dataPtr / 4; // float is 4 bytes
|
|
935
|
+
|
|
936
|
+
const results = [];
|
|
937
|
+
const FLOATS_PER_FACE = 343;
|
|
938
|
+
|
|
939
|
+
for (let i = 0; i < faceCount; i++) {
|
|
940
|
+
const faceOffset = dataOffset + i * FLOATS_PER_FACE;
|
|
941
|
+
let offset = faceOffset;
|
|
942
|
+
|
|
943
|
+
// Read rect
|
|
944
|
+
const rect = {
|
|
945
|
+
x: heap[offset++],
|
|
946
|
+
y: heap[offset++],
|
|
947
|
+
width: heap[offset++],
|
|
948
|
+
height: heap[offset++]
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
// Read basic fields
|
|
952
|
+
const faceId = Math.round(heap[offset++]);
|
|
953
|
+
const faceAction = Math.round(heap[offset++]);
|
|
954
|
+
const score = heap[offset++];
|
|
955
|
+
const pitch = heap[offset++];
|
|
956
|
+
const roll = heap[offset++];
|
|
957
|
+
const yaw = heap[offset++];
|
|
958
|
+
|
|
959
|
+
// Read key_points (111 points)
|
|
960
|
+
const keyPoints = [];
|
|
961
|
+
for (let j = 0; j < 111; j++) {
|
|
962
|
+
keyPoints.push({
|
|
963
|
+
x: heap[offset++],
|
|
964
|
+
y: heap[offset++]
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Read visibility (111 points)
|
|
969
|
+
const visibility = [];
|
|
970
|
+
for (let j = 0; j < 111; j++) {
|
|
971
|
+
visibility.push(heap[offset++]);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
results.push({
|
|
975
|
+
rect,
|
|
976
|
+
key_points: keyPoints,
|
|
977
|
+
visibility,
|
|
978
|
+
face_id: faceId,
|
|
979
|
+
face_action: faceAction,
|
|
980
|
+
score,
|
|
981
|
+
pitch,
|
|
982
|
+
roll,
|
|
983
|
+
yaw
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Call user callback
|
|
988
|
+
callbacks.onFaceLandmarks(results);
|
|
989
|
+
}
|
|
990
|
+
);
|
|
991
|
+
|
|
992
|
+
// Get callback ID (index after push, can be 0)
|
|
993
|
+
callbackId = Module._face_landmarks_callbacks.length - 1;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
// Call C API
|
|
997
|
+
const result = Module.ccall(
|
|
998
|
+
'SetCallbacks',
|
|
999
|
+
'number',
|
|
1000
|
+
['number', 'number', 'number', 'number'],
|
|
1001
|
+
[
|
|
1002
|
+
this.enginePtr,
|
|
1003
|
+
callbackId,
|
|
1004
|
+
sharedBufferPtr || 0,
|
|
1005
|
+
sharedBufferSize
|
|
1006
|
+
]
|
|
1007
|
+
);
|
|
1008
|
+
|
|
1009
|
+
checkResult(result, 'Failed to set callbacks');
|
|
1010
|
+
|
|
1011
|
+
// Clean up old shared memory (if it exists)
|
|
1012
|
+
if (this._callbackSharedBufferPtr) {
|
|
1013
|
+
Module._free(this._callbackSharedBufferPtr);
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
// Store new shared memory pointer for cleanup
|
|
1017
|
+
if (sharedBufferPtr) {
|
|
1018
|
+
this._callbackSharedBufferPtr = sharedBufferPtr;
|
|
1019
|
+
this._callbackSharedBufferSize = sharedBufferSize;
|
|
1020
|
+
} else {
|
|
1021
|
+
this._callbackSharedBufferPtr = null;
|
|
1022
|
+
this._callbackSharedBufferSize = 0;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
|
|
592
1026
|
/**
|
|
593
1027
|
* Sets virtual background options (unified API, matches C++/Java/OC)
|
|
594
1028
|
* @param {VirtualBackgroundOptions|Object} options - Virtual background options
|
|
@@ -606,7 +1040,7 @@ class BeautyEffectEngine {
|
|
|
606
1040
|
let imageBufferPtr = null;
|
|
607
1041
|
|
|
608
1042
|
try {
|
|
609
|
-
//
|
|
1043
|
+
// If a background image is provided, convert to ImageData and prepare buffer
|
|
610
1044
|
if (opts.backgroundImage) {
|
|
611
1045
|
imageData = this._toImageData(opts.backgroundImage);
|
|
612
1046
|
const bufferSize = imageData.width * imageData.height * 4;
|
|
@@ -617,7 +1051,7 @@ class BeautyEffectEngine {
|
|
|
617
1051
|
view.set(imageData.data);
|
|
618
1052
|
}
|
|
619
1053
|
|
|
620
|
-
//
|
|
1054
|
+
// Use unified SetVirtualBackground C interface (consistent with other platforms)
|
|
621
1055
|
const result = Module.ccall(
|
|
622
1056
|
'SetVirtualBackground',
|
|
623
1057
|
'number',
|
|
@@ -625,7 +1059,7 @@ class BeautyEffectEngine {
|
|
|
625
1059
|
[
|
|
626
1060
|
this.enginePtr,
|
|
627
1061
|
opts.mode,
|
|
628
|
-
imageBufferPtr || 0, //
|
|
1062
|
+
imageBufferPtr || 0, // If null, pass 0
|
|
629
1063
|
imageData ? imageData.width : 0,
|
|
630
1064
|
imageData ? imageData.height : 0,
|
|
631
1065
|
imageData ? imageData.width * 4 : 0
|
|
@@ -634,7 +1068,7 @@ class BeautyEffectEngine {
|
|
|
634
1068
|
|
|
635
1069
|
checkResult(result, 'Failed to set virtual background');
|
|
636
1070
|
} finally {
|
|
637
|
-
//
|
|
1071
|
+
// Free memory
|
|
638
1072
|
if (imageBufferPtr) {
|
|
639
1073
|
Module._free(imageBufferPtr);
|
|
640
1074
|
}
|
|
@@ -674,10 +1108,11 @@ class BeautyEffectEngine {
|
|
|
674
1108
|
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Uint8ClampedArray} input - Input image
|
|
675
1109
|
* @param {number} width - Image width (required if input is Uint8ClampedArray)
|
|
676
1110
|
* @param {number} height - Image height (required if input is Uint8ClampedArray)
|
|
677
|
-
* @param {number}
|
|
1111
|
+
* @param {number} frameType - Frame type (use FrameType enum, default: FrameType.Video)
|
|
1112
|
+
* @param {number} mirrorMode - Mirror mode applied to input before processing (MirrorMode enum, default: MirrorMode.None)
|
|
678
1113
|
* @returns {ImageData} Processed image data
|
|
679
1114
|
*/
|
|
680
|
-
processImage(input, width, height,
|
|
1115
|
+
processImage(input, width, height, frameType = FrameType$1.Video, mirrorMode = MirrorMode$1.None) {
|
|
681
1116
|
this._ensureInitialized();
|
|
682
1117
|
const imageData = this._platformAPI.toImageData(input, width, height);
|
|
683
1118
|
const Module = this._getWasmModule();
|
|
@@ -695,7 +1130,7 @@ class BeautyEffectEngine {
|
|
|
695
1130
|
const result = Module.ccall(
|
|
696
1131
|
'ProcessImageRGBA',
|
|
697
1132
|
'number',
|
|
698
|
-
['number', 'number', 'number', 'number', 'number', 'number', 'number'],
|
|
1133
|
+
['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number'],
|
|
699
1134
|
[
|
|
700
1135
|
this.enginePtr,
|
|
701
1136
|
this.srcBufferPtr,
|
|
@@ -703,7 +1138,8 @@ class BeautyEffectEngine {
|
|
|
703
1138
|
imageData.height,
|
|
704
1139
|
imageData.width * 4,
|
|
705
1140
|
this.dstBufferPtr,
|
|
706
|
-
|
|
1141
|
+
frameType,
|
|
1142
|
+
mirrorMode
|
|
707
1143
|
]
|
|
708
1144
|
);
|
|
709
1145
|
|
|
@@ -722,6 +1158,65 @@ class BeautyEffectEngine {
|
|
|
722
1158
|
}
|
|
723
1159
|
}
|
|
724
1160
|
|
|
1161
|
+
/**
|
|
1162
|
+
* Processes an external GPU texture.
|
|
1163
|
+
*
|
|
1164
|
+
* Note:
|
|
1165
|
+
* - This interface is mainly used for integration with internal WASM or advanced scenarios.
|
|
1166
|
+
* - textureHandle must be a texture handle (uint32) compatible with the OpenGL/WebGL context used by WASM.
|
|
1167
|
+
* - For common web scenarios, it is recommended to use processImage with ImageData/Canvas etc.
|
|
1168
|
+
*
|
|
1169
|
+
* @param {number} textureHandle - External texture handle (GL_TEXTURE_2D)
|
|
1170
|
+
* @param {number} width - Texture width
|
|
1171
|
+
* @param {number} height - Texture height
|
|
1172
|
+
* @param {number} stride - Row stride (usually width * 4)
|
|
1173
|
+
* @param {number} [frameType] - Frame type (FrameType.Image / FrameType.Video)
|
|
1174
|
+
* @param {number} [mirrorMode] - Mirror mode (MirrorMode enum; texture path does not support mirror, param reserved)
|
|
1175
|
+
* @returns {number} Processed texture handle (GL_TEXTURE_2D, uint32)
|
|
1176
|
+
*/
|
|
1177
|
+
processTexture(textureHandle,
|
|
1178
|
+
width,
|
|
1179
|
+
height,
|
|
1180
|
+
stride,
|
|
1181
|
+
frameType = FrameType$1.Video,
|
|
1182
|
+
mirrorMode = MirrorMode$1.None) {
|
|
1183
|
+
this._ensureInitialized();
|
|
1184
|
+
if (!textureHandle || width <= 0 || height <= 0 || stride <= 0) {
|
|
1185
|
+
throw new FacebetterError('Invalid textureHandle or dimensions for processTexture');
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
const Module = this._getWasmModule();
|
|
1189
|
+
|
|
1190
|
+
try {
|
|
1191
|
+
const result = Module.ccall(
|
|
1192
|
+
'ProcessImageTexture',
|
|
1193
|
+
'number',
|
|
1194
|
+
['number', 'number', 'number', 'number', 'number', 'number', 'number'],
|
|
1195
|
+
[
|
|
1196
|
+
this.enginePtr,
|
|
1197
|
+
textureHandle,
|
|
1198
|
+
width,
|
|
1199
|
+
height,
|
|
1200
|
+
stride,
|
|
1201
|
+
frameType,
|
|
1202
|
+
mirrorMode
|
|
1203
|
+
]
|
|
1204
|
+
);
|
|
1205
|
+
|
|
1206
|
+
if (!result || result === 0) {
|
|
1207
|
+
throw new FacebetterError('Failed to process external texture or got invalid output texture');
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// Return processed texture handle for caller to continue using in same GL context
|
|
1211
|
+
return result;
|
|
1212
|
+
} catch (error) {
|
|
1213
|
+
if (error instanceof FacebetterError) {
|
|
1214
|
+
throw error;
|
|
1215
|
+
}
|
|
1216
|
+
throw new FacebetterError(`Texture processing error: ${error.message}`);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
725
1220
|
/**
|
|
726
1221
|
* Ensures the engine is initialized
|
|
727
1222
|
* @private
|
|
@@ -842,77 +1337,6 @@ function toImageData(source, width, height) {
|
|
|
842
1337
|
throw new FacebetterError('Unsupported image source type');
|
|
843
1338
|
}
|
|
844
1339
|
|
|
845
|
-
/**
|
|
846
|
-
* Gets User-Agent string for web platform
|
|
847
|
-
* @returns {string} User-Agent string
|
|
848
|
-
*/
|
|
849
|
-
function getUserAgentString() {
|
|
850
|
-
return 'FB/1.0 (web; wasm32)';
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
/**
|
|
854
|
-
* Generates HMAC-SHA256 signature (browser version)
|
|
855
|
-
* @param {string} key - HMAC key (app_key)
|
|
856
|
-
* @param {string} data - Data to sign (timestamp string)
|
|
857
|
-
* @returns {Promise<string>} Promise that resolves with hex-encoded signature
|
|
858
|
-
*/
|
|
859
|
-
async function generateHMACSignature(key, data) {
|
|
860
|
-
const encoder = new TextEncoder();
|
|
861
|
-
const keyData = encoder.encode(key);
|
|
862
|
-
const messageData = encoder.encode(data);
|
|
863
|
-
|
|
864
|
-
const cryptoKey = await crypto.subtle.importKey(
|
|
865
|
-
'raw',
|
|
866
|
-
keyData,
|
|
867
|
-
{ name: 'HMAC', hash: 'SHA-256' },
|
|
868
|
-
false,
|
|
869
|
-
['sign']
|
|
870
|
-
);
|
|
871
|
-
|
|
872
|
-
const signature = await crypto.subtle.sign('HMAC', cryptoKey, messageData);
|
|
873
|
-
|
|
874
|
-
// Convert to hex string
|
|
875
|
-
const hashArray = Array.from(new Uint8Array(signature));
|
|
876
|
-
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
877
|
-
return hashHex;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/**
|
|
881
|
-
* Calls online_auth API to verify app_key (browser version)
|
|
882
|
-
* @param {string} appId - Application ID
|
|
883
|
-
* @param {string} appKey - Application key
|
|
884
|
-
* @returns {Promise<Object>} Promise that resolves with response data
|
|
885
|
-
*/
|
|
886
|
-
async function verifyAppKeyOnline(appId, appKey) {
|
|
887
|
-
try {
|
|
888
|
-
const timestamp = Math.floor(Date.now() / 1000);
|
|
889
|
-
const timestampStr = timestamp.toString();
|
|
890
|
-
const hmacSignature = await generateHMACSignature(appKey, timestampStr);
|
|
891
|
-
|
|
892
|
-
const requestBody = {
|
|
893
|
-
p_app_id: appId,
|
|
894
|
-
p_hmac_signature: hmacSignature,
|
|
895
|
-
p_timestamp: timestamp,
|
|
896
|
-
p_user_agent: getUserAgentString()
|
|
897
|
-
};
|
|
898
|
-
|
|
899
|
-
const response = await fetch('https://facebetter.pixpark.net/rest/v1/rpc/online_auth', {
|
|
900
|
-
method: 'POST',
|
|
901
|
-
headers: {
|
|
902
|
-
'Content-Type': 'application/json',
|
|
903
|
-
'User-Agent': getUserAgentString()
|
|
904
|
-
},
|
|
905
|
-
body: JSON.stringify(requestBody)
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
const responseData = await response.json();
|
|
909
|
-
return responseData;
|
|
910
|
-
} catch (error) {
|
|
911
|
-
console.error('Online auth request failed:', error);
|
|
912
|
-
return null;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
|
|
916
1340
|
/**
|
|
917
1341
|
* ESM Entry Point
|
|
918
1342
|
* For Vue/React/Vite/Webpack (ES Module)
|
|
@@ -1054,7 +1478,6 @@ const platformAPI = {
|
|
|
1054
1478
|
getWasmModule,
|
|
1055
1479
|
getWasmBuffer,
|
|
1056
1480
|
toImageData: toImageData,
|
|
1057
|
-
verifyAppKeyOnline: verifyAppKeyOnline,
|
|
1058
1481
|
ensureGPUPixelCanvas,
|
|
1059
1482
|
cleanupGPUPixelCanvas
|
|
1060
1483
|
};
|
|
@@ -1078,8 +1501,10 @@ const BeautyType = BeautyType$1;
|
|
|
1078
1501
|
const BasicParam = BasicParam$1;
|
|
1079
1502
|
const ReshapeParam = ReshapeParam$1;
|
|
1080
1503
|
const MakeupParam = MakeupParam$1;
|
|
1504
|
+
const ChromaKeyParam = ChromaKeyParam$1;
|
|
1081
1505
|
const BackgroundMode = BackgroundMode$1;
|
|
1082
|
-
const
|
|
1506
|
+
const FrameType = FrameType$1;
|
|
1507
|
+
const MirrorMode = MirrorMode$1;
|
|
1083
1508
|
const VirtualBackgroundOptions = VirtualBackgroundOptions$1;
|
|
1084
1509
|
|
|
1085
1510
|
// Default export
|
|
@@ -1091,5 +1516,5 @@ var index = {
|
|
|
1091
1516
|
loadWasmModule
|
|
1092
1517
|
};
|
|
1093
1518
|
|
|
1094
|
-
export { BackgroundMode, BasicParam, ESMBeautyEffectEngine as BeautyEffectEngine, BeautyType, EngineConfig, FacebetterError, MakeupParam,
|
|
1519
|
+
export { BackgroundMode, BasicParam, ESMBeautyEffectEngine as BeautyEffectEngine, BeautyType, ChromaKeyParam, EngineConfig, FacebetterError, FrameType, MakeupParam, MirrorMode, ReshapeParam, VirtualBackgroundOptions, createBeautyEffectEngine, index as default, getWasmBuffer, getWasmModule, loadWasmModule };
|
|
1095
1520
|
//# sourceMappingURL=facebetter.esm.js.map
|