facebetter 1.0.14 → 1.1.0
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 +349 -85
- package/dist/facebetter.esm.js.map +1 -1
- package/dist/facebetter.js +348 -85
- package/dist/facebetter.js.map +1 -1
- package/package.json +2 -2
package/dist/facebetter.esm.js
CHANGED
|
@@ -48,6 +48,12 @@ class EngineConfig {
|
|
|
48
48
|
this.appKey = config.appKey || null;
|
|
49
49
|
this.licenseJson = config.licenseJson || null;
|
|
50
50
|
this.resourcePath = '/facebetter/resource.bundle';
|
|
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,75 @@ 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)
|
|
89
96
|
};
|
|
90
97
|
|
|
91
98
|
/**
|
|
92
99
|
* Basic beauty parameter enumeration
|
|
100
|
+
* All values should be in range [0.0, 1.0]
|
|
93
101
|
*/
|
|
94
102
|
const BasicParam$1 = {
|
|
95
|
-
Smoothing: 0, //
|
|
96
|
-
Sharpening: 1,
|
|
97
|
-
Whitening: 2, //
|
|
98
|
-
Rosiness: 3 //
|
|
103
|
+
Smoothing: 0, // Skin smoothing (0.0: none, 1.0: maximum)
|
|
104
|
+
Sharpening: 1, // Image sharpening (0.0: none, 1.0: maximum)
|
|
105
|
+
Whitening: 2, // Skin whitening (0.0: none, 1.0: maximum)
|
|
106
|
+
Rosiness: 3 // Skin rosiness (0.0: none, 1.0: maximum)
|
|
99
107
|
};
|
|
100
108
|
|
|
101
109
|
/**
|
|
102
110
|
* Face reshape parameter enumeration
|
|
111
|
+
* All values should be in range [0.0, 1.0]
|
|
103
112
|
*/
|
|
104
113
|
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
|
|
114
|
+
FaceThinning: 0, // Face thinning (0.0: none, 1.0: maximum)
|
|
115
|
+
FaceVShape: 1, // V-shape face (0.0: none, 1.0: maximum)
|
|
116
|
+
FaceNarrowing: 2, // Face narrowing (0.0: none, 1.0: maximum)
|
|
117
|
+
FaceShortening: 3,// Face shortening (0.0: none, 1.0: maximum)
|
|
118
|
+
Cheekbone: 4, // Cheekbone slimming (0.0: none, 1.0: maximum)
|
|
119
|
+
Jawbone: 5, // Jawbone slimming (0.0: none, 1.0: maximum)
|
|
120
|
+
Chin: 6, // Chin length adjustment (0.0: none, 1.0: maximum)
|
|
121
|
+
NoseSlimming: 7, // Nose slimming (0.0: none, 1.0: maximum)
|
|
122
|
+
EyeSize: 8, // Eye size (0.0: normal, 1.0: maximum)
|
|
123
|
+
EyeDistance: 9 // Eye distance (0.0: normal, 1.0: maximum)
|
|
115
124
|
};
|
|
116
125
|
|
|
117
126
|
/**
|
|
118
127
|
* Makeup parameter enumeration
|
|
128
|
+
* All values should be in range [0.0, 1.0]
|
|
119
129
|
*/
|
|
120
130
|
const MakeupParam$1 = {
|
|
121
|
-
Lipstick: 0, //
|
|
122
|
-
Blush: 1 //
|
|
131
|
+
Lipstick: 0, // Lipstick intensity (0.0: none, 1.0: maximum)
|
|
132
|
+
Blush: 1 // Blush intensity (0.0: none, 1.0: maximum)
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Chroma Key parameter enumeration
|
|
137
|
+
*/
|
|
138
|
+
const ChromaKeyParam$1 = {
|
|
139
|
+
KeyColor: 0, // Key color (0.0: Green, 1.0: Blue, 2.0: Red)
|
|
140
|
+
Similarity: 1, // Color similarity (0.0 - 1.0)
|
|
141
|
+
Smoothness: 2, // Edge smoothness (0.0 - 1.0)
|
|
142
|
+
Desaturation: 3 // Spill desaturation (0.0 - 1.0)
|
|
123
143
|
};
|
|
124
144
|
|
|
125
145
|
/**
|
|
126
146
|
* Background mode enumeration
|
|
127
147
|
*/
|
|
128
148
|
const BackgroundMode$1 = {
|
|
129
|
-
None: 0, //
|
|
130
|
-
Blur: 1, //
|
|
131
|
-
Image: 2 //
|
|
149
|
+
None: 0, // No background processing
|
|
150
|
+
Blur: 1, // Blurred background
|
|
151
|
+
Image: 2 // Background image replacement
|
|
132
152
|
};
|
|
133
153
|
|
|
134
154
|
/**
|
|
135
|
-
*
|
|
155
|
+
* Frame type enumeration
|
|
136
156
|
*/
|
|
137
|
-
const
|
|
138
|
-
Image: 0, //
|
|
139
|
-
Video: 1 //
|
|
157
|
+
const FrameType$1 = {
|
|
158
|
+
Image: 0, // Image mode
|
|
159
|
+
Video: 1 // Video mode
|
|
140
160
|
};
|
|
141
161
|
|
|
142
162
|
/**
|
|
@@ -172,8 +192,9 @@ var constants = /*#__PURE__*/Object.freeze({
|
|
|
172
192
|
BackgroundMode: BackgroundMode$1,
|
|
173
193
|
BasicParam: BasicParam$1,
|
|
174
194
|
BeautyType: BeautyType$1,
|
|
195
|
+
ChromaKeyParam: ChromaKeyParam$1,
|
|
196
|
+
FrameType: FrameType$1,
|
|
175
197
|
MakeupParam: MakeupParam$1,
|
|
176
|
-
ProcessMode: ProcessMode$1,
|
|
177
198
|
ReshapeParam: ReshapeParam$1,
|
|
178
199
|
VirtualBackgroundOptions: VirtualBackgroundOptions$1
|
|
179
200
|
});
|
|
@@ -211,7 +232,7 @@ class BeautyEffectEngine {
|
|
|
211
232
|
throw new FacebetterError('Platform API is required');
|
|
212
233
|
}
|
|
213
234
|
|
|
214
|
-
//
|
|
235
|
+
// If an EngineConfig instance is passed, use it directly; otherwise create a new EngineConfig
|
|
215
236
|
let engineConfig;
|
|
216
237
|
if (config instanceof EngineConfig) {
|
|
217
238
|
engineConfig = config;
|
|
@@ -236,6 +257,10 @@ class BeautyEffectEngine {
|
|
|
236
257
|
this.dstBufferPtr = null;
|
|
237
258
|
this.bufferSize = 0;
|
|
238
259
|
|
|
260
|
+
// Callback related state
|
|
261
|
+
this._callbackSharedBufferPtr = null;
|
|
262
|
+
this._callbackSharedBufferSize = 0;
|
|
263
|
+
|
|
239
264
|
// Store platform API
|
|
240
265
|
this._platformAPI = platformAPI;
|
|
241
266
|
this._loadWasmModule = platformAPI.loadWasmModule;
|
|
@@ -320,23 +345,22 @@ class BeautyEffectEngine {
|
|
|
320
345
|
* @returns {Promise<void>} Promise that resolves when initialization is complete
|
|
321
346
|
*/
|
|
322
347
|
async init(options = {}) {
|
|
323
|
-
//
|
|
348
|
+
// Concurrency control: if already initialized, return immediately
|
|
324
349
|
if (this.initialized) {
|
|
325
350
|
return;
|
|
326
351
|
}
|
|
327
352
|
|
|
328
|
-
//
|
|
353
|
+
// Concurrency control: if initialization is in progress, return the same Promise
|
|
329
354
|
if (this._initPromise) {
|
|
330
355
|
return this._initPromise;
|
|
331
356
|
}
|
|
332
357
|
|
|
333
|
-
//
|
|
358
|
+
// Create initialization Promise
|
|
334
359
|
this._initPromise = (async () => {
|
|
335
360
|
try {
|
|
336
361
|
const wasmTimeout = options.timeout || 30000;
|
|
337
|
-
const authTimeout = options.authTimeout || 10000;
|
|
338
362
|
|
|
339
|
-
//
|
|
363
|
+
// Wait for WASM module loading (with timeout)
|
|
340
364
|
try {
|
|
341
365
|
await Promise.race([
|
|
342
366
|
this._wasmLoadPromise,
|
|
@@ -348,48 +372,60 @@ class BeautyEffectEngine {
|
|
|
348
372
|
|
|
349
373
|
const Module = this._getWasmModule();
|
|
350
374
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
);
|
|
375
|
+
// Setup usage report proxy for WASM
|
|
376
|
+
if (!Module.onReportUsage) {
|
|
377
|
+
Module.onReportUsage = async (payloadJson) => {
|
|
378
|
+
try {
|
|
379
|
+
const url = 'https://facebetter.pixpark.net/rest/v1/rpc/report_sdk_usage';
|
|
380
|
+
const response = await fetch(url, {
|
|
381
|
+
method: 'POST',
|
|
382
|
+
headers: {
|
|
383
|
+
'Content-Type': 'application/json'
|
|
384
|
+
},
|
|
385
|
+
body: payloadJson
|
|
386
|
+
});
|
|
387
|
+
return response.ok;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
return false;
|
|
367
390
|
}
|
|
391
|
+
};
|
|
392
|
+
}
|
|
368
393
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
394
|
+
// Setup online auth proxy for WASM
|
|
395
|
+
if (!Module.onOnlineAuth) {
|
|
396
|
+
Module.onOnlineAuth = async (payloadJson) => {
|
|
397
|
+
try {
|
|
398
|
+
const url = 'https://facebetter.pixpark.net/rest/v1/rpc/online_auth_v2';
|
|
399
|
+
const response = await fetch(url, {
|
|
400
|
+
method: 'POST',
|
|
401
|
+
headers: {
|
|
402
|
+
'Content-Type': 'application/json'
|
|
403
|
+
},
|
|
404
|
+
body: payloadJson
|
|
405
|
+
});
|
|
406
|
+
if (!response.ok) {
|
|
407
|
+
console.warn('[JS Engine] Online auth fetch failed with status:', response.status);
|
|
408
|
+
return "";
|
|
409
|
+
}
|
|
410
|
+
return await response.text();
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.error('[JS Engine] Online auth fetch exception:', error);
|
|
413
|
+
return "";
|
|
378
414
|
}
|
|
379
|
-
|
|
380
|
-
}
|
|
415
|
+
};
|
|
381
416
|
}
|
|
382
417
|
|
|
383
|
-
//
|
|
384
|
-
// 如果通过 appId/appKey 获取到了响应,则使用响应作为 licenseJson
|
|
385
|
-
// WASM 层只需要验证 licenseJson,不需要发送 HTTP 请求
|
|
418
|
+
// Create engine instance, auth (online/offline) is handled by WASM layer via onOnlineAuth
|
|
386
419
|
const enginePtr = Module.ccall(
|
|
387
|
-
'
|
|
420
|
+
'CreateBeautyEffectEngineEx',
|
|
388
421
|
'number',
|
|
389
|
-
['string', 'string'],
|
|
422
|
+
['string', 'string', 'string', 'string', 'number'],
|
|
390
423
|
[
|
|
391
424
|
this.resourcePath,
|
|
392
|
-
|
|
425
|
+
this.licenseJson || '',
|
|
426
|
+
this.appId || '',
|
|
427
|
+
this.appKey || '',
|
|
428
|
+
this.config.externalContext ? 1 : 0
|
|
393
429
|
]
|
|
394
430
|
);
|
|
395
431
|
|
|
@@ -402,9 +438,9 @@ class BeautyEffectEngine {
|
|
|
402
438
|
|
|
403
439
|
this.enginePtr = enginePtr;
|
|
404
440
|
this.initialized = true;
|
|
405
|
-
this._initPromise = null; //
|
|
441
|
+
this._initPromise = null; // Clear Promise cache, allow re-initialization (if needed)
|
|
406
442
|
} catch (error) {
|
|
407
|
-
this._initPromise = null; //
|
|
443
|
+
this._initPromise = null; // Clear Promise cache, allow retry
|
|
408
444
|
throw error;
|
|
409
445
|
}
|
|
410
446
|
})();
|
|
@@ -432,11 +468,18 @@ class BeautyEffectEngine {
|
|
|
432
468
|
this.dstBufferPtr = null;
|
|
433
469
|
}
|
|
434
470
|
|
|
471
|
+
// Clean up shared memory
|
|
472
|
+
if (this._callbackSharedBufferPtr) {
|
|
473
|
+
Module._free(this._callbackSharedBufferPtr);
|
|
474
|
+
this._callbackSharedBufferPtr = null;
|
|
475
|
+
this._callbackSharedBufferSize = 0;
|
|
476
|
+
}
|
|
477
|
+
|
|
435
478
|
Module.ccall('DestroyBeautyEffectEngine', null, ['number'], [this.enginePtr]);
|
|
436
479
|
this.enginePtr = null;
|
|
437
480
|
this.initialized = false;
|
|
438
481
|
this.bufferSize = 0;
|
|
439
|
-
this._initPromise = null; //
|
|
482
|
+
this._initPromise = null; // Clear initialization Promise
|
|
440
483
|
|
|
441
484
|
// Clean up offscreen canvas
|
|
442
485
|
if (this._offscreenCanvas) {
|
|
@@ -541,7 +584,7 @@ class BeautyEffectEngine {
|
|
|
541
584
|
|
|
542
585
|
/**
|
|
543
586
|
* Sets a basic beauty parameter
|
|
544
|
-
* @param {number} param - Parameter (use BasicParam enum)
|
|
587
|
+
* @param {number} param - Parameter (use BasicParam enum, e.g., BasicParam.Smoothing)
|
|
545
588
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
546
589
|
*/
|
|
547
590
|
setBasicParam(param, value) {
|
|
@@ -551,7 +594,7 @@ class BeautyEffectEngine {
|
|
|
551
594
|
|
|
552
595
|
/**
|
|
553
596
|
* Sets a reshape parameter
|
|
554
|
-
* @param {number} param - Parameter (use ReshapeParam enum)
|
|
597
|
+
* @param {number} param - Parameter (use ReshapeParam enum, e.g., ReshapeParam.FaceThinning)
|
|
555
598
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
556
599
|
*/
|
|
557
600
|
setReshapeParam(param, value) {
|
|
@@ -561,7 +604,7 @@ class BeautyEffectEngine {
|
|
|
561
604
|
|
|
562
605
|
/**
|
|
563
606
|
* Sets a makeup parameter
|
|
564
|
-
* @param {number} param - Parameter (use MakeupParam enum)
|
|
607
|
+
* @param {number} param - Parameter (use MakeupParam enum, e.g., MakeupParam.Lipstick)
|
|
565
608
|
* @param {number} value - Parameter value (0.0 - 1.0)
|
|
566
609
|
*/
|
|
567
610
|
setMakeupParam(param, value) {
|
|
@@ -569,6 +612,28 @@ class BeautyEffectEngine {
|
|
|
569
612
|
this._setBeautyParam('SetBeautyParamMakeup', param, value);
|
|
570
613
|
}
|
|
571
614
|
|
|
615
|
+
/**
|
|
616
|
+
* Sets chroma key parameter
|
|
617
|
+
* @param {number} param - Parameter (use ChromaKeyParam enum, e.g., ChromaKeyParam.Similarity)
|
|
618
|
+
* @param {number} value - Parameter value (KeyColor: 0.0=Green, 1.0=Blue, 2.0=Red; others 0.0-1.0)
|
|
619
|
+
*/
|
|
620
|
+
setChromaKeyParam(param, value) {
|
|
621
|
+
this._ensureInitialized();
|
|
622
|
+
// For KeyColor, values are 0, 1, 2, not 0.0-1.0
|
|
623
|
+
if (param === 0) { // ChromaKeyParam.KeyColor
|
|
624
|
+
const Module = this._getWasmModule();
|
|
625
|
+
const result = Module.ccall(
|
|
626
|
+
'SetBeautyParamChromaKey',
|
|
627
|
+
'number',
|
|
628
|
+
['number', 'number', 'number'],
|
|
629
|
+
[this.enginePtr, param, value]
|
|
630
|
+
);
|
|
631
|
+
checkResult(result, `Failed to set chroma key parameter`);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
this._setBeautyParam('SetBeautyParamChromaKey', param, value);
|
|
635
|
+
}
|
|
636
|
+
|
|
572
637
|
/**
|
|
573
638
|
* Internal method to set beauty parameters
|
|
574
639
|
* @private
|
|
@@ -589,6 +654,139 @@ class BeautyEffectEngine {
|
|
|
589
654
|
checkResult(result, `Failed to set beauty parameter`);
|
|
590
655
|
}
|
|
591
656
|
|
|
657
|
+
/**
|
|
658
|
+
* Sets engine callbacks (face landmarks detection)
|
|
659
|
+
* @param {Object} callbacks - Callback functions
|
|
660
|
+
* @param {Function} callbacks.onFaceLandmarks - Callback for face landmarks detection
|
|
661
|
+
* @param {number} [callbacks.maxFaces=10] - Maximum number of faces to support (affects shared buffer size)
|
|
662
|
+
*/
|
|
663
|
+
setCallbacks(callbacks) {
|
|
664
|
+
this._ensureInitialized();
|
|
665
|
+
const Module = this._getWasmModule();
|
|
666
|
+
|
|
667
|
+
// Initialize callback storage (if it doesn't exist)
|
|
668
|
+
if (!Module._face_landmarks_callbacks) {
|
|
669
|
+
Module._face_landmarks_callbacks = [];
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
let callbackId = 0;
|
|
673
|
+
let sharedBufferPtr = null;
|
|
674
|
+
let sharedBufferSize = 0;
|
|
675
|
+
|
|
676
|
+
if (callbacks && callbacks.onFaceLandmarks) {
|
|
677
|
+
// Get max faces (default 10)
|
|
678
|
+
const maxFaces = callbacks.maxFaces || 10;
|
|
679
|
+
|
|
680
|
+
// Pre-allocate shared memory
|
|
681
|
+
// Metadata: 2 ints (frame_number, face_count) = 8 bytes
|
|
682
|
+
// Face data: maxFaces * 343 floats * 4 bytes = maxFaces * 1372 bytes
|
|
683
|
+
const metadataSize = 2 * 4; // 2 ints
|
|
684
|
+
const faceDataSize = maxFaces * 343 * 4; // 343 floats per face
|
|
685
|
+
sharedBufferSize = metadataSize + faceDataSize;
|
|
686
|
+
sharedBufferPtr = Module._malloc(sharedBufferSize);
|
|
687
|
+
|
|
688
|
+
if (!sharedBufferPtr) {
|
|
689
|
+
throw new FacebetterError('Failed to allocate shared buffer for callbacks');
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
// Register callback function (internal wrapper, reads data from shared memory)
|
|
693
|
+
// Push first, then get index as callbackId (allows callbackId to be 0)
|
|
694
|
+
Module._face_landmarks_callbacks.push(
|
|
695
|
+
(frameNumber, faceCount, dataPtr) => {
|
|
696
|
+
// Read data from shared memory (zero-copy)
|
|
697
|
+
const heap = Module.HEAPF32;
|
|
698
|
+
const dataOffset = dataPtr / 4; // float is 4 bytes
|
|
699
|
+
|
|
700
|
+
const results = [];
|
|
701
|
+
const FLOATS_PER_FACE = 343;
|
|
702
|
+
|
|
703
|
+
for (let i = 0; i < faceCount; i++) {
|
|
704
|
+
const faceOffset = dataOffset + i * FLOATS_PER_FACE;
|
|
705
|
+
let offset = faceOffset;
|
|
706
|
+
|
|
707
|
+
// Read rect
|
|
708
|
+
const rect = {
|
|
709
|
+
x: heap[offset++],
|
|
710
|
+
y: heap[offset++],
|
|
711
|
+
width: heap[offset++],
|
|
712
|
+
height: heap[offset++]
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
// Read basic fields
|
|
716
|
+
const faceId = Math.round(heap[offset++]);
|
|
717
|
+
const faceAction = Math.round(heap[offset++]);
|
|
718
|
+
const score = heap[offset++];
|
|
719
|
+
const pitch = heap[offset++];
|
|
720
|
+
const roll = heap[offset++];
|
|
721
|
+
const yaw = heap[offset++];
|
|
722
|
+
|
|
723
|
+
// Read key_points (111 points)
|
|
724
|
+
const keyPoints = [];
|
|
725
|
+
for (let j = 0; j < 111; j++) {
|
|
726
|
+
keyPoints.push({
|
|
727
|
+
x: heap[offset++],
|
|
728
|
+
y: heap[offset++]
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// Read visibility (111 points)
|
|
733
|
+
const visibility = [];
|
|
734
|
+
for (let j = 0; j < 111; j++) {
|
|
735
|
+
visibility.push(heap[offset++]);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
results.push({
|
|
739
|
+
rect,
|
|
740
|
+
key_points: keyPoints,
|
|
741
|
+
visibility,
|
|
742
|
+
face_id: faceId,
|
|
743
|
+
face_action: faceAction,
|
|
744
|
+
score,
|
|
745
|
+
pitch,
|
|
746
|
+
roll,
|
|
747
|
+
yaw
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Call user callback
|
|
752
|
+
callbacks.onFaceLandmarks(results);
|
|
753
|
+
}
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
// Get callback ID (index after push, can be 0)
|
|
757
|
+
callbackId = Module._face_landmarks_callbacks.length - 1;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Call C API
|
|
761
|
+
const result = Module.ccall(
|
|
762
|
+
'SetCallbacks',
|
|
763
|
+
'number',
|
|
764
|
+
['number', 'number', 'number', 'number'],
|
|
765
|
+
[
|
|
766
|
+
this.enginePtr,
|
|
767
|
+
callbackId,
|
|
768
|
+
sharedBufferPtr || 0,
|
|
769
|
+
sharedBufferSize
|
|
770
|
+
]
|
|
771
|
+
);
|
|
772
|
+
|
|
773
|
+
checkResult(result, 'Failed to set callbacks');
|
|
774
|
+
|
|
775
|
+
// Clean up old shared memory (if it exists)
|
|
776
|
+
if (this._callbackSharedBufferPtr) {
|
|
777
|
+
Module._free(this._callbackSharedBufferPtr);
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
// Store new shared memory pointer for cleanup
|
|
781
|
+
if (sharedBufferPtr) {
|
|
782
|
+
this._callbackSharedBufferPtr = sharedBufferPtr;
|
|
783
|
+
this._callbackSharedBufferSize = sharedBufferSize;
|
|
784
|
+
} else {
|
|
785
|
+
this._callbackSharedBufferPtr = null;
|
|
786
|
+
this._callbackSharedBufferSize = 0;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
592
790
|
/**
|
|
593
791
|
* Sets virtual background options (unified API, matches C++/Java/OC)
|
|
594
792
|
* @param {VirtualBackgroundOptions|Object} options - Virtual background options
|
|
@@ -606,7 +804,7 @@ class BeautyEffectEngine {
|
|
|
606
804
|
let imageBufferPtr = null;
|
|
607
805
|
|
|
608
806
|
try {
|
|
609
|
-
//
|
|
807
|
+
// If a background image is provided, convert to ImageData and prepare buffer
|
|
610
808
|
if (opts.backgroundImage) {
|
|
611
809
|
imageData = this._toImageData(opts.backgroundImage);
|
|
612
810
|
const bufferSize = imageData.width * imageData.height * 4;
|
|
@@ -617,7 +815,7 @@ class BeautyEffectEngine {
|
|
|
617
815
|
view.set(imageData.data);
|
|
618
816
|
}
|
|
619
817
|
|
|
620
|
-
//
|
|
818
|
+
// Use unified SetVirtualBackground C interface (consistent with other platforms)
|
|
621
819
|
const result = Module.ccall(
|
|
622
820
|
'SetVirtualBackground',
|
|
623
821
|
'number',
|
|
@@ -625,7 +823,7 @@ class BeautyEffectEngine {
|
|
|
625
823
|
[
|
|
626
824
|
this.enginePtr,
|
|
627
825
|
opts.mode,
|
|
628
|
-
imageBufferPtr || 0, //
|
|
826
|
+
imageBufferPtr || 0, // If null, pass 0
|
|
629
827
|
imageData ? imageData.width : 0,
|
|
630
828
|
imageData ? imageData.height : 0,
|
|
631
829
|
imageData ? imageData.width * 4 : 0
|
|
@@ -634,7 +832,7 @@ class BeautyEffectEngine {
|
|
|
634
832
|
|
|
635
833
|
checkResult(result, 'Failed to set virtual background');
|
|
636
834
|
} finally {
|
|
637
|
-
//
|
|
835
|
+
// Free memory
|
|
638
836
|
if (imageBufferPtr) {
|
|
639
837
|
Module._free(imageBufferPtr);
|
|
640
838
|
}
|
|
@@ -674,10 +872,10 @@ class BeautyEffectEngine {
|
|
|
674
872
|
* @param {ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement|Uint8ClampedArray} input - Input image
|
|
675
873
|
* @param {number} width - Image width (required if input is Uint8ClampedArray)
|
|
676
874
|
* @param {number} height - Image height (required if input is Uint8ClampedArray)
|
|
677
|
-
* @param {number}
|
|
875
|
+
* @param {number} frameType - Frame type (use FrameType enum, default: FrameType.Video)
|
|
678
876
|
* @returns {ImageData} Processed image data
|
|
679
877
|
*/
|
|
680
|
-
processImage(input, width, height,
|
|
878
|
+
processImage(input, width, height, frameType = FrameType$1.Video) {
|
|
681
879
|
this._ensureInitialized();
|
|
682
880
|
const imageData = this._platformAPI.toImageData(input, width, height);
|
|
683
881
|
const Module = this._getWasmModule();
|
|
@@ -703,7 +901,7 @@ class BeautyEffectEngine {
|
|
|
703
901
|
imageData.height,
|
|
704
902
|
imageData.width * 4,
|
|
705
903
|
this.dstBufferPtr,
|
|
706
|
-
|
|
904
|
+
frameType
|
|
707
905
|
]
|
|
708
906
|
);
|
|
709
907
|
|
|
@@ -722,6 +920,62 @@ class BeautyEffectEngine {
|
|
|
722
920
|
}
|
|
723
921
|
}
|
|
724
922
|
|
|
923
|
+
/**
|
|
924
|
+
* Processes an external GPU texture.
|
|
925
|
+
*
|
|
926
|
+
* Note:
|
|
927
|
+
* - This interface is mainly used for integration with internal WASM or advanced scenarios.
|
|
928
|
+
* - textureHandle must be a texture handle (uint32) compatible with the OpenGL/WebGL context used by WASM.
|
|
929
|
+
* - For common web scenarios, it is recommended to use processImage with ImageData/Canvas etc.
|
|
930
|
+
*
|
|
931
|
+
* @param {number} textureHandle - External texture handle (GL_TEXTURE_2D)
|
|
932
|
+
* @param {number} width - Texture width
|
|
933
|
+
* @param {number} height - Texture height
|
|
934
|
+
* @param {number} stride - Row stride (usually width * 4)
|
|
935
|
+
* @param {number} [frameType] - Frame type (FrameType.Image / FrameType.Video)
|
|
936
|
+
* @returns {number} Processed texture handle (GL_TEXTURE_2D, uint32)
|
|
937
|
+
*/
|
|
938
|
+
processTexture(textureHandle,
|
|
939
|
+
width,
|
|
940
|
+
height,
|
|
941
|
+
stride,
|
|
942
|
+
frameType = FrameType$1.Video) {
|
|
943
|
+
this._ensureInitialized();
|
|
944
|
+
if (!textureHandle || width <= 0 || height <= 0 || stride <= 0) {
|
|
945
|
+
throw new FacebetterError('Invalid textureHandle or dimensions for processTexture');
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
const Module = this._getWasmModule();
|
|
949
|
+
|
|
950
|
+
try {
|
|
951
|
+
const result = Module.ccall(
|
|
952
|
+
'ProcessImageTexture',
|
|
953
|
+
'number',
|
|
954
|
+
['number', 'number', 'number', 'number', 'number', 'number'],
|
|
955
|
+
[
|
|
956
|
+
this.enginePtr,
|
|
957
|
+
textureHandle,
|
|
958
|
+
width,
|
|
959
|
+
height,
|
|
960
|
+
stride,
|
|
961
|
+
frameType
|
|
962
|
+
]
|
|
963
|
+
);
|
|
964
|
+
|
|
965
|
+
if (!result || result === 0) {
|
|
966
|
+
throw new FacebetterError('Failed to process external texture or got invalid output texture');
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// Return processed texture handle for caller to continue using in same GL context
|
|
970
|
+
return result;
|
|
971
|
+
} catch (error) {
|
|
972
|
+
if (error instanceof FacebetterError) {
|
|
973
|
+
throw error;
|
|
974
|
+
}
|
|
975
|
+
throw new FacebetterError(`Texture processing error: ${error.message}`);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
725
979
|
/**
|
|
726
980
|
* Ensures the engine is initialized
|
|
727
981
|
* @private
|
|
@@ -791,6 +1045,15 @@ class BeautyEffectEngine {
|
|
|
791
1045
|
return this._offscreenCanvas;
|
|
792
1046
|
}
|
|
793
1047
|
|
|
1048
|
+
/**
|
|
1049
|
+
* Internal method for online authentication (Deprecated: logic moved to WASM layer)
|
|
1050
|
+
* @private
|
|
1051
|
+
*/
|
|
1052
|
+
async _verifyAppKeyOnline(appId, appKey) {
|
|
1053
|
+
// This method is now deprecated as logic is moved to WASM layer via Module.onOnlineAuth
|
|
1054
|
+
return null;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
794
1057
|
}
|
|
795
1058
|
|
|
796
1059
|
/**
|
|
@@ -896,7 +1159,7 @@ async function verifyAppKeyOnline(appId, appKey) {
|
|
|
896
1159
|
p_user_agent: getUserAgentString()
|
|
897
1160
|
};
|
|
898
1161
|
|
|
899
|
-
const response = await fetch('https://facebetter.pixpark.net/rest/v1/rpc/
|
|
1162
|
+
const response = await fetch('https://facebetter.pixpark.net/rest/v1/rpc/online_auth_v2', {
|
|
900
1163
|
method: 'POST',
|
|
901
1164
|
headers: {
|
|
902
1165
|
'Content-Type': 'application/json',
|
|
@@ -1078,8 +1341,9 @@ const BeautyType = BeautyType$1;
|
|
|
1078
1341
|
const BasicParam = BasicParam$1;
|
|
1079
1342
|
const ReshapeParam = ReshapeParam$1;
|
|
1080
1343
|
const MakeupParam = MakeupParam$1;
|
|
1344
|
+
const ChromaKeyParam = ChromaKeyParam$1;
|
|
1081
1345
|
const BackgroundMode = BackgroundMode$1;
|
|
1082
|
-
const
|
|
1346
|
+
const FrameType = FrameType$1;
|
|
1083
1347
|
const VirtualBackgroundOptions = VirtualBackgroundOptions$1;
|
|
1084
1348
|
|
|
1085
1349
|
// Default export
|
|
@@ -1091,5 +1355,5 @@ var index = {
|
|
|
1091
1355
|
loadWasmModule
|
|
1092
1356
|
};
|
|
1093
1357
|
|
|
1094
|
-
export { BackgroundMode, BasicParam, ESMBeautyEffectEngine as BeautyEffectEngine, BeautyType, EngineConfig, FacebetterError,
|
|
1358
|
+
export { BackgroundMode, BasicParam, ESMBeautyEffectEngine as BeautyEffectEngine, BeautyType, ChromaKeyParam, EngineConfig, FacebetterError, FrameType, MakeupParam, ReshapeParam, VirtualBackgroundOptions, createBeautyEffectEngine, index as default, getWasmBuffer, getWasmModule, loadWasmModule };
|
|
1095
1359
|
//# sourceMappingURL=facebetter.esm.js.map
|