1
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
package="io.dcloud.uni_modules.xFaceDetection">
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-feature android:name="android.hardware.camera.any" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<application>
|
||||
<meta-data android:name="UTS_MLKIT_xFaceDetection" android:value="xFaceDetection" />
|
||||
<activity android:name="uts.sdk.modules.xFaceDetection.DemoActivity"></activity>
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,51 @@
|
||||
import MediaPlayer from "android.media.MediaPlayer"
|
||||
import File from 'java.io.File';
|
||||
import FileOutputStream from 'java.io.FileOutputStream';
|
||||
export class xAudio {
|
||||
audio:MediaPlayer;
|
||||
constructor(){
|
||||
this.audio = new MediaPlayer();
|
||||
}
|
||||
play(src:string){
|
||||
|
||||
|
||||
this.audio.stop();
|
||||
this.audio.release()
|
||||
this.audio = new MediaPlayer();
|
||||
let assetManager = UTSAndroid.getAppContext()!.getAssets();
|
||||
// 加载free.mp3 资源
|
||||
const listAssets = assetManager.list("");
|
||||
let filename = src+".mp3";
|
||||
let isExites = listAssets?.contains(filename)??false
|
||||
|
||||
if(!isExites) return;
|
||||
let afd = assetManager.openFd(filename);
|
||||
try {
|
||||
// 使用android 自带的媒体组件进行播放
|
||||
let mediaPlayer = this.audio;
|
||||
mediaPlayer.setDataSource(afd.getFileDescriptor(),afd.getStartOffset(), afd.getLength());
|
||||
mediaPlayer.prepare();
|
||||
mediaPlayer.start();
|
||||
class audioCompleted implements MediaPlayer.OnCompletionListener{
|
||||
override onCompletion(m:MediaPlayer|null){
|
||||
// if(m!=null){
|
||||
// m.release()
|
||||
// }
|
||||
}
|
||||
}
|
||||
mediaPlayer.setOnCompletionListener(new audioCompleted())
|
||||
} catch (e: Exception) {
|
||||
console.log("AudioPlayer", "Error setting data source: ",e)
|
||||
|
||||
} finally {
|
||||
// 确保关闭文件描述符
|
||||
afd.close()
|
||||
}
|
||||
}
|
||||
stop(){
|
||||
// this.audio.stop();
|
||||
}
|
||||
destory(){
|
||||
// this.audio.release()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,548 @@
|
||||
import ListView from 'android.widget.ListView';
|
||||
import FrameLayout from 'android.widget.FrameLayout';
|
||||
import CameraManager from 'android.hardware.camera2.CameraManager'
|
||||
import CameraDevice from 'android.hardware.camera2.CameraDevice'
|
||||
import StateCallback from 'android.hardware.camera2.CameraDevice.StateCallback'
|
||||
import CameraCaptureSession from 'android.hardware.camera2.CameraCaptureSession'
|
||||
import Camera2CameraControl from 'androidx.camera.camera2.interop.Camera2CameraControl'
|
||||
import Camera2CameraInfo from 'androidx.camera.camera2.interop.Camera2CameraInfo'
|
||||
|
||||
|
||||
|
||||
|
||||
import CaptureRequest from 'android.hardware.camera2.CaptureRequest'
|
||||
import TotalCaptureResult from 'android.hardware.camera2.TotalCaptureResult'
|
||||
import StreamConfigurationMap from 'android.hardware.camera2.params.StreamConfigurationMap'
|
||||
import MeteringRectangle from 'android.hardware.camera2.params.MeteringRectangle'
|
||||
import OutputConfiguration from 'android.hardware.camera2.params.OutputConfiguration'
|
||||
import SessionConfiguration from 'android.hardware.camera2.params.SessionConfiguration'
|
||||
import CameraCharacteristics from 'android.hardware.camera2.CameraCharacteristics'
|
||||
import CameraMetadata from 'android.hardware.camera2.CameraMetadata'
|
||||
import Range from 'android.util.Range';
|
||||
|
||||
import InputImage from "com.google.mlkit.vision.common.InputImage"
|
||||
|
||||
import Executor from 'java.util.concurrent.Executor'
|
||||
import Looper from 'android.os.Looper'
|
||||
import ImageFormat from 'android.graphics.ImageFormat'
|
||||
import Size from 'android.util.Size'
|
||||
import SurfaceTexture from 'android.graphics.SurfaceTexture'
|
||||
import Handler from 'android.os.Handler'
|
||||
import Surface from 'android.view.Surface'
|
||||
import Image from 'android.media.Image'
|
||||
import LinearLayout from 'android.widget.LinearLayout';
|
||||
import Intent from 'android.content.Intent';
|
||||
import Integer from 'java.lang.Integer';
|
||||
import ByteOrder from 'java.nio.ByteOrder';
|
||||
|
||||
|
||||
import SurfaceHolder from 'android.view.SurfaceHolder'
|
||||
import SurfaceView from 'android.view.SurfaceView'
|
||||
import TextureView from 'android.view.TextureView'
|
||||
import View from 'android.view.View'
|
||||
import Context from 'android.content.Context'
|
||||
import Manifest from "android.Manifest";
|
||||
import Uri from 'android.net.Uri';
|
||||
import File from 'java.io.File'
|
||||
import System from 'java.lang.System'
|
||||
import Activity from 'android.app.Activity';
|
||||
import Bundle from 'android.os.Bundle';
|
||||
import Intent from 'android.content.Intent';
|
||||
import IntentFilter from 'android.content.IntentFilter';
|
||||
|
||||
import Rect from 'android.graphics.Rect';
|
||||
import Matrix from 'android.graphics.Matrix'
|
||||
import ImageReader from 'android.media.ImageReader'
|
||||
import OnImageAvailableListener from 'android.media.ImageReader.OnImageAvailableListener'
|
||||
|
||||
|
||||
import ByteBuffer from 'java.nio.ByteBuffer'
|
||||
import MediaStore from 'android.provider.MediaStore'
|
||||
import Plane from 'android.media.Image.Plane'
|
||||
import Bitmap from "android.graphics.Bitmap"
|
||||
import BitmapFactory from "android.graphics.BitmapFactory"
|
||||
import Vibrator from "android.os.Vibrator"
|
||||
import Animation from "android.view.animation.Animation"
|
||||
import ScaleAnimation from "android.view.animation.ScaleAnimation"
|
||||
import AnimationUtils from "android.view.animation.AnimationUtils"
|
||||
|
||||
|
||||
import Color from "android.graphics.Color"
|
||||
import Window from "android.view.Window"
|
||||
import WindowManager from "android.view.WindowManager"
|
||||
import TextView from "android.widget.TextView"
|
||||
import RelativeLayout from "android.widget.RelativeLayout"
|
||||
import ImageView from "android.widget.ImageView"
|
||||
import HandlerThread from 'android.os.HandlerThread'
|
||||
import YuvImage from 'android.graphics.YuvImage'
|
||||
import ByteArrayOutputStream from 'java.io.ByteArrayOutputStream'
|
||||
import GradientDrawable from 'android.graphics.drawable.GradientDrawable'
|
||||
import MotionEvent from 'android.view.MotionEvent';
|
||||
import ViewGroup from 'android.view.ViewGroup';
|
||||
|
||||
|
||||
import IOException from 'java.io.IOException'
|
||||
import InputStream from 'java.io.InputStream'
|
||||
// import BarcodeScanner from "com.google.mlkit.vision.barcode.BarcodeScanner"
|
||||
// import BarcodeScannerOptions from "com.google.mlkit.vision.barcode.BarcodeScannerOptions"
|
||||
// import BarcodeScanning from "com.google.mlkit.vision.barcode.BarcodeScanning"
|
||||
// import ZoomSuggestionOptions from "com.google.mlkit.vision.barcode.ZoomSuggestionOptions"
|
||||
// import ZoomCallback from "com.google.mlkit.vision.barcode.ZoomSuggestionOptions.ZoomCallback"
|
||||
// import Barcode from "com.google.mlkit.vision.barcode.common.Barcode"
|
||||
// import InputImage from "com.google.mlkit.vision.common.InputImage"
|
||||
|
||||
import Task from "com.google.android.gms.tasks.Task"
|
||||
import List from "java.util.List"
|
||||
|
||||
// x
|
||||
import ProcessCameraProvider from "androidx.camera.lifecycle.ProcessCameraProvider"
|
||||
import PreviewView from "androidx.camera.view.PreviewView"
|
||||
import CameraController from "androidx.camera.view.CameraController"
|
||||
import CameraSelector from "androidx.camera.core.CameraSelector"
|
||||
import Preview from 'androidx.camera.core.Preview'
|
||||
import Camera from 'androidx.camera.core.Camera'
|
||||
import LifecycleObserver from "androidx.lifecycle.LifecycleObserver"
|
||||
import LifecycleOwner from "androidx.lifecycle.LifecycleOwner"
|
||||
import OnLifecycleEvent from "androidx.lifecycle.OnLifecycleEvent"
|
||||
import ImageAnalysis from 'androidx.camera.core.ImageAnalysis'
|
||||
import ImageProxy from 'androidx.camera.core.ImageProxy'
|
||||
import ImageCapture from 'androidx.camera.core.ImageCapture';
|
||||
import AspectRatio from 'androidx.camera.core.AspectRatio';
|
||||
import CameraInfo from 'androidx.camera.core.CameraInfo';
|
||||
import CameraControl from 'androidx.camera.core.CameraControl'
|
||||
|
||||
import NonNull from 'androidx.annotation.NonNull'
|
||||
import ExecutorService from 'java.util.concurrent.ExecutorService'
|
||||
import Executors from 'java.util.concurrent.Executors'
|
||||
// import TargetResolution from 'androidx.camera.core.ImageAnalysis.TargetResolution'
|
||||
import {decodeImage} from "./index.uts"
|
||||
|
||||
|
||||
type buffoptsPlanesType = {
|
||||
data : ByteBuffer,
|
||||
getRowStride : number,
|
||||
getPixelStride : number,
|
||||
}
|
||||
type buffoptsType = {
|
||||
width : number,
|
||||
height : number,
|
||||
format : number,
|
||||
rect : Rect,
|
||||
planes : buffoptsPlanesType[],
|
||||
}
|
||||
|
||||
import { AUTH_CALL_BACK_TYPE, CAMERA_PHOTO_SIZE,XCHECKFACE_ENTER_CALL,XFACE_EVENT_SUCCESS } from "../interface.uts"
|
||||
|
||||
import ContextCompat from 'androidx.core.content.ContextCompat';
|
||||
import FileOutputStream from 'java.io.FileOutputStream';
|
||||
import PreviewConfig from 'androidx.camera.core.impl.PreviewConfig';
|
||||
import VideoSource from 'android.media.MediaRecorder.VideoSource';
|
||||
import VideoCapture from 'androidx.camera.video.VideoCapture';
|
||||
import OutputFileOptions from 'androidx.camera.core.ImageCapture.OutputFileOptions';
|
||||
import Recorder from 'androidx.camera.video.Recorder';
|
||||
import Quality from 'androidx.camera.video.Quality';
|
||||
import QualitySelector from 'androidx.camera.video.QualitySelector';
|
||||
import OutputFileResults from 'androidx.camera.core.ImageCapture.OutputFileResults';
|
||||
import FileDescriptor from 'java.io.FileDescriptor';
|
||||
import FileOutputOptions from 'androidx.camera.video.FileOutputOptions';
|
||||
|
||||
import VideoRecordEvent from 'androidx.camera.video.VideoRecordEvent';
|
||||
import Consumer from 'androidx.core.util.Consumer';
|
||||
import Recording from 'androidx.camera.video.Recording';
|
||||
import ResolutionCorrector from 'androidx.camera.camera2.internal.compat.workaround.ResolutionCorrector';
|
||||
import AspectRatioStrategy from 'androidx.camera.core.resolutionselector.AspectRatioStrategy';
|
||||
import ResolutionSelector from 'androidx.camera.core.resolutionselector.ResolutionSelector';
|
||||
|
||||
type cameraListNameType = { id : string, device : CameraCharacteristics }
|
||||
type TAKE_CALL_BACK = (path : string) => void;
|
||||
let callFuntake = (path : string) => { }
|
||||
let callVideoFun = (path : string) => { }
|
||||
let callVideoFaceFun= (img : XFACE_EVENT_SUCCESS[],imgBit:Bitmap|null) => { }
|
||||
let checking = true
|
||||
function px2dp(n : number) : number {
|
||||
const mets = UTSAndroid.getAppContext()!.resources!.getDisplayMetrics()
|
||||
return mets.density * n
|
||||
}
|
||||
function getUid(rdix = 1, length = 12) : string {
|
||||
let ix = "";
|
||||
// #ifdef APP
|
||||
ix = Math.floor(Math.random() * rdix * Math.floor(Math.random() * Date.now())).toString().substring(0, length as Int);
|
||||
// #endif
|
||||
return ix;
|
||||
}
|
||||
export class xCamera {
|
||||
parentView : FrameLayout;
|
||||
|
||||
|
||||
|
||||
|
||||
viewBox_width = 0
|
||||
viewBox_height = 0
|
||||
|
||||
imgPointsBycanmarea = [] as RelativeLayout[]
|
||||
|
||||
|
||||
/** 手动震动服务 */
|
||||
vibrator = null as null | Vibrator
|
||||
context : Context;
|
||||
// 相机旋转的角度。
|
||||
cameraRate = new Map<Number, Number>([
|
||||
[Surface.ROTATION_0, 0],
|
||||
[Surface.ROTATION_90, 0],
|
||||
[Surface.ROTATION_180, 0],
|
||||
[Surface.ROTATION_270, 0]
|
||||
])
|
||||
// 相机服务
|
||||
cameraService : CameraManager
|
||||
// 相机列表,name,id
|
||||
cameraListName = new Map<string, cameraListNameType>();
|
||||
//
|
||||
cameraPreviewSize = { width: 800, height: 800 } as CAMERA_PHOTO_SIZE
|
||||
// 当前预览的什么是设备
|
||||
cameraDevice : CameraDevice | null = null
|
||||
cameraDeviceCaptureSession : CameraCaptureSession | null = null
|
||||
sufaceHolderView : Surface | null = null
|
||||
|
||||
// 相机区域视图
|
||||
cameraView : PreviewView | null = null;
|
||||
cameraProvider : ProcessCameraProvider | null = null
|
||||
camera : Camera | null = null;
|
||||
cameraPreview : Preview | null = null;
|
||||
videoCapture : VideoCapture<Recorder> | null = null;
|
||||
// Recording
|
||||
recoderVideoObj:Recording|null = null;
|
||||
|
||||
// 是否拍照中
|
||||
isDecoderQring = false
|
||||
// 当前相机是否正在预览中。
|
||||
isOpeningCameraing = false;
|
||||
|
||||
callFunEvent : TAKE_CALL_BACK = (str : string) => { }
|
||||
//摄像头朝向,默认是向后置摄像头.
|
||||
CamerDeviceDir = CameraSelector.LENS_FACING_FRONT
|
||||
//摄像头的是否开
|
||||
flashMode = false
|
||||
// 拍照模式,还是录像模式.
|
||||
takeModelType = 'video'; //photo,video
|
||||
|
||||
private PHOTO_TYPE = "image/jpeg"
|
||||
private RATIO_4_3_VALUE = 4.0 / 3.0
|
||||
private RATIO_16_9_VALUE = 16.0 / 9.0
|
||||
constructor(GroupView : FrameLayout) {
|
||||
this.context = UTSAndroid.getAppContext()! as Context;
|
||||
this.parentView = GroupView;
|
||||
this.cameraService = this.context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
|
||||
this.vibrator = this.context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator;
|
||||
this._createCameraView()
|
||||
}
|
||||
|
||||
/** 创建相机预览区域 */
|
||||
private _createCameraView() {
|
||||
|
||||
let sv = new PreviewView(UTSAndroid.getAppContext()!)
|
||||
sv.scaleType = PreviewView.ScaleType.FILL_CENTER
|
||||
|
||||
// 让相机的高和宽与组件对齐。
|
||||
let layaout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
sv.setLayoutParams(layaout)
|
||||
this.cameraView = sv;
|
||||
|
||||
this.parentView.addView(this.cameraView!)
|
||||
}
|
||||
|
||||
openCamera() {
|
||||
let _this = this;
|
||||
if (this.isOpeningCameraing) {
|
||||
this.closeCamera()
|
||||
}
|
||||
_this._openCamera();
|
||||
}
|
||||
startRecoderVideo(call : (path : string) => void) {
|
||||
callVideoFun = call;
|
||||
let _this = this;
|
||||
|
||||
if(_this.recoderVideoObj?.isClosed()==false){
|
||||
_this.recoderVideoObj?.resume()
|
||||
}else{
|
||||
if (this.isOpeningCameraing||this.recoderVideoObj!=null) {
|
||||
this.stopRecoderVideo()
|
||||
this.closeCamera()
|
||||
}
|
||||
_this.takeModelType = 'video'
|
||||
_this._openCamera();
|
||||
}
|
||||
}
|
||||
pauseRecoderVideo(){
|
||||
let _this = this;
|
||||
_this.recoderVideoObj?.pause()
|
||||
}
|
||||
stopRecoderVideo() {
|
||||
let _this = this;
|
||||
_this.takeModelType = 'photo'
|
||||
_this.recoderVideoObj?.stop()
|
||||
_this.recoderVideoObj?.close()
|
||||
_this.recoderVideoObj = null;
|
||||
_this.videoCapture = null;
|
||||
// closeCamera();
|
||||
}
|
||||
|
||||
|
||||
setCallEvent(call : TAKE_CALL_BACK) {
|
||||
this.callFunEvent = call;
|
||||
}
|
||||
setCheckFaceEnter(call:XCHECKFACE_ENTER_CALL){
|
||||
callVideoFaceFun = call
|
||||
}
|
||||
getCamraRotation() : Number {
|
||||
return 0
|
||||
}
|
||||
|
||||
closeCamera() {
|
||||
let t = this;
|
||||
class IntentRunable2 extends Runnable {
|
||||
override run() {
|
||||
t.cameraProvider?.unbindAll()
|
||||
t.cameraPreview?.setSurfaceProvider(null)
|
||||
t.isOpeningCameraing = false;
|
||||
}
|
||||
}
|
||||
// 确保在主线程中关闭相机
|
||||
new Handler(Looper.getMainLooper()).post(new IntentRunable2());
|
||||
}
|
||||
|
||||
private aspectRatio(width : Int, height : Int) : Int {
|
||||
let previewRatio = Math.max(width, height).toDouble() / Math.min(width, height)
|
||||
if (Math.abs(previewRatio - this.RATIO_4_3_VALUE) <= Math.abs(previewRatio - this.RATIO_16_9_VALUE)) {
|
||||
return AspectRatio.RATIO_4_3
|
||||
}
|
||||
return AspectRatio.RATIO_16_9
|
||||
}
|
||||
|
||||
private imageToBitmap(image: Image): Bitmap {
|
||||
// Assuming the image format is YUV_420_888 and converting it to Bitmap
|
||||
let buffer = image.planes[0].buffer
|
||||
let bytes = ByteArray(buffer.capacity())
|
||||
buffer.get(bytes)
|
||||
let yuvImage = YuvImage(bytes, ImageFormat.NV21, image.width, image.height, null)
|
||||
let out = ByteArrayOutputStream()
|
||||
yuvImage.compressToJpeg(Rect(0, 0, image.width, image.height), 100, out)
|
||||
let byteArray = out.toByteArray()
|
||||
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
|
||||
}
|
||||
|
||||
private increaseBrightness(camera: Camera) {
|
||||
// 调整曝光补偿以提高亮度
|
||||
let cameraControl = camera.cameraControl
|
||||
let cameraInfo = camera.cameraInfo
|
||||
|
||||
let exposureState = cameraInfo.exposureState
|
||||
let range = exposureState.exposureCompensationRange
|
||||
let maxExposure = range.upper
|
||||
|
||||
if (maxExposure > 0) {
|
||||
cameraControl.setExposureCompensationIndex(maxExposure)
|
||||
console.log("曝光补偿值已设置为最大值: $",maxExposure)
|
||||
} else {
|
||||
console.log("相机不支持曝光补偿。")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private setISO(camera: Camera) {
|
||||
|
||||
}
|
||||
|
||||
private setWhiteBalance(camera: Camera) {
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private _openCamera() {
|
||||
let _this = this;
|
||||
let cameraProviderFuture = ProcessCameraProvider.getInstance(this.context)
|
||||
|
||||
class IntentRunable extends Runnable {
|
||||
override run() {
|
||||
let cameraProvider : ProcessCameraProvider = cameraProviderFuture.get()
|
||||
let previewView = _this.cameraView! as PreviewView
|
||||
|
||||
let cameraSelector : CameraSelector = new CameraSelector.Builder()
|
||||
.requireLensFacing(_this.CamerDeviceDir)
|
||||
.build();
|
||||
|
||||
// 预览比例
|
||||
let screenAspectRatio = _this.aspectRatio((300).toInt(), (300).toInt())
|
||||
let preview : Preview = new Preview.Builder()
|
||||
.setTargetAspectRatio(screenAspectRatio)
|
||||
.build();
|
||||
preview.setSurfaceProvider(previewView.getSurfaceProvider())
|
||||
// 创建ImageCapture用例,并设置闪光灯模式
|
||||
|
||||
let imageCapture : ImageCapture = new ImageCapture.Builder()
|
||||
.setTargetAspectRatio(screenAspectRatio)
|
||||
.build();
|
||||
|
||||
|
||||
let imageAnalysis = new ImageAnalysis.Builder()
|
||||
.setTargetResolution(new Size(300, 300))
|
||||
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
||||
.build();
|
||||
class MyImageAnalyzer implements ImageAnalysis.Analyzer {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
override analyze(image : ImageProxy) {
|
||||
// image
|
||||
if (_this.isDecoderQring) {
|
||||
_this.savePhotoTocache(image)
|
||||
|
||||
} else {
|
||||
const imgInput = image.getImage()
|
||||
if(imgInput!=null){
|
||||
|
||||
let img = InputImage.fromMediaImage(imgInput,image.getImageInfo().getRotationDegrees())
|
||||
decodeImage((evt:XFACE_EVENT_SUCCESS[])=>{
|
||||
UTSAndroid.getDispatcher("main").async(function(_){
|
||||
let imgbitmap = image.toBitmap()
|
||||
callVideoFaceFun(evt,imgbitmap)
|
||||
image.close()
|
||||
},null)
|
||||
},()=>{},img)
|
||||
}else{
|
||||
image.close()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
override getDefaultTargetResolution() : Size {
|
||||
return new Size(_this.viewBox_width.toInt(), _this.viewBox_height.toInt());
|
||||
}
|
||||
|
||||
}
|
||||
let cameraExecutor = Executors.newSingleThreadExecutor();
|
||||
imageAnalysis.setAnalyzer(cameraExecutor, new MyImageAnalyzer());
|
||||
|
||||
let recorder = Recorder.Builder()
|
||||
.setQualitySelector(QualitySelector.from(Quality.LOWEST)) // 选择录制质量,HD、FHD等
|
||||
.build()
|
||||
_this.videoCapture = VideoCapture.withOutput(recorder)
|
||||
|
||||
|
||||
let camera : Camera = cameraProvider.bindToLifecycle(UTSAndroid.getUniActivity()! as LifecycleOwner,
|
||||
cameraSelector,
|
||||
imageCapture,
|
||||
imageAnalysis,
|
||||
preview,
|
||||
videoCapture!
|
||||
);
|
||||
|
||||
|
||||
if (_this.takeModelType == 'video') {
|
||||
// 录制视频
|
||||
let filepath = _this.context.getExternalCacheDir()?.getPath() ?? ""
|
||||
let videoFile = new File(filepath, 'tmui4xCamreaVideo' + getUid(1, 12) + '.mp4')
|
||||
let outputOptions = FileOutputOptions.Builder(videoFile).build()
|
||||
class DirectExecutor implements Executor {
|
||||
override execute(r:Runnable ) {
|
||||
r.run();
|
||||
console.error('录制错误')
|
||||
callVideoFun('')
|
||||
}
|
||||
}
|
||||
// Consumer<VideoRecordEvent>
|
||||
class reocdereventClass implements Consumer<VideoRecordEvent> {
|
||||
override accept(event: VideoRecordEvent) {
|
||||
if(event instanceof VideoRecordEvent.Start){
|
||||
console.log("开始录制")
|
||||
}else if(event instanceof VideoRecordEvent.Finalize){
|
||||
console.log("结束录制",videoFile.absolutePath)
|
||||
callVideoFun(videoFile.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
// ContextCompat.getMainExecutor(_this.context)
|
||||
_this.recoderVideoObj = _this.videoCapture!.getOutput()
|
||||
.prepareRecording(_this.context,outputOptions)
|
||||
.start(ContextCompat.getMainExecutor(_this.context),new reocdereventClass() as Consumer<VideoRecordEvent>)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
let cameraControl = camera.getCameraControl()
|
||||
let cameraInfo : CameraInfo = camera.getCameraInfo()
|
||||
|
||||
|
||||
_this.increaseBrightness(camera)
|
||||
|
||||
// 闪光灯.
|
||||
cameraControl.enableTorch(_this.flashMode)
|
||||
_this.camera = camera
|
||||
_this.cameraPreview = preview
|
||||
|
||||
_this.cameraProvider = cameraProvider
|
||||
_this.isDecoderQring = false
|
||||
_this.isOpeningCameraing = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
cameraProviderFuture.addListener(new IntentRunable(), ContextCompat.getMainExecutor(this.context))
|
||||
}catch(e){
|
||||
console.error('开启错误.')
|
||||
}
|
||||
}
|
||||
|
||||
takPhoto(call : (path : string) => void) {
|
||||
callFuntake = call;
|
||||
this.isDecoderQring = true;
|
||||
}
|
||||
//front,前置,back后置
|
||||
setCameraDir(type : string) {
|
||||
this.CamerDeviceDir = type == 'back' ? CameraSelector.LENS_FACING_BACK : CameraSelector.LENS_FACING_FRONT
|
||||
}
|
||||
setFlash(type : boolean) {
|
||||
this.flashMode = type;
|
||||
}
|
||||
|
||||
|
||||
savePhotoTocache(image : ImageProxy) {
|
||||
let context = UTSAndroid.getAppContext()!
|
||||
let filepath = context.getExternalCacheDir()?.getPath() ?? ""
|
||||
let img : Bitmap | null = image.toBitmap()
|
||||
let file = new File(filepath, 'tmui4xCamrea' + getUid(1, 12) + '.jpg');
|
||||
let fos = new FileOutputStream(file)
|
||||
let conunt = (img?.getByteCount() ?? 0) / 1024 / 1024
|
||||
|
||||
let saved = img!.compress(Bitmap.CompressFormat.JPEG, conunt > 1 ? 64 : 100, fos);
|
||||
let t = this;
|
||||
class IntentRunable2 extends Runnable {
|
||||
override run() {
|
||||
if (saved) {
|
||||
callFuntake(file.getPath())
|
||||
t.isDecoderQring = false
|
||||
}
|
||||
// ,拍照暂不关闭相机让用户手动关闭.
|
||||
// t.closeCamera()
|
||||
}
|
||||
}
|
||||
image.close()
|
||||
new Handler(Looper.getMainLooper()).post(new IntentRunable2());
|
||||
}
|
||||
|
||||
savePhotoBitmapTocache(img : Bitmap) {
|
||||
let context = UTSAndroid.getAppContext()!
|
||||
let filepath = context.getExternalCacheDir()?.getPath() ?? ""
|
||||
let file = new File(filepath, 'tmui4xCamrea' + getUid(1, 12) + '.jpg');
|
||||
let fos = new FileOutputStream(file)
|
||||
let conunt = img.getByteCount() / 1024 / 1024
|
||||
img!.compress(Bitmap.CompressFormat.JPEG, conunt > 1 ? 64 : 100, fos);
|
||||
return file.getPath();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"minSdkVersion": "21",
|
||||
"dependencies":[
|
||||
"com.google.mlkit:face-detection:16.1.7",
|
||||
"androidx.camera:camera-core:1.3.4",
|
||||
"androidx.camera:camera-camera2:1.3.4",
|
||||
"androidx.camera:camera-lifecycle:1.3.4",
|
||||
"androidx.camera:camera-video:1.3.4",
|
||||
"androidx.camera:camera-view:1.3.4",
|
||||
"androidx.camera:camera-extensions:1.3.4"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
import Intent from 'android.content.Intent';
|
||||
import Context from 'android.content.Context'
|
||||
import IOException from 'java.io.IOException'
|
||||
import InputStream from 'java.io.InputStream'
|
||||
import Uri from 'android.net.Uri';
|
||||
import File from 'java.io.File'
|
||||
import Bitmap from "android.graphics.Bitmap"
|
||||
import FrameLayout from 'android.widget.FrameLayout';
|
||||
import FaceDetection from "com.google.mlkit.vision.face.FaceDetection"
|
||||
import FaceDetectorOptions from "com.google.mlkit.vision.face.FaceDetectorOptions"
|
||||
import FaceLandmark from "com.google.mlkit.vision.face.FaceLandmark"
|
||||
import FaceContour from "com.google.mlkit.vision.face.FaceContour"
|
||||
import Face from "com.google.mlkit.vision.face.Face"
|
||||
|
||||
import InputImage from "com.google.mlkit.vision.common.InputImage"
|
||||
|
||||
import Task from "com.google.android.gms.tasks.Task"
|
||||
import List from "java.util.List"
|
||||
import ByteBuffer from 'java.nio.ByteBuffer'
|
||||
import ImageFormat from 'android.graphics.ImageFormat'
|
||||
import Kotlin from 'kotlin.jvm.internal.Intrinsics.Kotlin';
|
||||
import Image from 'android.media.Image';
|
||||
import LinearLayout from 'android.widget.LinearLayout';
|
||||
import ViewGroup from 'android.view.ViewGroup';
|
||||
|
||||
import { XFACE_CHECK_OPTS, XFACE_EVENT_SUCCESS, XFACE_TEST_EYE_TYPE, XFACE_FACE_Direction, XFACE_EVENT_CHECK_SUCCESS } from "../interface.uts"
|
||||
import { XFACE_CHECK_OPTS_REAL, getDefaultConfig } from "../libs/config.uts"
|
||||
import BitmapFactory from 'android.graphics.BitmapFactory';
|
||||
import View from 'android.view.View';
|
||||
import { xCamera } from "./camera.uts"
|
||||
import { xAudio } from "./audio.uts"
|
||||
|
||||
let camera : xCamera | null = null;
|
||||
const audio = new xAudio();
|
||||
const checkFaceResult = (image : InputImage, faces : MutableList<Face>, callBack : (result : XFACE_EVENT_SUCCESS[]) => void) => {
|
||||
const cfaces = [] as XFACE_EVENT_SUCCESS[]
|
||||
// @ts-ignore
|
||||
for (item in faces) {
|
||||
// @ts-ignore
|
||||
const face = item as Face;
|
||||
let rightEye = { openNum: 0, isOpen: false } as XFACE_TEST_EYE_TYPE;
|
||||
let leftEye = { openNum: 0, isOpen: false } as XFACE_TEST_EYE_TYPE;
|
||||
// 眼睛
|
||||
let rightEyeMark = face.getLandmark(FaceLandmark.RIGHT_EYE)
|
||||
let leftEyeMark = face.getLandmark(FaceLandmark.RIGHT_EYE)
|
||||
// 鼻子
|
||||
let noseMark = face.getLandmark(FaceLandmark.NOSE_BASE)
|
||||
// 耳朵
|
||||
let rightEarMark = face.getLandmark(FaceLandmark.RIGHT_EAR)
|
||||
let leftEarMark = face.getLandmark(FaceLandmark.LEFT_EAR)
|
||||
|
||||
|
||||
let rightEyeNum = face.getRightEyeOpenProbability()
|
||||
let leftEyeNum = face.getLeftEyeOpenProbability()
|
||||
let isSmile = face.getSmilingProbability()
|
||||
|
||||
let faceId = face.getTrackingId()
|
||||
|
||||
if (rightEyeNum != null) {
|
||||
rightEye.openNum = rightEyeNum + 0;
|
||||
rightEye.isOpen = rightEyeNum > 0.7
|
||||
}
|
||||
if (leftEyeNum != null) {
|
||||
leftEye.openNum = leftEyeNum + 0;
|
||||
leftEye.isOpen = leftEyeNum > 0.7
|
||||
}
|
||||
|
||||
// 检测当前左,右,下,上
|
||||
let faceRightLeft : XFACE_FACE_Direction = "center"
|
||||
let faceUpDown : XFACE_FACE_Direction = "center"
|
||||
|
||||
|
||||
let eulerX = face.getHeadEulerAngleX(); // 获取头部左右旋转角度
|
||||
let eulerY = face.getHeadEulerAngleY(); // 获取头部上下俯仰角度
|
||||
let eulerZ = face.getHeadEulerAngleZ(); // 获取头部上下俯仰角度
|
||||
|
||||
// 嘴巴
|
||||
let leftMouth = face.getLandmark(FaceLandmark.MOUTH_LEFT)
|
||||
let rightMouth = face.getLandmark(FaceLandmark.MOUTH_RIGHT)
|
||||
let bottomMouth = face.getLandmark(FaceLandmark.MOUTH_BOTTOM)
|
||||
|
||||
let isMouthOpened = false
|
||||
let ANGLE_THRESHOLD = 30; // 容差值
|
||||
let ANGLE_HEAD_THRESHOLD = 0; // 容差值
|
||||
let ANGLE_EYE_THRESHOLD = 6; // 眨眼的容差.
|
||||
|
||||
let allHeadBody = false;
|
||||
|
||||
if (Math.abs(eulerY) > ANGLE_THRESHOLD) { // 确保头部没有明显上下俯仰
|
||||
faceRightLeft = eulerY > 0 ? 'left' : 'right';
|
||||
}
|
||||
|
||||
if (Math.abs(eulerX) >= ANGLE_HEAD_THRESHOLD) { // 确保头部没有明显上下俯仰
|
||||
faceUpDown = eulerY > 0 ? 'down' : 'up';
|
||||
}
|
||||
|
||||
if (leftMouth != null && rightMouth != null && bottomMouth != null) {
|
||||
// @ts-ignore
|
||||
let mouthWidth = rightMouth.position.x - leftMouth.position.x
|
||||
// @ts-ignore
|
||||
let mouthHeight = bottomMouth.position.y - ((leftMouth.position.y + rightMouth.position.y) / 2)
|
||||
|
||||
if (mouthHeight / mouthWidth > 0.4 && faceRightLeft == 'center') {
|
||||
isMouthOpened = true;
|
||||
} else {
|
||||
isMouthOpened = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(
|
||||
leftMouth != null &&
|
||||
rightMouth != null &&
|
||||
bottomMouth != null &&
|
||||
noseMark !=null&&
|
||||
rightEarMark !=null&&
|
||||
leftEarMark !=null&&
|
||||
rightEyeMark !=null&&
|
||||
leftEyeMark !=null
|
||||
){
|
||||
allHeadBody = true;
|
||||
}
|
||||
|
||||
cfaces.push({
|
||||
imgWidth: image.getWidth(),
|
||||
imgHeight: image.getHeight(),
|
||||
isSmile: isSmile == null ? false : (isSmile >= 0.8),
|
||||
rightEye,
|
||||
leftEye,
|
||||
faceRightLeft,
|
||||
faceUpDown,
|
||||
isMouthOpened,
|
||||
allHeadBody,
|
||||
faceId:faceId!=null?(faceId+0):null
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
callBack(cfaces)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export function decodeImage(success : (evt : XFACE_EVENT_SUCCESS[]) => void, fail : () => void, image : InputImage) {
|
||||
// @ts-ignore
|
||||
const highAccuracyOpts = new FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_FAST)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
||||
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_NONE)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
|
||||
.enableTracking()
|
||||
.build()
|
||||
const detector = FaceDetection.getClient(highAccuracyOpts)
|
||||
|
||||
|
||||
detector.process(image)
|
||||
.addOnSuccessListener((faces : MutableList<Face>) => {
|
||||
|
||||
UTSAndroid.getDispatcher("main").async(function(_){
|
||||
checkFaceResult(image, faces, (result : XFACE_EVENT_SUCCESS[]) => {
|
||||
success(result)
|
||||
})
|
||||
},null)
|
||||
|
||||
})
|
||||
.addOnFailureListener(e => {
|
||||
console.error(e)
|
||||
fail()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过相册选择检测当前图片是否有人脸.
|
||||
*/
|
||||
export function checkFaceByImage(config : XFACE_CHECK_OPTS | null = null) {
|
||||
const cfg = getDefaultConfig(config)
|
||||
// @ts-ignore
|
||||
const highAccuracyOpts = new FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
||||
.setContourMode(FaceDetectorOptions.CONTOUR_MODE_ALL)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
|
||||
.build()
|
||||
|
||||
// @ts-ignore
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
// @ts-ignore
|
||||
success(evt : ChooseImageSuccess) {
|
||||
if (evt.tempFilePaths.length == 0) return;
|
||||
const imgs = evt.tempFilePaths[0] as string;
|
||||
const decodedPath = UTSAndroid.convert2AbsFullPath(imgs)
|
||||
const file = new File(decodedPath)
|
||||
const image = InputImage.fromFilePath(UTSAndroid.getAppContext() as Context, Uri.fromFile(file));
|
||||
// const image = InputImage.fromBitmap(BitmapFactory.decodeFile(decodedPath)!, 0)
|
||||
const detector = FaceDetection.getClient(highAccuracyOpts)
|
||||
detector.process(image)
|
||||
.addOnSuccessListener((faces : MutableList<Face>) => {
|
||||
if (faces.size == 0) {
|
||||
cfg.success({
|
||||
isPass: false,
|
||||
images: [decodedPath] as string[],
|
||||
videoPath: ""
|
||||
})
|
||||
return;
|
||||
}
|
||||
checkFaceResult(image, faces, (result : XFACE_EVENT_SUCCESS[]) => {
|
||||
|
||||
cfg.enter(result,JSON.stringify(result))
|
||||
cfg.success({
|
||||
isPass: true,
|
||||
images: [decodedPath] as string[],
|
||||
videoPath: ""
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
.addOnFailureListener(e => {
|
||||
console.error(e)
|
||||
cfg.fail("解析错误")
|
||||
})
|
||||
},
|
||||
fail() {
|
||||
console.error("未选择图片")
|
||||
cfg.fail("未选择图片")
|
||||
}
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 提供外部图片地址检测当前图片是否存在人脸
|
||||
*/
|
||||
export function checkFaceByImageFromFilePath(config : XFACE_CHECK_OPTS) {
|
||||
const cfg = getDefaultConfig(config)
|
||||
if (cfg.url == '') {
|
||||
cfg.fail("url图片地址没提供正确.")
|
||||
return;
|
||||
}
|
||||
const decodedPath = UTSAndroid.convert2AbsFullPath(cfg.url)
|
||||
const file = new File(decodedPath)
|
||||
const image = InputImage.fromFilePath(UTSAndroid.getAppContext() as Context, Uri.fromFile(file));
|
||||
// const image = InputImage.fromBitmap(BitmapFactory.decodeFile(decodedPath)!, 0)
|
||||
// @ts-ignore
|
||||
const highAccuracyOpts = new FaceDetectorOptions.Builder()
|
||||
.setPerformanceMode(FaceDetectorOptions.PERFORMANCE_MODE_ACCURATE)
|
||||
.setLandmarkMode(FaceDetectorOptions.LANDMARK_MODE_ALL)
|
||||
.setClassificationMode(FaceDetectorOptions.CLASSIFICATION_MODE_ALL)
|
||||
.build()
|
||||
const detector = FaceDetection.getClient(highAccuracyOpts)
|
||||
detector.process(image)
|
||||
.addOnSuccessListener((faces : MutableList<Face>) => {
|
||||
if (faces.size == 0) {
|
||||
cfg.enter([] as XFACE_EVENT_SUCCESS[],JSON.stringify([] as XFACE_EVENT_SUCCESS[] ))
|
||||
cfg.fail("未检测到人脸")
|
||||
return;
|
||||
}
|
||||
checkFaceResult(image, faces, (result : XFACE_EVENT_SUCCESS[]) => {
|
||||
|
||||
cfg.enter(result,JSON.stringify(result))
|
||||
cfg.success({
|
||||
isPass: true,
|
||||
images: [decodedPath] as string[],
|
||||
videoPath: ""
|
||||
})
|
||||
})
|
||||
})
|
||||
.addOnFailureListener(e => {
|
||||
console.error(e)
|
||||
cfg.fail("解析错误")
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查相机权限
|
||||
*/
|
||||
export function checkCamraPermissions(call : (istrue : boolean) => void) {
|
||||
let permissionCheck = ["android.permission.CAMERA"]
|
||||
|
||||
if (UTSAndroid.checkSystemPermissionGranted(UTSAndroid.getUniActivity()!, permissionCheck)) {
|
||||
call(true)
|
||||
} else {
|
||||
console.log("当前不具备指定权限")
|
||||
// 请求拍照权限
|
||||
UTSAndroid.requestSystemPermission(UTSAndroid.getUniActivity()!, permissionCheck, function (allRight : boolean, _ : string[]) {
|
||||
call(true)
|
||||
}, function (_ : boolean, _ : string[]) {
|
||||
//用户拒绝了部分权限
|
||||
call(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
let tid = 0
|
||||
//当前等待检测的指令
|
||||
let nowInsIndex = 0;
|
||||
//是否允许开始动作检测
|
||||
//allow,next,‘wait'
|
||||
let isCheckNext = 'wait'
|
||||
//指令执行中start,checking,dercoding,end
|
||||
let actioning = ''
|
||||
|
||||
/**
|
||||
* 打开视频进行人脸活体检测
|
||||
*/
|
||||
@UTSJS.keepAlive
|
||||
export function checkFaceByCamra(config : XFACE_CHECK_OPTS) {
|
||||
|
||||
if (camera != null) {
|
||||
camera!.closeCamera()
|
||||
clearTimeout(tid)
|
||||
}
|
||||
actioning = ''
|
||||
isCheckNext = 'wait'
|
||||
nowInsIndex = 0
|
||||
|
||||
const cfg = getDefaultConfig(config)
|
||||
if (cfg.viewId == '') {
|
||||
cfg.fail("没有提供正在的view的id绑定.")
|
||||
return;
|
||||
}
|
||||
if (cfg.instruction.length == 0) {
|
||||
console.warn("未提供指令,将仅进行人脸验证.")
|
||||
// cfg.fail("没有提供活体检测指令")
|
||||
// return;
|
||||
}
|
||||
// @ts-ignore
|
||||
let ele = uni.getElementById(cfg.viewId) as UniElement | null;
|
||||
if (ele == null) {
|
||||
cfg.fail("绑定的容器view找不到")
|
||||
return;
|
||||
}
|
||||
let parentView = ele.getAndroidView() as ViewGroup;
|
||||
let viewWidth = parentView.getWidth()
|
||||
let viewHeight = parentView.getHeight()
|
||||
let grop = new FrameLayout(UTSAndroid!.getAppContext()!)
|
||||
let layaout = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
grop.setLayoutParams(layaout)
|
||||
parentView.addView(grop)
|
||||
|
||||
let isPassCheck = false
|
||||
let checkImgs = [] as string[]
|
||||
let lastFaceAllBody = ""
|
||||
let faceId = null as null|number;
|
||||
if (viewWidth == 0 || viewHeight == 0) {
|
||||
cfg.fail("绑定的容器view宽高不能为0")
|
||||
return;
|
||||
}
|
||||
|
||||
camera = new xCamera(grop)
|
||||
camera?.setCameraDir('front')
|
||||
camera?.setFlash(false)
|
||||
|
||||
camera?.startRecoderVideo((videoPath : string) => {
|
||||
console.log(videoPath)
|
||||
UTSAndroid.getDispatcher("main").async(function (_) {
|
||||
if(lastFaceAllBody!=''){
|
||||
checkImgs.push(lastFaceAllBody)
|
||||
}
|
||||
cfg.success({
|
||||
videoPath,
|
||||
images:checkImgs,
|
||||
isPass:isPassCheck
|
||||
} as XFACE_EVENT_CHECK_SUCCESS)
|
||||
})
|
||||
})
|
||||
|
||||
function closeCamera() {
|
||||
camera?.stopRecoderVideo()
|
||||
camera?.closeCamera()
|
||||
parentView.removeAllViews()
|
||||
}
|
||||
|
||||
tid = setTimeout(() => {
|
||||
cfg.insTipsEvent("start")
|
||||
actioning = 'start'
|
||||
isCheckNext = 'allow'
|
||||
}, 2000)
|
||||
|
||||
let headDonwUp = 0
|
||||
UTSAndroid.getDispatcher("main").async(function (_) {
|
||||
camera?.setCheckFaceEnter((result:XFACE_EVENT_SUCCESS[],imgBit:any|null) => {
|
||||
|
||||
// 无指令时的正脸检测
|
||||
if(cfg.instruction.length==0){
|
||||
if(result.length>0){
|
||||
let item = result[0]
|
||||
if(item.allHeadBody){
|
||||
nowInsIndex = -1;
|
||||
if(imgBit!=null&&camera!=null&&imgBit instanceof Bitmap){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache((imgBit! as Bitmap)))
|
||||
}
|
||||
isPassCheck = true;
|
||||
closeCamera()
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (nowInsIndex == -1 || actioning == '') {
|
||||
return;
|
||||
}
|
||||
if (nowInsIndex > cfg.instruction.length - 1) {
|
||||
nowInsIndex = -1;
|
||||
cfg.insTipsEvent("end")
|
||||
isPassCheck = true;
|
||||
closeCamera()
|
||||
return;
|
||||
}
|
||||
let item = null as null|XFACE_EVENT_SUCCESS
|
||||
if(result.length>0){
|
||||
item = result[0]
|
||||
}
|
||||
let dir = cfg.instruction[nowInsIndex]
|
||||
if (actioning == 'start') {
|
||||
actioning = ''
|
||||
audio.play(dir)
|
||||
setTimeout(function () {
|
||||
cfg.insTipsEvent("ins_start_" + dir)
|
||||
isCheckNext = 'allow'
|
||||
actioning = 'checking'
|
||||
}, 1500);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 保存一次正脸
|
||||
if(lastFaceAllBody==""){
|
||||
if(result.length>0){
|
||||
let item = result[0]
|
||||
if(item.allHeadBody){
|
||||
lastFaceAllBody = camera!.savePhotoBitmapTocache(imgBit! as Bitmap)
|
||||
faceId = item.faceId
|
||||
console.log(faceId,'+++')
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 进行人脸检测
|
||||
if(item!=null&&actioning == 'checking'&&isCheckNext == 'allow'){
|
||||
let rts = result!
|
||||
if(faceId!=item.faceId||item.faceId==null||faceId==null){
|
||||
console.log(item.faceId,'---')
|
||||
isPassCheck = false;
|
||||
console.log("检脸追踪id变化,检测失败")
|
||||
nowInsIndex = -1;
|
||||
cfg.insTipsEvent("end")
|
||||
closeCamera()
|
||||
return;
|
||||
}
|
||||
// 向左转
|
||||
if (dir == 'left' && item.faceRightLeft == 'left') {
|
||||
// 立即更改状态,防止重复处理
|
||||
actioning = 'dercoding'
|
||||
cfg.insTipsEvent("ins_end_" + dir)
|
||||
cfg.enter(result,JSON.stringify(rts))
|
||||
isCheckNext = 'wait';
|
||||
audio.play('goold')
|
||||
if(imgBit!=null&&camera!=null){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache(imgBit! as Bitmap))
|
||||
}
|
||||
tid = setTimeout(function () {
|
||||
isCheckNext = 'next';
|
||||
}, 1000);
|
||||
} else if (dir == 'right' && item.faceRightLeft == 'right') {
|
||||
// 立即更改状态,防止重复处理
|
||||
actioning = 'dercoding'
|
||||
cfg.insTipsEvent("ins_end_" + dir)
|
||||
cfg.enter(result,JSON.stringify(rts))
|
||||
isCheckNext = 'wait';
|
||||
audio.play('goold')
|
||||
if(imgBit!=null&&camera!=null){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache(imgBit! as Bitmap))
|
||||
}
|
||||
tid = setTimeout(function () {
|
||||
isCheckNext = 'next';
|
||||
}, 1000);
|
||||
|
||||
} else if(dir == 'downUp'&&(item.faceUpDown=='up'||item.faceUpDown=='down')){
|
||||
if(item.faceUpDown=='up'&&headDonwUp==0){
|
||||
headDonwUp = 1;
|
||||
|
||||
}else if(item.faceUpDown=='down'&&headDonwUp==1){
|
||||
headDonwUp = 2;
|
||||
|
||||
// 立即更改状态,防止重复处理
|
||||
actioning = 'dercoding'
|
||||
cfg.insTipsEvent("ins_end_" + dir)
|
||||
cfg.enter(result,JSON.stringify(rts))
|
||||
audio.play('goold')
|
||||
isCheckNext = 'wait';
|
||||
if(imgBit!=null&&camera!=null){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache(imgBit! as Bitmap))
|
||||
}
|
||||
tid = setTimeout(function () {
|
||||
isCheckNext = 'next';
|
||||
headDonwUp = 0
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}else if(dir == 'monthOpenClose'){
|
||||
if(item.isMouthOpened==true&&headDonwUp==0){
|
||||
headDonwUp = 1;
|
||||
|
||||
}else if(item.isMouthOpened == false&&headDonwUp==1){
|
||||
headDonwUp = 2;
|
||||
// 立即更改状态,防止重复处理
|
||||
actioning = 'dercoding'
|
||||
cfg.insTipsEvent("ins_end_" + dir)
|
||||
cfg.enter(result,JSON.stringify(rts))
|
||||
audio.play('goold')
|
||||
isCheckNext = 'wait';
|
||||
if(imgBit!=null&&camera!=null){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache(imgBit! as Bitmap))
|
||||
}
|
||||
tid = setTimeout(function () {
|
||||
isCheckNext = 'next';
|
||||
headDonwUp = 0
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}else if(dir == 'eyeOplenClose'){
|
||||
if((item.leftEye.isOpen&&item.rightEye.isOpen)&&headDonwUp==0){
|
||||
headDonwUp = 1;
|
||||
}else if((!item.leftEye.isOpen&&!item.rightEye.isOpen)&&headDonwUp==1){
|
||||
headDonwUp = 2;
|
||||
}else if((item.leftEye.isOpen&&item.rightEye.isOpen)&&headDonwUp==2){
|
||||
headDonwUp = 3;
|
||||
// 立即更改状态,防止重复处理
|
||||
actioning = 'dercoding'
|
||||
cfg.insTipsEvent("ins_end_" + dir)
|
||||
cfg.enter(result,JSON.stringify(rts))
|
||||
audio.play('goold')
|
||||
isCheckNext = 'wait';
|
||||
if(imgBit!=null&&camera!=null){
|
||||
checkImgs.push(camera!.savePhotoBitmapTocache(imgBit! as Bitmap))
|
||||
}
|
||||
tid = setTimeout(function () {
|
||||
isCheckNext = 'next';
|
||||
headDonwUp = 0
|
||||
}, 1000);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (isCheckNext == 'next'){
|
||||
isCheckNext = 'allow';
|
||||
actioning = 'start'
|
||||
nowInsIndex += 1;
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user